From: Andreas Gerstmayr <agerstmayr@redhat.com>
To: linux-perf-users@vger.kernel.org
Cc: Martin Spier <mspier@netflix.com>,
Brendan Gregg <bgregg@netflix.com>,
Andreas Gerstmayr <agerstmayr@redhat.com>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@redhat.com>, Namhyung Kim <namhyung@kernel.org>,
linux-kernel@vger.kernel.org
Subject: [PATCH] perf script: add flamegraph.py script
Date: Fri, 20 Mar 2020 16:13:48 +0100 [thread overview]
Message-ID: <20200320151355.66302-1-agerstmayr@redhat.com> (raw)
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/d3-flamegraph-base.html and fill in the collected
stacks.
Usage:
perf record -a -g -F 99 sleep 60
perf script report flamegraph
Combined:
perf script flamegraph -a -F 99 sleep 60
Signed-off-by: Andreas Gerstmayr <agerstmayr@redhat.com>
---
Package for d3-flame-graph is currently under review, in the meantime you can
download the template from:
https://cdn.jsdelivr.net/npm/d3-flame-graph@3.0.2/dist/templates/d3-flamegraph-base.html
and move it to /usr/share/d3-flame-graph/d3-flamegraph-base.html
.../perf/scripts/python/bin/flamegraph-record | 2 +
.../perf/scripts/python/bin/flamegraph-report | 3 +
tools/perf/scripts/python/flamegraph.py | 126 ++++++++++++++++++
3 files changed, 131 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..5835d190ca42
--- /dev/null
+++ b/tools/perf/scripts/python/flamegraph.py
@@ -0,0 +1,126 @@
+# 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>
+
+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 = []
+
+ 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(f"Flame Graph template {self.args.template} does not " +
+ f"exist. Please install the js-d3-flame-graph (RPM) or " +
+ f"libjs-d3-flame-graph (deb) package, specify an " +
+ f"existing flame graph template (--template PATH) or " +
+ f"another output format (--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):
+ json_str = json.dumps(self.stack, default=lambda x: x.toJSON(),
+ indent=self.args.indent)
+
+ if self.args.format == "html":
+ try:
+ with open(self.args.template) as f:
+ output_str = f.read().replace("/** @flamegraph_json **/",
+ 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:
+ print(f"dumping data to {output_fn}")
+ 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/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
--
2.25.1
next reply other threads:[~2020-03-20 15:14 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-20 15:13 Andreas Gerstmayr [this message]
2020-03-24 16:16 ` [PATCH] perf script: add flamegraph.py script Kim Phillips
2020-03-24 19:05 ` Andreas Gerstmayr
2020-03-24 21:26 ` Arnaldo Melo
2020-03-26 19:04 ` Kim Phillips
2020-04-02 12:43 ` [PATCH] perf script: fix invalid read Andreas Gerstmayr
2020-04-02 15:15 ` Arnaldo Carvalho de Melo
2020-04-04 8:41 ` [tip: perf/urgent] perf script: Fix invalid read of directory entry after closedir() tip-bot2 for Andreas Gerstmayr
2020-04-02 12:54 ` [PATCH] perf script report: fix segfault when using DWARF mode Andreas Gerstmayr
2020-04-02 15:16 ` Arnaldo Carvalho de Melo
2020-04-02 19:07 ` Kim Phillips
2020-04-03 12:40 ` Arnaldo Carvalho de Melo
2020-04-03 13:16 ` Andreas Gerstmayr
2020-04-06 9:30 ` Andreas Gerstmayr
2020-04-06 12:59 ` Arnaldo Carvalho de Melo
2020-04-06 14:28 ` Kim Phillips
2020-04-04 8:41 ` [tip: perf/urgent] perf script report: Fix SEGFAULT " tip-bot2 for Andreas Gerstmayr
2020-04-02 13:04 ` [PATCH] perf script: add flamegraph.py script Andreas Gerstmayr
2020-04-06 14:27 ` Kim Phillips
2020-04-06 15:11 ` Arnaldo Carvalho de Melo
2020-04-09 16:57 ` [PATCH] perf script flamegraph: python2 support, update cli args Andreas Gerstmayr
2020-04-13 13:59 ` Arnaldo Carvalho de Melo
2020-04-09 17:14 ` [PATCH] perf script: add flamegraph.py script Andreas Gerstmayr
2020-04-22 12:17 ` [tip: perf/core] perf script: Add " tip-bot2 for Andreas Gerstmayr
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200320151355.66302-1-agerstmayr@redhat.com \
--to=agerstmayr@redhat.com \
--cc=acme@kernel.org \
--cc=alexander.shishkin@linux.intel.com \
--cc=bgregg@netflix.com \
--cc=jolsa@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=mspier@netflix.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.