summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorPaul Elder <paul.elder@ideasonboard.com>2020-10-28 19:06:00 +0900
committerPaul Elder <paul.elder@ideasonboard.com>2020-11-03 11:33:41 +0900
commit6e77b59055a79a0d32ac96bdef73357c9c084c30 (patch)
treec00523ad7a5c93f2025db49b8d77db4f9f01fb95 /utils
parent27c9d6eceb15b8a4e400fd2b053fb84d0db10da4 (diff)
utils: tracepoints: Add simple statistics script
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@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'utils')
-rwxr-xr-xutils/tracepoints/analyze-ipa-trace.py77
1 files changed, 77 insertions, 0 deletions
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@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))