[libcamera-devel] [PATCH v4 4/5] utils: tracepoints: Add simple statistics script

Paul Elder paul.elder at ideasonboard.com
Fri Oct 30 09:57:55 CET 2020


Add a script that scans a trace for IPA call tracepoints, and returns
statistics on the time taken for IPA calls.

Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>

---
Changes in v4:
- rename script to analyze-ipa-trace.py
- align output stats table

Changes in v3:
- check for the new tracepoint names, ipa_call_begin and ipa_call_end
- fix babeltrace2 parsing in the case that the event doesn't have a
  pipeline_name field
- change script description
- add argparse description
- add example for trace_path argument
- change double quotes to single quotes

New in v2
---
 utils/tracepoints/analyze-ipa-trace.py | 77 ++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100755 utils/tracepoints/analyze-ipa-trace.py

diff --git a/utils/tracepoints/analyze-ipa-trace.py b/utils/tracepoints/analyze-ipa-trace.py
new file mode 100755
index 00000000..50fbbf42
--- /dev/null
+++ b/utils/tracepoints/analyze-ipa-trace.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2020, Google Inc.
+#
+# Author: Paul Elder <paul.elder at ideasonboard.com>
+#
+# analyze-ipa-trace.py - Example of how to extract information from libcamera lttng traces
+
+import argparse
+import bt2
+import statistics as stats
+import sys
+
+# pipeline -> {function -> stack(timestamps)}
+timestamps = {}
+
+# pipeline:function -> samples[]
+samples = {}
+
+def main(argv):
+    parser = argparse.ArgumentParser(
+            description='A simple analysis script to get statistics on time taken for IPA calls')
+    parser.add_argument('-p', '--pipeline', type=str,
+                        help='Name of pipeline to filter for')
+    parser.add_argument('trace_path', type=str,
+                        help='Path to lttng trace (eg. ~/lttng-traces/demo-20201029-184003)')
+    args = parser.parse_args(argv[1:])
+
+    traces = bt2.TraceCollectionMessageIterator(args.trace_path)
+    for msg in traces:
+        if type(msg) is not bt2._EventMessageConst or \
+           'pipeline_name' not in msg.event.payload_field or \
+           (args.pipeline is not None and \
+            msg.event.payload_field['pipeline_name'] != args.pipeline):
+            continue
+
+        pipeline = msg.event.payload_field['pipeline_name']
+        event = msg.event.name
+        func = msg.event.payload_field['function_name']
+        timestamp_ns = msg.default_clock_snapshot.ns_from_origin
+
+        if event == 'libcamera:ipa_call_begin':
+            if pipeline not in timestamps:
+                timestamps[pipeline] = {}
+            if func not in timestamps[pipeline]:
+                timestamps[pipeline][func] = []
+            timestamps[pipeline][func].append(timestamp_ns)
+
+        if event == 'libcamera:ipa_call_end':
+            ts = timestamps[pipeline][func].pop()
+            key = f'{pipeline}:{func}'
+            if key not in samples:
+                samples[key] = []
+            samples[key].append(timestamp_ns - ts)
+
+    # Compute stats
+    rows = []
+    rows.append(['pipeline:function', 'min', 'max', 'mean', 'stddev'])
+    for k, v in samples.items():
+        mean = int(stats.mean(v))
+        stddev = int(stats.stdev(v))
+        minv = min(v)
+        maxv = max(v)
+        rows.append([k, str(minv), str(maxv), str(mean), str(stddev)])
+
+    # Get maximum string width for every column
+    widths = []
+    for i in range(len(rows[0])):
+        widths.append(max([len(row[i]) for row in rows]))
+
+    # Print stats table
+    for row in rows:
+        fmt = [row[i].rjust(widths[i]) for i in range(1, 5)]
+        print('{} {} {} {} {}'.format(row[0].ljust(widths[0]), *fmt))
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
-- 
2.27.0



More information about the libcamera-devel mailing list