diff options
Diffstat (limited to 'tools/perf/scripts/python')
-rw-r--r-- | tools/perf/scripts/python/Perf-Trace-Util/Build | 2 | ||||
-rw-r--r-- | tools/perf/scripts/python/Perf-Trace-Util/Context.c | 17 | ||||
-rwxr-xr-x | tools/perf/scripts/python/arm-cs-trace-disasm.py | 1 | ||||
-rwxr-xr-x | tools/perf/scripts/python/flamegraph.py | 107 | ||||
-rw-r--r-- | tools/perf/scripts/python/intel-pt-events.py | 8 | ||||
-rwxr-xr-x | tools/perf/scripts/python/net_dropmonitor.py | 4 | ||||
-rw-r--r-- | tools/perf/scripts/python/netdev-times.py | 6 | ||||
-rwxr-xr-x | tools/perf/scripts/python/task-analyzer.py | 2 |
8 files changed, 108 insertions, 39 deletions
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Build b/tools/perf/scripts/python/Perf-Trace-Util/Build index d5fed4e42617..7d0e33ce6aba 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Build +++ b/tools/perf/scripts/python/Perf-Trace-Util/Build @@ -1,3 +1,3 @@ -perf-$(CONFIG_LIBTRACEEVENT) += Context.o +perf-y += Context.o CFLAGS_Context.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 895f5fc23965..3954bd1587ce 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -59,6 +59,7 @@ static struct scripting_context *get_scripting_context(PyObject *args) return get_args(args, "context", NULL); } +#ifdef HAVE_LIBTRACEEVENT static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args) { struct scripting_context *c = get_scripting_context(args); @@ -90,6 +91,7 @@ static PyObject *perf_trace_context_common_lock_depth(PyObject *obj, return Py_BuildValue("i", common_lock_depth(c)); } +#endif static PyObject *perf_sample_insn(PyObject *obj, PyObject *args) { @@ -98,10 +100,11 @@ static PyObject *perf_sample_insn(PyObject *obj, PyObject *args) if (!c) return NULL; - if (c->sample->ip && !c->sample->insn_len && - c->al->thread->maps && c->al->thread->maps->machine) - script_fetch_insn(c->sample, c->al->thread, c->al->thread->maps->machine); + if (c->sample->ip && !c->sample->insn_len && thread__maps(c->al->thread)) { + struct machine *machine = maps__machine(thread__maps(c->al->thread)); + script_fetch_insn(c->sample, c->al->thread, machine); + } if (!c->sample->insn_len) Py_RETURN_NONE; /* N.B. This is a return statement */ @@ -142,6 +145,7 @@ static PyObject *perf_sample_src(PyObject *obj, PyObject *args, bool get_srccode char *srccode = NULL; PyObject *result; struct map *map; + struct dso *dso; int len = 0; u64 addr; @@ -150,9 +154,10 @@ static PyObject *perf_sample_src(PyObject *obj, PyObject *args, bool get_srccode map = c->al->map; addr = c->al->addr; + dso = map ? map__dso(map) : NULL; - if (map && map->dso) - srcfile = get_srcline_split(map->dso, map__rip_2objdump(map, addr), &line); + if (dso) + srcfile = get_srcline_split(dso, map__rip_2objdump(map, addr), &line); if (get_srccode) { if (srcfile) @@ -178,12 +183,14 @@ static PyObject *perf_sample_srccode(PyObject *obj, PyObject *args) } static PyMethodDef ContextMethods[] = { +#ifdef HAVE_LIBTRACEEVENT { "common_pc", perf_trace_context_common_pc, METH_VARARGS, "Get the common preempt count event field value."}, { "common_flags", perf_trace_context_common_flags, METH_VARARGS, "Get the common flags event field value."}, { "common_lock_depth", perf_trace_context_common_lock_depth, METH_VARARGS, "Get the common lock depth event field value."}, +#endif { "perf_sample_insn", perf_sample_insn, METH_VARARGS, "Get the machine code instruction."}, { "perf_set_itrace_options", perf_set_itrace_options, diff --git a/tools/perf/scripts/python/arm-cs-trace-disasm.py b/tools/perf/scripts/python/arm-cs-trace-disasm.py index 4339692a8d0b..d59ff53f1d94 100755 --- a/tools/perf/scripts/python/arm-cs-trace-disasm.py +++ b/tools/perf/scripts/python/arm-cs-trace-disasm.py @@ -9,7 +9,6 @@ from __future__ import print_function import os from os import path -import sys import re from subprocess import * from optparse import OptionParser, make_option diff --git a/tools/perf/scripts/python/flamegraph.py b/tools/perf/scripts/python/flamegraph.py index b6af1dd5f816..cf7ce8229a6c 100755 --- a/tools/perf/scripts/python/flamegraph.py +++ b/tools/perf/scripts/python/flamegraph.py @@ -19,12 +19,34 @@ # pylint: disable=missing-function-docstring from __future__ import print_function -import sys -import os -import io import argparse +import hashlib +import io import json +import os import subprocess +import sys +import urllib.request + +minimal_html = """<head> + <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/d3-flamegraph.css"> +</head> +<body> + <div id="chart"></div> + <script type="text/javascript" src="https://d3js.org/d3.v7.js"></script> + <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/d3-flamegraph.min.js"></script> + <script type="text/javascript"> + const stacks = [/** @flamegraph_json **/]; + // Note, options is unused. + const options = [/** @options_json **/]; + + var chart = flamegraph(); + d3.select("#chart") + .datum(stacks[0]) + .call(chart); + </script> +</body> +""" # pylint: disable=too-few-public-methods class Node: @@ -50,16 +72,6 @@ class FlameGraphCLI: self.args = args self.stack = Node("all", "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) - @staticmethod def get_libtype_from_dso(dso): """ @@ -128,16 +140,63 @@ class FlameGraphCLI: } options_json = json.dumps(options) + template_md5sum = None + if self.args.format == "html": + if os.path.isfile(self.args.template): + template = f"file://{self.args.template}" + else: + if not self.args.allow_download: + print(f"""Warning: Flame Graph template '{self.args.template}' +does not exist. To avoid this please install a package such as the +js-d3-flame-graph or libjs-d3-flame-graph, specify an existing flame +graph template (--template PATH) or use another output format (--format +FORMAT).""", + file=sys.stderr) + if self.args.input == "-": + print("""Not attempting to download Flame Graph template as script command line +input is disabled due to using live mode. If you want to download the +template retry without live mode. For example, use 'perf record -a -g +-F 99 sleep 60' and 'perf script report flamegraph'. Alternatively, +download the template from: +https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/templates/d3-flamegraph-base.html +and place it at: +/usr/share/d3-flame-graph/d3-flamegraph-base.html""", + file=sys.stderr) + quit() + s = None + while s != "y" and s != "n": + s = input("Do you wish to download a template from cdn.jsdelivr.net? (this warning can be suppressed with --allow-download) [yn] ").lower() + if s == "n": + quit() + template = "https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/templates/d3-flamegraph-base.html" + template_md5sum = "143e0d06ba69b8370b9848dcd6ae3f36" + try: - with io.open(self.args.template, encoding="utf-8") as template: - output_str = ( - template.read() - .replace("/** @options_json **/", options_json) - .replace("/** @flamegraph_json **/", stacks_json) - ) - except IOError as err: - print("Error reading template file: {}".format(err), file=sys.stderr) - sys.exit(1) + with urllib.request.urlopen(template) as template: + output_str = "".join([ + l.decode("utf-8") for l in template.readlines() + ]) + except Exception as err: + print(f"Error reading template {template}: {err}\n" + "a minimal flame graph will be generated", file=sys.stderr) + output_str = minimal_html + template_md5sum = None + + if template_md5sum: + download_md5sum = hashlib.md5(output_str.encode("utf-8")).hexdigest() + if download_md5sum != template_md5sum: + s = None + while s != "y" and s != "n": + s = input(f"""Unexpected template md5sum. +{download_md5sum} != {template_md5sum}, for: +{output_str} +continue?[yn] """).lower() + if s == "n": + quit() + + output_str = output_str.replace("/** @options_json **/", options_json) + output_str = output_str.replace("/** @flamegraph_json **/", stacks_json) + output_fn = self.args.output or "flamegraph.html" else: output_str = stacks_json @@ -172,6 +231,10 @@ if __name__ == "__main__": choices=["blue-green", "orange"]) parser.add_argument("-i", "--input", help=argparse.SUPPRESS) + parser.add_argument("--allow-download", + default=False, + action="store_true", + help="allow unprompted downloading of HTML template") cli_args = parser.parse_args() cli = FlameGraphCLI(cli_args) diff --git a/tools/perf/scripts/python/intel-pt-events.py b/tools/perf/scripts/python/intel-pt-events.py index 08862a2582f4..346c89bd16d6 100644 --- a/tools/perf/scripts/python/intel-pt-events.py +++ b/tools/perf/scripts/python/intel-pt-events.py @@ -11,7 +11,7 @@ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. -from __future__ import print_function +from __future__ import division, print_function import io import os @@ -340,7 +340,6 @@ def print_srccode(comm, param_dict, sample, symbol, dso, with_insn): print(start_str, src_str) def do_process_event(param_dict): - event_attr = param_dict["attr"] sample = param_dict["sample"] raw_buf = param_dict["raw_buf"] comm = param_dict["comm"] @@ -349,6 +348,7 @@ def do_process_event(param_dict): # callchain = param_dict["callchain"] # brstack = param_dict["brstack"] # brstacksym = param_dict["brstacksym"] + # event_attr = param_dict["attr"] # Symbol and dso info are not always resolved dso = get_optional(param_dict, "dso") @@ -359,13 +359,13 @@ def do_process_event(param_dict): print(glb_switch_str[cpu]) del glb_switch_str[cpu] - if name[0:12] == "instructions": + if name.startswith("instructions"): if glb_src: print_srccode(comm, param_dict, sample, symbol, dso, True) else: print_instructions_start(comm, sample) print_common_ip(param_dict, sample, symbol, dso) - elif name[0:8] == "branches": + elif name.startswith("branches"): if glb_src: print_srccode(comm, param_dict, sample, symbol, dso, False) else: diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py index 101059971738..a97e7a6e0940 100755 --- a/tools/perf/scripts/python/net_dropmonitor.py +++ b/tools/perf/scripts/python/net_dropmonitor.py @@ -68,9 +68,9 @@ def trace_end(): get_kallsyms_table() print_drop_table() -# called from perf, when it finds a correspoinding event +# called from perf, when it finds a corresponding event def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, - skbaddr, location, protocol): + skbaddr, location, protocol, reason): slocation = str(location) try: drop_log[slocation] = drop_log[slocation] + 1 diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py index a0cfc7fe5908..00552eeb7178 100644 --- a/tools/perf/scripts/python/netdev-times.py +++ b/tools/perf/scripts/python/netdev-times.py @@ -288,9 +288,9 @@ def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, callchain, all_event_list.append(event_info) def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, - skbaddr, protocol, location): + skbaddr, location, protocol, reason): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, - skbaddr, protocol, location) + skbaddr, location, protocol, reason) all_event_list.append(event_info) def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr): @@ -430,7 +430,7 @@ def handle_net_dev_xmit(event_info): def handle_kfree_skb(event_info): (name, context, cpu, time, pid, comm, - skbaddr, protocol, location) = event_info + skbaddr, location, protocol, reason) = event_info for i in range(len(tx_queue_list)): skb = tx_queue_list[i] if skb['skbaddr'] == skbaddr: diff --git a/tools/perf/scripts/python/task-analyzer.py b/tools/perf/scripts/python/task-analyzer.py index 52e8dae9b1f0..3f1df9894246 100755 --- a/tools/perf/scripts/python/task-analyzer.py +++ b/tools/perf/scripts/python/task-analyzer.py @@ -114,7 +114,7 @@ def _parse_args(): "--ns", action="store_true", help="show timestamps in nanoseconds" ) parser.add_argument( - "--ms", action="store_true", help="show timestamps in miliseconds" + "--ms", action="store_true", help="show timestamps in milliseconds" ) parser.add_argument( "--extended-times", |