mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-28 05:24:47 +08:00
c42ad5d435
On some platforms the default encoding is not utf-8, which causes an UnicodeDecodeError when reading the flamegraph template and writing the flamegraph Signed-off-by: Andreas Gerstmayr <agerstmayr@redhat.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Michael Petlan <mpetlan@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lore.kernel.org/lkml/20200619153232.203537-1-agerstmayr@redhat.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
127 lines
4.2 KiB
Python
Executable File
127 lines
4.2 KiB
Python
Executable File
# 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:
|
|
#
|
|
# perf script flamegraph -a -F 99 sleep 60
|
|
#
|
|
# Written by Andreas Gerstmayr <agerstmayr@redhat.com>
|
|
# Flame Graphs invented by Brendan Gregg <bgregg@netflix.com>
|
|
# Works in tandem with d3-flame-graph by Martin Spier <mspier@netflix.com>
|
|
|
|
from __future__ import print_function
|
|
import sys
|
|
import os
|
|
import io
|
|
import argparse
|
|
import json
|
|
|
|
|
|
class Node:
|
|
def __init__(self, name, libtype=""):
|
|
self.name = name
|
|
self.libtype = libtype
|
|
self.value = 0
|
|
self.children = []
|
|
|
|
def toJSON(self):
|
|
return {
|
|
"n": self.name,
|
|
"l": self.libtype,
|
|
"v": self.value,
|
|
"c": 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("Flame Graph template {} does not exist. Please install "
|
|
"the js-d3-flame-graph (RPM) or libjs-d3-flame-graph (deb) "
|
|
"package, specify an existing flame graph template "
|
|
"(--template PATH) or another output format "
|
|
"(--format FORMAT).".format(self.args.template),
|
|
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):
|
|
json_str = json.dumps(self.stack, default=lambda x: x.toJSON())
|
|
|
|
if self.args.format == "html":
|
|
try:
|
|
with io.open(self.args.template, encoding="utf-8") as f:
|
|
output_str = f.read().replace("/** @flamegraph_json **/",
|
|
json_str)
|
|
except IOError as e:
|
|
print("Error reading template file: {}".format(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 == "-":
|
|
with io.open(sys.stdout.fileno(), "w", encoding="utf-8", closefd=False) as out:
|
|
out.write(output_str)
|
|
else:
|
|
print("dumping data to {}".format(output_fn))
|
|
try:
|
|
with io.open(output_fn, "w", encoding="utf-8") as out:
|
|
out.write(output_str)
|
|
except IOError as e:
|
|
print("Error writing output file: {}".format(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("--template",
|
|
default="/usr/share/d3-flame-graph/d3-flamegraph-base.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
|