aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/perf/scripts/python
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/scripts/python')
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/Build2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/Context.c17
-rwxr-xr-xtools/perf/scripts/python/arm-cs-trace-disasm.py1
-rwxr-xr-xtools/perf/scripts/python/flamegraph.py107
-rw-r--r--tools/perf/scripts/python/intel-pt-events.py8
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py4
-rw-r--r--tools/perf/scripts/python/netdev-times.py6
-rwxr-xr-xtools/perf/scripts/python/task-analyzer.py2
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",