[libcamera-devel] [PATCH v2 5/6] utils: tracepoints: Add simple statistics script

Laurent Pinchart laurent.pinchart at ideasonboard.com
Thu Oct 29 02:03:08 CET 2020


Hi Paul,

Thank you for the patch.

On Wed, Oct 28, 2020 at 07:31:50PM +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 at ideasonboard.com>
> 
> ---
> New in v2
> ---
>  utils/tracepoints/analyze.py | 64 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
>  create mode 100755 utils/tracepoints/analyze.py
> 
> diff --git a/utils/tracepoints/analyze.py b/utils/tracepoints/analyze.py
> new file mode 100755
> index 00000000..be56ca28
> --- /dev/null
> +++ b/utils/tracepoints/analyze.py
> @@ -0,0 +1,64 @@
> +#!/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.py - Analysis tool for libcamera lttng output

Maybe mention this is meant as a simple example to show how information
can be extracted from 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()
> +    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')

Good you expand this with documentation to allow someone who runs the
script with --help to understand what it can be used for, and how ?

> +    args = parser.parse_args(argv[1:])
> +
> +    traces = bt2.TraceCollectionMessageIterator(args.trace_path)
> +    for msg in traces:
> +        if type(msg) is not bt2._EventMessageConst 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"]

s/"/'/g

> +        timestamp_ns = msg.default_clock_snapshot.ns_from_origin
> +
> +        if event == 'libcamera:ipa_call_start':
> +            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_finish':
> +            ts = timestamps[pipeline][func].pop()
> +            key = f'{pipeline}:{func}'
> +            if key not in samples:
> +                samples[key] = []
> +            samples[key].append(timestamp_ns - ts)
> +
> +    print('pipeline:function\t:\tmin\tmax\tmean\tstddev')
> +    for k, v in samples.items():
> +        mean = int(stats.mean(v))
> +        stddev = int(stats.stdev(v))
> +        minv = min(v)
> +        maxv = max(v)
> +        print(f'{k}\t:\t{minv}\t{maxv}\t{mean}\t{stddev}')

A small enhancement, if you have time, to make it easier to read, would
be to align fields in different lines. That would require storing the
fields in text form for all lines first, then computing the max string
length for each field, and then print them accordingly.

> +
> +
> +if __name__ == '__main__':
> +    sys.exit(main(sys.argv))

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list