1 # flamegraph.py - create flame graphs from perf samples
2 # SPDX-License-Identifier: GPL-2.0
6 # perf record -a -g -F 99 sleep 60
7 # perf script report flamegraph
11 # perf script flamegraph -a -F 99 sleep 60
13 # Written by Andreas Gerstmayr <agerstmayr@redhat.com>
14 # Flame Graphs invented by Brendan Gregg <bgregg@netflix.com>
15 # Works in tandem with d3-flame-graph by Martin Spier <mspier@netflix.com>
17 from __future__
import print_function
26 def __init__(self
, name
, libtype
=""):
28 self
.libtype
= libtype
42 def __init__(self
, args
):
44 self
.stack
= Node("root")
46 if self
.args
.format
== "html" and \
47 not os
.path
.isfile(self
.args
.template
):
48 print("Flame Graph template {} does not exist. Please install "
49 "the js-d3-flame-graph (RPM) or libjs-d3-flame-graph (deb) "
50 "package, specify an existing flame graph template "
51 "(--template PATH) or another output format "
52 "(--format FORMAT).".format(self
.args
.template
),
56 def find_or_create_node(self
, node
, name
, dso
):
57 libtype
= "kernel" if dso
== "[kernel.kallsyms]" else ""
61 for child
in node
.children
:
62 if child
.name
== name
and child
.libtype
== libtype
:
65 child
= Node(name
, libtype
)
66 node
.children
.append(child
)
69 def process_event(self
, event
):
70 node
= self
.find_or_create_node(self
.stack
, event
["comm"], None)
71 if "callchain" in event
:
72 for entry
in reversed(event
['callchain']):
73 node
= self
.find_or_create_node(
74 node
, entry
.get("sym", {}).get("name"), event
.get("dso"))
76 node
= self
.find_or_create_node(
77 node
, entry
.get("symbol"), event
.get("dso"))
81 json_str
= json
.dumps(self
.stack
, default
=lambda x
: x
.toJSON())
83 if self
.args
.format
== "html":
85 with io
.open(self
.args
.template
, encoding
="utf-8") as f
:
86 output_str
= f
.read().replace("/** @flamegraph_json **/",
89 print("Error reading template file: {}".format(e
), file=sys
.stderr
)
91 output_fn
= self
.args
.output
or "flamegraph.html"
94 output_fn
= self
.args
.output
or "stacks.json"
97 with io
.open(sys
.stdout
.fileno(), "w", encoding
="utf-8", closefd
=False) as out
:
100 print("dumping data to {}".format(output_fn
))
102 with io
.open(output_fn
, "w", encoding
="utf-8") as out
:
103 out
.write(output_str
)
105 print("Error writing output file: {}".format(e
), file=sys
.stderr
)
109 if __name__
== "__main__":
110 parser
= argparse
.ArgumentParser(description
="Create flame graphs.")
111 parser
.add_argument("-f", "--format",
112 default
="html", choices
=["json", "html"],
113 help="output file format")
114 parser
.add_argument("-o", "--output",
115 help="output file name")
116 parser
.add_argument("--template",
117 default
="/usr/share/d3-flame-graph/d3-flamegraph-base.html",
118 help="path to flamegraph HTML template")
119 parser
.add_argument("-i", "--input",
120 help=argparse
.SUPPRESS
)
122 args
= parser
.parse_args()
123 cli
= FlameGraphCLI(args
)
125 process_event
= cli
.process_event
126 trace_end
= cli
.trace_end