lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 25 Feb 2020 21:36:13 +0100
From:   Andreas Gerstmayr <agerstmayr@...hat.com>
To:     Jiri Olsa <jolsa@...hat.com>
Cc:     linux-kernel@...r.kernel.org, kabbott@...hat.com,
        skozina@...hat.com, mpetlan@...hat.com, nathans@...hat.com,
        mgoodwin@...hat.com, linux-perf-users@...r.kernel.org,
        bgregg@...flix.com, mspier@...flix.com,
        Peter Zijlstra <peterz@...radead.org>,
        Ingo Molnar <mingo@...hat.com>,
        Arnaldo Carvalho de Melo <acme@...nel.org>,
        Mark Rutland <mark.rutland@....com>,
        Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
        Namhyung Kim <namhyung@...nel.org>
Subject: Re: [RFC] perf script: add flamegraph.py script



On 25.02.20 21:20, Jiri Olsa wrote:
> On Tue, Feb 25, 2020 at 09:03:19PM +0100, Andreas Gerstmayr wrote:
>> On 25.02.20 20:54, Jiri Olsa wrote:
>>> On Fri, Feb 21, 2020 at 06:55:01PM +0100, Andreas Gerstmayr wrote:
>>>> This script works in tandem with d3-flame-graph to generate flame graphs
>>>> from perf. It supports two output formats: JSON and HTML (the default).
>>>> The HTML format will look for a standalone d3-flame-graph template file in
>>>> /usr/share/d3-flame-graph/template.html and fill in the collected stacks.
>>>>
>>>> Usage:
>>>>
>>>>       perf script flamegraph -a -F 99 sleep 60
>>>>
>>>> Alternative usage:
>>>>
>>>>       perf record -a -g -F 99 sleep 60
>>>>       perf script report flamegraph
>>>
>>> nice, could this output the output file, like:
>>>
>>>        # perf script report flamegraph --output krava.html
>>>        dumping data to krava.html
> 
> I meant the actual line ^^^^, saying that it's writing to the file

Ah! Sorry, I misunderstood.
Yep, sure, I can add that.

I also have one other change lined up to reduce the JSON output, and I'm 
testing it with huge flamegraphs right now. Will send an update this week.


Cheers,
Andreas


