[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v3 12/14] simpletrace: added simplified Analyzer2 class
From: |
Mads Ynddal |
Subject: |
[PATCH v3 12/14] simpletrace: added simplified Analyzer2 class |
Date: |
Thu, 8 Jun 2023 14:41:45 +0200 |
From: Mads Ynddal <m.ynddal@samsung.com>
By moving the dynamic argument construction to keyword-arguments,
we can remove all of the specialized handling, and streamline it.
If a tracing method wants to access these, they can define the
kwargs, or ignore it be placing `**kwargs` at the end of the
function's arguments list.
Added deprecation warning to Analyzer class to make users aware
of the Analyzer2 class. No removal date is planned.
Signed-off-by: Mads Ynddal <m.ynddal@samsung.com>
---
scripts/simpletrace.py | 72 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index 4136d00600..ca982c9b54 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -12,6 +12,7 @@
import sys
import struct
import inspect
+import warnings
from tracetool import read_events, Event
from tracetool.backend.simple import is_string
@@ -188,6 +189,11 @@ def _build_fn(self, event):
return lambda _, rec: fn(*rec[3:3 + event_argcount])
def _process_event(self, rec_args, *, event, event_id, timestamp_ns, pid,
**kwargs):
+ warnings.warn(
+ "Use of deprecated Analyzer class. Refer to Analyzer2 instead.",
+ DeprecationWarning,
+ )
+
if not hasattr(self, '_fn_cache'):
# NOTE: Cannot depend on downstream subclasses to have
# super().__init__() because of legacy.
@@ -211,6 +217,56 @@ def __exit__(self, exc_type, exc_val, exc_tb):
self.end()
return False
+class Analyzer2(Analyzer):
+ """A trace file analyzer which processes trace records.
+
+ An analyzer can be passed to run() or process(). The begin() method is
+ invoked, then each trace record is processed, and finally the end() method
+ is invoked. When Analyzer is used as a context-manager (using the `with`
+ statement), begin() and end() are called automatically.
+
+ If a method matching a trace event name exists, it is invoked to process
+ that trace record. Otherwise the catchall() method is invoked.
+
+ The methods are called with a set of keyword-arguments. These can be
ignored
+ using `**kwargs` or defined like any keyword-argument.
+
+ The following keyword-arguments are available, but make sure to have an
+ **kwargs to allow for unmatched arguments in the future:
+ event: Event object of current trace
+ event_id: The id of the event in the current trace file
+ timestamp_ns: The timestamp in nanoseconds of the trace
+ pid: The process id recorded for the given trace
+
+ Example:
+ The following method handles the runstate_set(int new_state) trace event::
+
+ def runstate_set(self, new_state, **kwargs):
+ ...
+
+ The method can also explicitly take a timestamp keyword-argument with the
+ trace event arguments::
+
+ def runstate_set(self, new_state, *, timestamp_ns, **kwargs):
+ ...
+
+ Timestamps have the uint64_t type and are in nanoseconds.
+
+ The pid can be included in addition to the timestamp and is useful when
+ dealing with traces from multiple processes:
+
+ def runstate_set(self, new_state, *, timestamp_ns, pid, **kwargs):
+ ...
+ """
+
+ def catchall(self, *rec_args, event, timestamp_ns, pid, event_id,
**kwargs):
+ """Called if no specific method for processing a trace event has been
found."""
+ pass
+
+ def _process_event(self, rec_args, *, event, **kwargs):
+ fn = getattr(self, event.name, self.catchall)
+ fn(*rec_args, event=event, **kwargs)
+
def process(events, log, analyzer, read_header=True):
"""Invoke an analyzer on each event in a log.
Args:
@@ -300,6 +356,22 @@ def catchall(self, event, rec):
i += 1
print(' '.join(fields))
+ class Formatter2(Analyzer2):
+ def __init__(self):
+ self.last_timestamp_ns = None
+
+ def catchall(self, *rec_args, event, timestamp_ns, pid, event_id):
+ if self.last_timestamp_ns is None:
+ self.last_timestamp_ns = timestamp_ns
+ delta_ns = timestamp_ns - self.last_timestamp_ns
+ self.last_timestamp_ns = timestamp_ns
+
+ fields = [
+ f'{name}={r}' if is_string(type) else f'{name}=0x{r:x}'
+ for r, (type, name) in zip(rec_args, event.args)
+ ]
+ print(f'{event.name} {delta_ns / 1000:0.3f} {pid=} ' + '
'.join(fields))
+
try:
run(Formatter())
except SimpleException as e:
--
2.38.1
- [PATCH v3 02/14] simpletrace: annotate magic constants from QEMU code, (continued)
- [PATCH v3 02/14] simpletrace: annotate magic constants from QEMU code, Mads Ynddal, 2023/06/08
- [PATCH v3 03/14] simpletrace: improve parsing of sys.argv; fix files never closed., Mads Ynddal, 2023/06/08
- [PATCH v3 04/14] simpletrace: changed naming of edict and idtoname to improve readability, Mads Ynddal, 2023/06/08
- [PATCH v3 05/14] simpletrace: update code for Python 3.11, Mads Ynddal, 2023/06/08
- [PATCH v3 06/14] simpletrace: improved error handling on struct unpack, Mads Ynddal, 2023/06/08
- [PATCH v3 07/14] simpletrace: define exception and add handling, Mads Ynddal, 2023/06/08
- [PATCH v3 08/14] simpletrace: made Analyzer into context-manager, Mads Ynddal, 2023/06/08
- [PATCH v3 09/14] simpletrace: refactor to separate responsibilities, Mads Ynddal, 2023/06/08
- [PATCH v3 10/14] simpletrace: move logic of process into internal function, Mads Ynddal, 2023/06/08
- [PATCH v3 11/14] simpletrace: move event processing to Analyzer class, Mads Ynddal, 2023/06/08
- [PATCH v3 12/14] simpletrace: added simplified Analyzer2 class,
Mads Ynddal <=
- [PATCH v3 13/14] MAINTAINERS: add maintainer of simpletrace.py, Mads Ynddal, 2023/06/08
- [PATCH v3 14/14] scripts/analyse-locks-simpletrace.py: changed iteritems() to items(), Mads Ynddal, 2023/06/08