Message ID | 20201030085756.79329-5-paul.elder@ideasonboard.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Paul, Thank you for the patch. On Fri, Oct 30, 2020 at 05:57:55PM +0900, Paul Elder wrote: > 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> > > --- > 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@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])) You can write this widths.append(max(len(row[i]) for row in rows)) and python will create a generator for the expression passed to max(), instead of creating an actual list. And I've now tried to measure the efficiency, and the generator is slower -_-'. Let's ignore this. > + > + # 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)) You've made all the code here independent of the number of columns, except for the format string :-) No big deal though. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > + > +if __name__ == '__main__': > + sys.exit(main(sys.argv))
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))
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> --- 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