> 
> thanks,
> jirka
> 
>>>
>>> or something in that sense
>>>
>>> other than that it looks good to me
>>
>> Yes, it's already implemented.
>>
>> $ perf script report flamegraph --output krava.html
>>
>> writes the output to krava.html
>>
>> $ perf script report flamegraph --help
>>
>> shows the supported arguments.
>>
>> The only gotcha is that you need to have a perf.data in the same directory
>> when calling this command, otherwise perf complains about a missing
>> perf.data and doesn't call the flamegraph.py script.
>>
>>
>> Cheers,
>> Andreas
>>
>>
>>>
>>> thanks,
>>> jirka
>>>
>>>
>>>>
>>>> Signed-off-by: Andreas Gerstmayr <agerstmayr@...hat.com>
>>>> Cc: Peter Zijlstra <peterz@...radead.org>
>>>> Cc: Ingo Molnar <mingo@...hat.com>
>>>> Cc: Arnaldo Carvalho de Melo <acme@...nel.org>
>>>> Cc: Mark Rutland <mark.rutland@....com>
>>>> Cc: Alexander Shishkin <alexander.shishkin@...ux.intel.com>
>>>> Cc: Jiri Olsa <jolsa@...hat.com>
>>>> Cc: Namhyung Kim <namhyung@...nel.org>
>>>> ---
>>>>
>>>> I'm currently preparing packages for d3-flame-graph. For Fedora, the copr
>>>> at
>>>> https://copr.fedorainfracloud.org/coprs/agerstmayr/reviews/package/js-d3-flame-graph/
>>>> can be installed, or alternatively the prebuilt standalone d3-flame-graph
>>>> template can be downloaded from
>>>> https://raw.githubusercontent.com/andreasgerstmayr/specs/master/reviews/js-d3-flame-graph/template.html
>>>> and moved into /usr/share/d3-flame-graph/template.html
>>>>
>>>>    .../perf/scripts/python/bin/flamegraph-record |   2 +
>>>>    .../perf/scripts/python/bin/flamegraph-report |   3 +
>>>>    tools/perf/scripts/python/flamegraph.py       | 117 ++++++++++++++++++
>>>>    3 files changed, 122 insertions(+)
>>>>    create mode 100755 tools/perf/scripts/python/bin/flamegraph-record
>>>>    create mode 100755 tools/perf/scripts/python/bin/flamegraph-report
>>>>    create mode 100755 tools/perf/scripts/python/flamegraph.py
>>>>
>>>> diff --git a/tools/perf/scripts/python/bin/flamegraph-record b/tools/perf/scripts/python/bin/flamegraph-record
>>>> new file mode 100755
>>>> index 000000000000..725d66e71570
>>>> --- /dev/null
>>>> +++ b/tools/perf/scripts/python/bin/flamegraph-record
>>>> @@ -0,0 +1,2 @@
>>>> +#!/usr/bin/sh
>>>> +perf record -g "$@"
>>>> diff --git a/tools/perf/scripts/python/bin/flamegraph-report b/tools/perf/scripts/python/bin/flamegraph-report
>>>> new file mode 100755
>>>> index 000000000000..b1a79afd903b
>>>> --- /dev/null
>>>> +++ b/tools/perf/scripts/python/bin/flamegraph-report
>>>> @@ -0,0 +1,3 @@
>>>> +#!/usr/bin/sh
>>>> +# description: create flame graphs
>>>> +perf script -s "$PERF_EXEC_PATH"/scripts/python/flamegraph.py -- "$@"
>>>> diff --git a/tools/perf/scripts/python/flamegraph.py b/tools/perf/scripts/python/flamegraph.py
>>>> new file mode 100755
>>>> index 000000000000..2e9139ef2c4a
>>>> --- /dev/null
>>>> +++ b/tools/perf/scripts/python/flamegraph.py
>>>> @@ -0,0 +1,117 @@
>>>> +# flamegraph.py - create flame graphs from perf samples
>>>> +# SPDX-License-Identifier: GPL-2.0
>>>> +#
>>>> +# Usage:
>>>> +#
>>>> +#  perf record -a -g -F 99 sleep 60
>>>> +#  perf script report flamegraph
>>>> +#
>>>> +# Combined data collection and flamegraph generation:
>>>> +#
>>>> +#  perf script flamegraph -a -F 99 sleep 60
>>>> +#
>>>> +# Written by Andreas Gerstmayr <agerstmayr@...hat.com>
>>>> +# Flame Graphs invented by Brendan Gregg <bgregg@...flix.com>
>>>> +# Works in tandem with d3-flame-graph by Martin Spier <mspier@...flix.com>
>>>> +
>>>> +import sys
>>>> +import os
>>>> +import argparse
>>>> +import json
>>>> +
>>>> +
>>>> +class Node:
>>>> +    def __init__(self, name, libtype=""):
>>>> +        self.name = name
>>>> +        self.libtype = libtype
>>>> +        self.value = 0
>>>> +        self.children = []
>>>> +
>>>> +
>>>> +class FlameGraphCLI:
>>>> +    def __init__(self, args):
>>>> +        self.args = args
>>>> +        self.stack = Node("root")
>>>> +
>>>> +        if self.args.format == "html" and \
>>>> +                not os.path.isfile(self.args.template):
>>>> +            print(f"Flame Graph template '{self.args.template}' does not " +
>>>> +                  f"exist. Please install the d3-flame-graph package, " +
>>>> +                  f"specify an existing flame graph template " +
>>>> +                  f"(--template PATH) or another output format " +
>>>> +                  f"(--format FORMAT).", file=sys.stderr)
>>>> +            sys.exit(1)
>>>> +
>>>> +    def find_or_create_node(self, node, name, dso):
>>>> +        libtype = "kernel" if dso == "[kernel.kallsyms]" else ""
>>>> +        if name is None:
>>>> +            name = "[unknown]"
>>>> +
>>>> +        for child in node.children:
>>>> +            if child.name == name and child.libtype == libtype:
>>>> +                return child
>>>> +
>>>> +        child = Node(name, libtype)
>>>> +        node.children.append(child)
>>>> +        return child
>>>> +
>>>> +    def process_event(self, event):
>>>> +        node = self.find_or_create_node(self.stack, event["comm"], None)
>>>> +        if "callchain" in event:
>>>> +            for entry in reversed(event['callchain']):
>>>> +                node = self.find_or_create_node(
>>>> +                    node, entry.get("sym", {}).get("name"), event.get("dso"))
>>>> +        else:
>>>> +            node = self.find_or_create_node(
>>>> +                node, entry.get("symbol"), event.get("dso"))
>>>> +        node.value += 1
>>>> +
>>>> +    def trace_end(self):
>>>> +        def encoder(x): return x.__dict__
>>>> +        json_str = json.dumps(self.stack, default=encoder,
>>>> +                              indent=self.args.indent)
>>>> +
>>>> +        if self.args.format == "html":
>>>> +            try:
>>>> +                with open(self.args.template) as f:
>>>> +                    output_str = f.read().replace("/** @flamegraph_params **/",
>>>> +                                                  json_str)
>>>> +            except IOError as e:
>>>> +                print(f"Error reading template file: {e}", file=sys.stderr)
>>>> +                sys.exit(1)
>>>> +            output_fn = self.args.output or "flamegraph.html"
>>>> +        else:
>>>> +            output_str = json_str
>>>> +            output_fn = self.args.output or "stacks.json"
>>>> +
>>>> +        if output_fn == "-":
>>>> +            sys.stdout.write(output_str)
>>>> +        else:
>>>> +            try:
>>>> +                with open(output_fn, "w") as out:
>>>> +                    out.write(output_str)
>>>> +            except IOError as e:
>>>> +                print(f"Error writing output file: {e}", file=sys.stderr)
>>>> +                sys.exit(1)
>>>> +
>>>> +
>>>> +if __name__ == "__main__":
>>>> +    parser = argparse.ArgumentParser(description="Create flame graphs.")
>>>> +    parser.add_argument("-F", "--format",
>>>> +                        default="html", choices=["json", "html"],
>>>> +                        help="output file format")
>>>> +    parser.add_argument("-o", "--output",
>>>> +                        help="output file name")
>>>> +    parser.add_argument("--indent",
>>>> +                        type=int, help="JSON indentation")
>>>> +    parser.add_argument("--template",
>>>> +                        default="/usr/share/d3-flame-graph/template.html",
>>>> +                        help="path to flamegraph HTML template")
>>>> +    parser.add_argument("-i", "--input",
>>>> +                        help=argparse.SUPPRESS)
>>>> +
>>>> +    args = parser.parse_args()
>>>> +    cli = FlameGraphCLI(args)
>>>> +
>>>> +    process_event = cli.process_event
>>>> +    trace_end = cli.trace_end
>>>> -- 
>>>> 2.24.1
>>>>
>>>
>>
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