* [PATCH v7 10/59] perf evlist: Add reference count
From: Ian Rogers @ 2026-04-25 22:49 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
This a no-op for most of the perf tool. The reference count is set to
1 at allocation, the put will see the 1, decrement it and perform the
delete. The purpose for adding the reference count is for the python
code. Prior to this change the python code would clone evlists, but
this has issues if events are opened, etc. This change adds a
reference count for the evlists and a later change will add it to
evsels. The combination is needed for the python code to operate
correctly (not hit asserts in the evsel clone), but the changes are
broken apart for the sake of smaller patches.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2: Added evlist__put to pyrf_evlist__init in case init is called more
than once.
I double-checked trace__replay() and confirmed that trace->evlist
is not assigned to session->evlist in that function.
trace__replay creates a new session and uses its own evlist for
processing file events, leaving trace->evlist pointing to the
empty list created at startup. Therefore, the
evlist__put(trace->evlist) call in trace__exit() is safe and
correct to avoid leaking that empty list.
v7:
- Added pyrf_evlist__new to zero-initialize pevlist->evlist to fix
crash on re-initialization.
---
tools/perf/arch/x86/tests/hybrid.c | 2 +-
tools/perf/arch/x86/tests/topdown.c | 2 +-
tools/perf/arch/x86/util/iostat.c | 2 +-
tools/perf/bench/evlist-open-close.c | 18 +-
tools/perf/builtin-ftrace.c | 8 +-
tools/perf/builtin-kvm.c | 4 +-
tools/perf/builtin-lock.c | 2 +-
tools/perf/builtin-record.c | 4 +-
tools/perf/builtin-sched.c | 6 +-
tools/perf/builtin-script.c | 2 +-
tools/perf/builtin-stat.c | 10 +-
tools/perf/builtin-top.c | 52 ++---
tools/perf/builtin-trace.c | 26 +--
tools/perf/tests/backward-ring-buffer.c | 18 +-
tools/perf/tests/code-reading.c | 4 +-
tools/perf/tests/event-times.c | 4 +-
tools/perf/tests/event_update.c | 2 +-
tools/perf/tests/evsel-roundtrip-name.c | 8 +-
tools/perf/tests/expand-cgroup.c | 8 +-
tools/perf/tests/hists_cumulate.c | 2 +-
tools/perf/tests/hists_filter.c | 2 +-
tools/perf/tests/hists_link.c | 2 +-
tools/perf/tests/hists_output.c | 2 +-
tools/perf/tests/hwmon_pmu.c | 2 +-
tools/perf/tests/keep-tracking.c | 2 +-
tools/perf/tests/mmap-basic.c | 18 +-
tools/perf/tests/openat-syscall-tp-fields.c | 18 +-
tools/perf/tests/parse-events.c | 4 +-
tools/perf/tests/parse-metric.c | 4 +-
tools/perf/tests/parse-no-sample-id-all.c | 2 +-
tools/perf/tests/perf-record.c | 18 +-
tools/perf/tests/perf-time-to-tsc.c | 2 +-
tools/perf/tests/pfm.c | 4 +-
tools/perf/tests/pmu-events.c | 6 +-
tools/perf/tests/pmu.c | 4 +-
tools/perf/tests/sw-clock.c | 14 +-
tools/perf/tests/switch-tracking.c | 2 +-
tools/perf/tests/task-exit.c | 14 +-
tools/perf/tests/tool_pmu.c | 2 +-
tools/perf/tests/topology.c | 2 +-
tools/perf/util/cgroup.c | 4 +-
tools/perf/util/data-convert-bt.c | 2 +-
tools/perf/util/evlist.c | 20 +-
tools/perf/util/evlist.h | 7 +-
tools/perf/util/expr.c | 2 +-
| 12 +-
tools/perf/util/metricgroup.c | 6 +-
tools/perf/util/parse-events.c | 4 +-
tools/perf/util/perf_api_probe.c | 2 +-
tools/perf/util/python.c | 212 ++++++++------------
tools/perf/util/record.c | 2 +-
tools/perf/util/session.c | 2 +-
tools/perf/util/sideband_evlist.c | 16 +-
53 files changed, 279 insertions(+), 320 deletions(-)
diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c
index e221ea104174..dfb0ffc0d030 100644
--- a/tools/perf/arch/x86/tests/hybrid.c
+++ b/tools/perf/arch/x86/tests/hybrid.c
@@ -268,7 +268,7 @@ static int test_event(const struct evlist_test *e)
ret = e->check(evlist);
}
parse_events_error__exit(&err);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c
index 3ee4e5e71be3..2d0ae5b0d76c 100644
--- a/tools/perf/arch/x86/tests/topdown.c
+++ b/tools/perf/arch/x86/tests/topdown.c
@@ -56,7 +56,7 @@ static int event_cb(void *state, struct pmu_event_info *info)
*ret = TEST_FAIL;
}
}
- evlist__delete(evlist);
+ evlist__put(evlist);
return 0;
}
diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c
index 7442a2cd87ed..e0417552b0cb 100644
--- a/tools/perf/arch/x86/util/iostat.c
+++ b/tools/perf/arch/x86/util/iostat.c
@@ -337,7 +337,7 @@ int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config)
if (evlist->core.nr_entries > 0) {
pr_warning("The -e and -M options are not supported."
"All chosen events/metrics will be dropped\n");
- evlist__delete(evlist);
+ evlist__put(evlist);
evlist = evlist__new();
if (!evlist)
return -ENOMEM;
diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c
index faf9c34b4a5d..304929d1f67f 100644
--- a/tools/perf/bench/evlist-open-close.c
+++ b/tools/perf/bench/evlist-open-close.c
@@ -76,7 +76,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
parse_events_error__exit(&err);
pr_err("Run 'perf list' for a list of valid events\n");
ret = 1;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
parse_events_error__exit(&err);
if (uid_str) {
@@ -85,24 +85,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
if (uid == UINT_MAX) {
pr_err("Invalid User: %s", uid_str);
ret = -EINVAL;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
ret = parse_uid_filter(evlist, uid);
if (ret)
- goto out_delete_evlist;
+ goto out_put_evlist;
}
ret = evlist__create_maps(evlist, &opts.target);
if (ret < 0) {
pr_err("Not enough memory to create thread/cpu maps\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__config(evlist, &opts, NULL);
return evlist;
-out_delete_evlist:
- evlist__delete(evlist);
+out_put_evlist:
+ evlist__put(evlist);
return NULL;
}
@@ -151,7 +151,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
evlist->core.nr_entries, evlist__count_evsel_fds(evlist));
printf(" Number of iterations:\t%d\n", iterations);
- evlist__delete(evlist);
+ evlist__put(evlist);
for (i = 0; i < iterations; i++) {
pr_debug("Started iteration %d\n", i);
@@ -162,7 +162,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
gettimeofday(&start, NULL);
err = bench__do_evlist_open_close(evlist);
if (err) {
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
@@ -171,7 +171,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
runtime_us = timeval2usec(&diff);
update_stats(&time_stats, runtime_us);
- evlist__delete(evlist);
+ evlist__put(evlist);
pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us);
}
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 8a7dbfb14535..676239148b87 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -1999,20 +1999,20 @@ int cmd_ftrace(int argc, const char **argv)
ret = evlist__create_maps(ftrace.evlist, &ftrace.target);
if (ret < 0)
- goto out_delete_evlist;
+ goto out_put_evlist;
if (argc) {
ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target,
argv, false,
ftrace__workload_exec_failed_signal);
if (ret < 0)
- goto out_delete_evlist;
+ goto out_put_evlist;
}
ret = cmd_func(&ftrace);
-out_delete_evlist:
- evlist__delete(ftrace.evlist);
+out_put_evlist:
+ evlist__put(ftrace.evlist);
out_delete_filters:
delete_filter_func(&ftrace.filters);
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 0c5e6b3aac74..d88855e3c7b4 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1811,7 +1811,7 @@ static struct evlist *kvm_live_event_list(void)
out:
if (err) {
- evlist__delete(evlist);
+ evlist__put(evlist);
evlist = NULL;
}
@@ -1942,7 +1942,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
out:
perf_session__delete(kvm->session);
kvm->session = NULL;
- evlist__delete(kvm->evlist);
+ evlist__put(kvm->evlist);
return err;
}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 5585aeb97684..c40d070f6c36 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -2145,7 +2145,7 @@ static int __cmd_contention(int argc, const char **argv)
out_delete:
lock_filter_finish();
- evlist__delete(con.evlist);
+ evlist__put(con.evlist);
lock_contention_finish(&con);
perf_session__delete(session);
perf_env__exit(&host_env);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4a5eba498c02..b4fffa936e01 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -4289,7 +4289,7 @@ int cmd_record(int argc, const char **argv)
goto out;
evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries);
- evlist__delete(def_evlist);
+ evlist__put(def_evlist);
}
if (rec->opts.target.tid && !rec->opts.no_inherit_set)
@@ -4397,7 +4397,7 @@ int cmd_record(int argc, const char **argv)
auxtrace_record__free(rec->itr);
out_opts:
evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.ctl_fd_close);
- evlist__delete(rec->evlist);
+ evlist__put(rec->evlist);
return err;
}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 555247568e7a..d683642ab4e0 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -3829,7 +3829,7 @@ static int perf_sched__schedstat_record(struct perf_sched *sched,
session = perf_session__new(&data, &sched->tool);
if (IS_ERR(session)) {
pr_err("Perf session creation failed.\n");
- evlist__delete(evlist);
+ evlist__put(evlist);
return PTR_ERR(session);
}
@@ -3925,7 +3925,7 @@ static int perf_sched__schedstat_record(struct perf_sched *sched,
else
fprintf(stderr, "[ perf sched stats: Failed !! ]\n");
- evlist__delete(evlist);
+ evlist__put(evlist);
close(fd);
return err;
}
@@ -4724,7 +4724,7 @@ static int perf_sched__schedstat_live(struct perf_sched *sched,
free_cpu_domain_info(cd_map, sv, nr);
out:
free_schedstat(&cpu_head);
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 853b141a0d50..0ead134940d5 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -2269,7 +2269,7 @@ static int script_find_metrics(const struct pmu_metric *pm,
}
pr_debug("Found metric '%s' whose evsels match those of in the perf data\n",
pm->metric_name);
- evlist__delete(metric_evlist);
+ evlist__put(metric_evlist);
out:
return 0;
}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 99d7db372b48..bfa3512e1686 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -2113,7 +2113,7 @@ static int add_default_events(void)
stat_config.user_requested_cpu_list,
stat_config.system_wide,
stat_config.hardware_aware_grouping) < 0) {
- evlist__delete(metric_evlist);
+ evlist__put(metric_evlist);
ret = -1;
break;
}
@@ -2125,7 +2125,7 @@ static int add_default_events(void)
metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL,
&evlist->metric_events,
&metric_evlist->metric_events);
- evlist__delete(metric_evlist);
+ evlist__put(metric_evlist);
}
list_sort(/*priv=*/NULL, &evlist->core.entries, default_evlist_evsel_cmp);
@@ -2146,7 +2146,7 @@ static int add_default_events(void)
metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL,
&evsel_list->metric_events,
&evlist->metric_events);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
@@ -2381,7 +2381,7 @@ static int __cmd_report(int argc, const char **argv)
perf_stat.session = session;
stat_config.output = stderr;
- evlist__delete(evsel_list);
+ evlist__put(evsel_list);
evsel_list = session->evlist;
ret = perf_session__process_events(session);
@@ -3060,7 +3060,7 @@ int cmd_stat(int argc, const char **argv)
if (smi_cost && smi_reset)
sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
- evlist__delete(evsel_list);
+ evlist__put(evsel_list);
evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index f6eb543de537..c509cfef8285 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1652,14 +1652,14 @@ int cmd_top(int argc, const char **argv)
perf_env__init(&host_env);
status = perf_config(perf_top_config, &top);
if (status)
- goto out_delete_evlist;
+ goto out_put_evlist;
/*
* Since the per arch annotation init routine may need the cpuid, read
* it here, since we are not getting this from the perf.data header.
*/
status = perf_env__set_cmdline(&host_env, argc, argv);
if (status)
- goto out_delete_evlist;
+ goto out_put_evlist;
status = perf_env__read_cpuid(&host_env);
if (status) {
@@ -1680,30 +1680,30 @@ int cmd_top(int argc, const char **argv)
annotate_opts.disassembler_style = strdup(disassembler_style);
if (!annotate_opts.disassembler_style) {
status = -ENOMEM;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
if (objdump_path) {
annotate_opts.objdump_path = strdup(objdump_path);
if (!annotate_opts.objdump_path) {
status = -ENOMEM;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
if (addr2line_path) {
symbol_conf.addr2line_path = strdup(addr2line_path);
if (!symbol_conf.addr2line_path) {
status = -ENOMEM;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
status = symbol__validate_sym_arguments();
if (status)
- goto out_delete_evlist;
+ goto out_put_evlist;
if (annotate_check_args() < 0)
- goto out_delete_evlist;
+ goto out_put_evlist;
status = target__validate(target);
if (status) {
@@ -1718,15 +1718,15 @@ int cmd_top(int argc, const char **argv)
struct evlist *def_evlist = evlist__new_default(target, callchain_param.enabled);
if (!def_evlist)
- goto out_delete_evlist;
+ goto out_put_evlist;
evlist__splice_list_tail(top.evlist, &def_evlist->core.entries);
- evlist__delete(def_evlist);
+ evlist__put(def_evlist);
}
status = evswitch__init(&top.evswitch, top.evlist, stderr);
if (status)
- goto out_delete_evlist;
+ goto out_put_evlist;
if (symbol_conf.report_hierarchy) {
/* disable incompatible options */
@@ -1737,18 +1737,18 @@ int cmd_top(int argc, const char **argv)
pr_err("Error: --hierarchy and --fields options cannot be used together\n");
parse_options_usage(top_usage, options, "fields", 0);
parse_options_usage(NULL, options, "hierarchy", 0);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
if (top.stitch_lbr && !(callchain_param.record_mode == CALLCHAIN_LBR)) {
pr_err("Error: --stitch-lbr must be used with --call-graph lbr\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (nr_cgroups > 0 && opts->record_cgroup) {
pr_err("--cgroup and --all-cgroups cannot be used together\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (branch_call_mode) {
@@ -1772,7 +1772,7 @@ int cmd_top(int argc, const char **argv)
status = perf_env__read_core_pmu_caps(&host_env);
if (status) {
pr_err("PMU capability data is not available\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
@@ -1795,7 +1795,7 @@ int cmd_top(int argc, const char **argv)
if (IS_ERR(top.session)) {
status = PTR_ERR(top.session);
top.session = NULL;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
top.evlist->session = top.session;
@@ -1805,7 +1805,7 @@ int cmd_top(int argc, const char **argv)
if (field_order)
parse_options_usage(sort_order ? NULL : top_usage,
options, "fields", 0);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (top.uid_str) {
@@ -1814,18 +1814,18 @@ int cmd_top(int argc, const char **argv)
if (uid == UINT_MAX) {
ui__error("Invalid User: %s", top.uid_str);
status = -EINVAL;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
status = parse_uid_filter(top.evlist, uid);
if (status)
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (evlist__create_maps(top.evlist, target) < 0) {
ui__error("Couldn't create thread/CPU maps: %s\n",
errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf)));
status = -errno;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (top.delay_secs < 1)
@@ -1833,7 +1833,7 @@ int cmd_top(int argc, const char **argv)
if (record_opts__config(opts)) {
status = -EINVAL;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
top.sym_evsel = evlist__first(top.evlist);
@@ -1848,14 +1848,14 @@ int cmd_top(int argc, const char **argv)
status = symbol__annotation_init();
if (status < 0)
- goto out_delete_evlist;
+ goto out_put_evlist;
annotation_config__init();
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
status = symbol__init(NULL);
if (status < 0)
- goto out_delete_evlist;
+ goto out_put_evlist;
sort__setup_elide(stdout);
@@ -1875,13 +1875,13 @@ int cmd_top(int argc, const char **argv)
if (top.sb_evlist == NULL) {
pr_err("Couldn't create side band evlist.\n.");
status = -EINVAL;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (evlist__add_bpf_sb_event(top.sb_evlist, &host_env)) {
pr_err("Couldn't ask for PERF_RECORD_BPF_EVENT side band events.\n.");
status = -EINVAL;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
#endif
@@ -1896,8 +1896,8 @@ int cmd_top(int argc, const char **argv)
if (!opts->no_bpf_event)
evlist__stop_sb_thread(top.sb_evlist);
-out_delete_evlist:
- evlist__delete(top.evlist);
+out_put_evlist:
+ evlist__put(top.evlist);
perf_session__delete(top.session);
annotation_options__exit();
perf_env__exit(&host_env);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index e58c49d047a2..da703d762433 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -4388,7 +4388,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
if (trace->summary_bpf) {
if (trace_prepare_bpf_summary(trace->summary_mode) < 0)
- goto out_delete_evlist;
+ goto out_put_evlist;
if (trace->summary_only)
goto create_maps;
@@ -4456,19 +4456,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
err = evlist__create_maps(evlist, &trace->opts.target);
if (err < 0) {
fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
err = trace__symbols_init(trace, argc, argv, evlist);
if (err < 0) {
fprintf(trace->output, "Problems initializing symbol libraries!\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
trace->syscall_stats = alloc_syscall_stats();
if (!trace->syscall_stats)
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__config(evlist, &trace->opts, &callchain_param);
@@ -4477,7 +4477,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
if (err < 0) {
fprintf(trace->output, "Couldn't run the workload!\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
workload_pid = evlist->workload.pid;
}
@@ -4525,7 +4525,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
err = trace__expand_filters(trace, &evsel);
if (err)
- goto out_delete_evlist;
+ goto out_put_evlist;
err = evlist__apply_filters(evlist, &evsel, &trace->opts.target);
if (err < 0)
goto out_error_apply_filters;
@@ -4642,12 +4642,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
}
}
-out_delete_evlist:
+out_put_evlist:
trace_cleanup_bpf_summary();
delete_syscall_stats(trace->syscall_stats);
trace__symbols__exit(trace);
evlist__free_syscall_tp_fields(evlist);
- evlist__delete(evlist);
+ evlist__put(evlist);
cgroup__put(trace->cgroup);
trace->evlist = NULL;
trace->live = false;
@@ -4672,21 +4672,21 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
out_error:
fprintf(trace->output, "%s\n", errbuf);
- goto out_delete_evlist;
+ goto out_put_evlist;
out_error_apply_filters:
fprintf(trace->output,
"Failed to set filter \"%s\" on event %s: %m\n",
evsel->filter, evsel__name(evsel));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
out_error_mem:
fprintf(trace->output, "Not enough memory to run!\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
out_errno:
fprintf(trace->output, "%m\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
static int trace__replay(struct trace *trace)
@@ -5364,7 +5364,7 @@ static void trace__exit(struct trace *trace)
zfree(&trace->syscalls.table);
}
zfree(&trace->perfconfig_events);
- evlist__delete(trace->evlist);
+ evlist__put(trace->evlist);
trace->evlist = NULL;
ordered_events__free(&trace->oe.data);
#ifdef HAVE_LIBBPF_SUPPORT
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
index c5e7999f2817..2b49b002d749 100644
--- a/tools/perf/tests/backward-ring-buffer.c
+++ b/tools/perf/tests/backward-ring-buffer.c
@@ -111,7 +111,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
err = evlist__create_maps(evlist, &opts.target);
if (err < 0) {
pr_debug("Not enough memory to create thread/cpu maps\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
parse_events_error__init(&parse_error);
@@ -124,7 +124,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
if (err) {
pr_debug("Failed to parse tracepoint event, try use root\n");
ret = TEST_SKIP;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__config(evlist, &opts, NULL);
@@ -133,19 +133,19 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
if (err < 0) {
pr_debug("perf_evlist__open: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
ret = TEST_FAIL;
err = do_test(evlist, opts.mmap_pages, &sample_count,
&comm_count);
if (err != TEST_OK)
- goto out_delete_evlist;
+ goto out_put_evlist;
if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
sample_count, comm_count);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__close(evlist);
@@ -154,16 +154,16 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
if (err < 0) {
pr_debug("perf_evlist__open: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
err = do_test(evlist, 1, &sample_count, &comm_count);
if (err != TEST_OK)
- goto out_delete_evlist;
+ goto out_put_evlist;
ret = TEST_OK;
-out_delete_evlist:
- evlist__delete(evlist);
+out_put_evlist:
+ evlist__put(evlist);
return ret;
}
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 47043a3a2fb4..fc65a17f67f7 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -807,7 +807,7 @@ static int do_test_code_reading(bool try_kcore)
}
perf_evlist__set_maps(&evlist->core, NULL, NULL);
- evlist__delete(evlist);
+ evlist__put(evlist);
evlist = NULL;
continue;
}
@@ -844,7 +844,7 @@ static int do_test_code_reading(bool try_kcore)
out_put:
thread__put(thread);
out_err:
- evlist__delete(evlist);
+ evlist__put(evlist);
perf_cpu_map__put(cpus);
perf_thread_map__put(threads);
machine__delete(machine);
diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c
index ae3b98bb42cf..94ab54ecd3f9 100644
--- a/tools/perf/tests/event-times.c
+++ b/tools/perf/tests/event-times.c
@@ -186,7 +186,7 @@ static int test_times(int (attach)(struct evlist *),
err = attach(evlist);
if (err == TEST_SKIP) {
pr_debug(" SKIP : not enough rights\n");
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
@@ -205,7 +205,7 @@ static int test_times(int (attach)(struct evlist *),
count.ena, count.run);
out_err:
- evlist__delete(evlist);
+ evlist__put(evlist);
return !err ? TEST_OK : TEST_FAIL;
}
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
index facc65e29f20..73141b122d2f 100644
--- a/tools/perf/tests/event_update.c
+++ b/tools/perf/tests/event_update.c
@@ -117,7 +117,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
TEST_ASSERT_VAL("failed to synthesize attr update cpus",
!perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
- evlist__delete(evlist);
+ evlist__put(evlist);
return 0;
}
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 1922cac13a24..6a220634c52f 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -33,7 +33,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
if (err) {
pr_debug("Failure to parse cache event '%s' possibly as PMUs don't support it",
name);
- evlist__delete(evlist);
+ evlist__put(evlist);
continue;
}
evlist__for_each_entry(evlist, evsel) {
@@ -42,7 +42,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
ret = TEST_FAIL;
}
}
- evlist__delete(evlist);
+ evlist__put(evlist);
}
}
}
@@ -66,7 +66,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
if (err) {
pr_debug("failed to parse event '%s', err %d\n",
names[i], err);
- evlist__delete(evlist);
+ evlist__put(evlist);
ret = TEST_FAIL;
continue;
}
@@ -76,7 +76,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
ret = TEST_FAIL;
}
}
- evlist__delete(evlist);
+ evlist__put(evlist);
}
return ret;
}
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index dd547f2f77cc..a7a445f12693 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -106,7 +106,7 @@ static int expand_default_events(void)
TEST_ASSERT_VAL("failed to get evlist", evlist);
ret = test_expand_events(evlist);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
@@ -133,7 +133,7 @@ static int expand_group_events(void)
ret = test_expand_events(evlist);
out:
parse_events_error__exit(&err);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
@@ -164,7 +164,7 @@ static int expand_libpfm_events(void)
ret = test_expand_events(evlist);
out:
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
@@ -188,7 +188,7 @@ static int expand_metric_events(void)
ret = test_expand_events(evlist);
out:
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 606aa926a8fc..eca4ecb63ca8 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -744,7 +744,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt
out:
/* tear down everything */
- evlist__delete(evlist);
+ evlist__put(evlist);
machines__exit(&machines);
put_fake_samples();
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index cc6b26e373d1..0d09dc306019 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -332,7 +332,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes
out:
/* tear down everything */
- evlist__delete(evlist);
+ evlist__put(evlist);
reset_output_field();
machines__exit(&machines);
put_fake_samples();
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 996f5f0b3bd1..9646c3b7b4de 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -352,7 +352,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest
out:
/* tear down everything */
- evlist__delete(evlist);
+ evlist__put(evlist);
reset_output_field();
machines__exit(&machines);
put_fake_samples();
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index 7818950d786e..3f3bc978553e 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -631,7 +631,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes
out:
/* tear down everything */
- evlist__delete(evlist);
+ evlist__put(evlist);
machines__exit(&machines);
put_fake_samples();
diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
index ada6e445c4c4..1b60c3a900f1 100644
--- a/tools/perf/tests/hwmon_pmu.c
+++ b/tools/perf/tests/hwmon_pmu.c
@@ -214,7 +214,7 @@ static int do_test(size_t i, bool with_pmu, bool with_alias)
out:
parse_events_error__exit(&err);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 729cc9cc1cb7..51cfd6522867 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -153,7 +153,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte
out_err:
if (evlist) {
evlist__disable(evlist);
- evlist__delete(evlist);
+ evlist__put(evlist);
}
perf_cpu_map__put(cpus);
perf_thread_map__put(threads);
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 8d04f6edb004..e6501791c505 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -94,7 +94,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
/* Permissions failure, flag the failure as a skip. */
err = TEST_SKIP;
}
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evsels[i]->core.attr.wakeup_events = 1;
@@ -106,7 +106,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
pr_debug("failed to open counter: %s, "
"tweak /proc/sys/kernel/perf_event_paranoid?\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
nr_events[i] = 0;
@@ -116,7 +116,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
if (evlist__mmap(evlist, 128) < 0) {
pr_debug("failed to mmap events: %d (%s)\n", errno,
str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
for (i = 0; i < nsyscalls; ++i)
@@ -134,7 +134,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
if (event->header.type != PERF_RECORD_SAMPLE) {
pr_debug("unexpected %s event\n",
perf_event__name(event->header.type));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
perf_sample__init(&sample, /*all=*/false);
@@ -142,7 +142,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
if (err) {
pr_err("Can't parse sample, err = %d\n", err);
perf_sample__exit(&sample);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
err = -1;
@@ -151,7 +151,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
if (evsel == NULL) {
pr_debug("event with id %" PRIu64
" doesn't map to an evsel\n", sample.id);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
nr_events[evsel->core.idx]++;
perf_mmap__consume(&md->core);
@@ -166,12 +166,12 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
expected_nr_events[evsel->core.idx],
evsel__name(evsel), nr_events[evsel->core.idx]);
err = -1;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
-out_delete_evlist:
- evlist__delete(evlist);
+out_put_evlist:
+ evlist__put(evlist);
out_free_cpus:
perf_cpu_map__put(cpus);
out_free_threads:
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index 2a139d2781a8..3ff595c7a86a 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -51,7 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
if (IS_ERR(evsel)) {
pr_debug("%s: evsel__newtp\n", __func__);
ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__add(evlist, evsel);
@@ -59,7 +59,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
err = evlist__create_maps(evlist, &opts.target);
if (err < 0) {
pr_debug("%s: evlist__create_maps\n", __func__);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evsel__config(evsel, &opts, NULL);
@@ -70,14 +70,14 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
if (err < 0) {
pr_debug("perf_evlist__open: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
err = evlist__mmap(evlist, UINT_MAX);
if (err < 0) {
pr_debug("evlist__mmap: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__enable(evlist);
@@ -115,7 +115,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
if (err) {
pr_debug("Can't parse sample, err = %d\n", err);
perf_sample__exit(&sample);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
tp_flags = evsel__intval(evsel, &sample, "flags");
@@ -123,7 +123,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
if (flags != tp_flags) {
pr_debug("%s: Expected flags=%#x, got %#x\n",
__func__, flags, tp_flags);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
goto out_ok;
@@ -136,13 +136,13 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
if (++nr_polls > 5) {
pr_debug("%s: no events!\n", __func__);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
}
out_ok:
ret = TEST_OK;
-out_delete_evlist:
- evlist__delete(evlist);
+out_put_evlist:
+ evlist__put(evlist);
out:
return ret;
}
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 05c3e899b425..19dc7b7475d2 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -2568,7 +2568,7 @@ static int test_event(const struct evlist_test *e)
ret = e->check(evlist);
}
parse_events_error__exit(&err);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
@@ -2594,7 +2594,7 @@ static int test_event_fake_pmu(const char *str)
}
parse_events_error__exit(&err);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 7c7f489a5eb0..3f0ec839c056 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -84,7 +84,7 @@ static int __compute_metric(const char *name, struct value *vals,
cpus = perf_cpu_map__new("0");
if (!cpus) {
- evlist__delete(evlist);
+ evlist__put(evlist);
return -ENOMEM;
}
@@ -113,7 +113,7 @@ static int __compute_metric(const char *name, struct value *vals,
/* ... cleanup. */
evlist__free_stats(evlist);
perf_cpu_map__put(cpus);
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 50e68b7d43aa..d5a8d065809e 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -49,7 +49,7 @@ static int process_events(union perf_event **events, size_t count)
for (i = 0; i < count && !err; i++)
err = process_event(&evlist, events[i]);
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index ad44cc68820b..f95752b2ed1c 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -105,7 +105,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
err = evlist__create_maps(evlist, &opts.target);
if (err < 0) {
pr_debug("Not enough memory to create thread/cpu maps\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
/*
@@ -117,7 +117,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
if (err < 0) {
pr_debug("Couldn't run the workload!\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
/*
@@ -134,7 +134,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
pr_debug("sched__get_first_possible_cpu: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
evlist__cancel_workload(evlist);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
cpu = err;
@@ -146,7 +146,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
pr_debug("sched_setaffinity: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
evlist__cancel_workload(evlist);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
/*
@@ -158,7 +158,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
pr_debug("perf_evlist__open: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
evlist__cancel_workload(evlist);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
/*
@@ -171,7 +171,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
pr_debug("evlist__mmap: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
evlist__cancel_workload(evlist);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
/*
@@ -209,7 +209,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
if (verbose > 0)
perf_event__fprintf(event, NULL, stderr);
pr_debug("Couldn't parse sample\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (verbose > 0) {
@@ -350,9 +350,9 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
++errs;
}
-out_delete_evlist:
+out_put_evlist:
CPU_FREE(cpu_mask);
- evlist__delete(evlist);
+ evlist__put(evlist);
out:
perf_sample__exit(&sample);
if (err == -EACCES)
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index cca41bd37ae3..d3538fa20af3 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -201,7 +201,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
err = TEST_OK;
out_err:
- evlist__delete(evlist);
+ evlist__put(evlist);
perf_cpu_map__put(cpus);
perf_thread_map__put(threads);
return err;
diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c
index fca4a86452df..8d19b1bfecbc 100644
--- a/tools/perf/tests/pfm.c
+++ b/tools/perf/tests/pfm.c
@@ -80,7 +80,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused,
evlist__nr_groups(evlist),
0);
- evlist__delete(evlist);
+ evlist__put(evlist);
}
return 0;
}
@@ -165,7 +165,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused,
evlist__nr_groups(evlist),
table[i].nr_groups);
- evlist__delete(evlist);
+ evlist__put(evlist);
}
return 0;
}
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index a99716862168..236bbbad5773 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -797,7 +797,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error)
/*warn_if_reordered=*/true, /*fake_tp=*/false);
free(dup);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
@@ -844,7 +844,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
cpus = perf_cpu_map__new("0");
if (!cpus) {
- evlist__delete(evlist);
+ evlist__put(evlist);
return -ENOMEM;
}
@@ -899,7 +899,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
/* ... cleanup. */
evlist__free_stats(evlist);
perf_cpu_map__put(cpus);
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index 0ebf2d7b2cb4..3d931c1f99dd 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -287,7 +287,7 @@ static int test__pmu_usr_chgs(struct test_suite *test __maybe_unused, int subtes
ret = TEST_OK;
err_out:
parse_events_terms__exit(&terms);
- evlist__delete(evlist);
+ evlist__put(evlist);
test_pmu_put(dir, pmu);
return ret;
}
@@ -339,7 +339,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest
ret = TEST_OK;
err_out:
parse_events_error__exit(&err);
- evlist__delete(evlist);
+ evlist__put(evlist);
test_pmu_put(dir, pmu);
return ret;
}
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index b6e46975379c..bb6b62cf51d1 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -59,7 +59,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
evsel = evsel__new(&attr);
if (evsel == NULL) {
pr_debug("evsel__new\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__add(evlist, evsel);
@@ -68,7 +68,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
if (!cpus || !threads) {
err = -ENOMEM;
pr_debug("Not enough memory to create thread/cpu maps\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
perf_evlist__set_maps(&evlist->core, cpus, threads);
@@ -80,14 +80,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
str_error_r(errno, sbuf, sizeof(sbuf)),
knob, (u64)attr.sample_freq);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
err = evlist__mmap(evlist, 128);
if (err < 0) {
pr_debug("failed to mmap event: %d (%s)\n", errno,
str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__enable(evlist);
@@ -113,7 +113,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
if (err < 0) {
pr_debug("Error during parse sample\n");
perf_sample__exit(&sample);
- goto out_delete_evlist;
+ goto out_put_evlist;
}
total_periods += sample.period;
@@ -131,10 +131,10 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
err = -1;
}
-out_delete_evlist:
+out_put_evlist:
perf_cpu_map__put(cpus);
perf_thread_map__put(threads);
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index 72a8289e846d..306151c83af8 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -579,7 +579,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub
out:
if (evlist) {
evlist__disable(evlist);
- evlist__delete(evlist);
+ evlist__put(evlist);
}
perf_cpu_map__put(cpus);
perf_thread_map__put(threads);
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index 4053ff2813bb..a46650b10689 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -74,7 +74,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
if (!cpus || !threads) {
err = -ENOMEM;
pr_debug("Not enough memory to create thread/cpu maps\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
perf_evlist__set_maps(&evlist->core, cpus, threads);
@@ -82,7 +82,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
if (err < 0) {
pr_debug("Couldn't run the workload!\n");
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evsel = evlist__first(evlist);
@@ -101,14 +101,14 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
if (err < 0) {
pr_debug("Couldn't open the evlist: %s\n",
str_error_r(-err, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (evlist__mmap(evlist, 128) < 0) {
pr_debug("failed to mmap events: %d (%s)\n", errno,
str_error_r(errno, sbuf, sizeof(sbuf)));
err = -1;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist__start_workload(evlist);
@@ -133,7 +133,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
if (retry_count++ > 1000) {
pr_debug("Failed after retrying 1000 times\n");
err = -1;
- goto out_delete_evlist;
+ goto out_put_evlist;
}
goto retry;
@@ -144,10 +144,10 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
err = -1;
}
-out_delete_evlist:
+out_put_evlist:
perf_cpu_map__put(cpus);
perf_thread_map__put(threads);
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c
index 1e900ef92e37..e78ff9dcea97 100644
--- a/tools/perf/tests/tool_pmu.c
+++ b/tools/perf/tests/tool_pmu.c
@@ -67,7 +67,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu)
out:
parse_events_error__exit(&err);
- evlist__delete(evlist);
+ evlist__put(evlist);
return ret;
}
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index f54502ebef4b..4ecf5d750313 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -57,7 +57,7 @@ static int session_write_header(char *path)
!perf_session__write_header(session, session->evlist,
perf_data__fd(&data), true));
- evlist__delete(session->evlist);
+ evlist__put(session->evlist);
perf_session__delete(session);
return 0;
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 1b5664d1481f..652a45aac828 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -520,8 +520,8 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
cgrp_event_expanded = true;
out_err:
- evlist__delete(orig_list);
- evlist__delete(tmp_list);
+ evlist__put(orig_list);
+ evlist__put(tmp_list);
metricgroup__rblist_exit(&orig_metric_events);
release_cgroup_list();
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 3b8f2df823a9..a85ae53db7c5 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -1363,7 +1363,7 @@ static void cleanup_events(struct perf_session *session)
zfree(&evsel->priv);
}
- evlist__delete(evlist);
+ evlist__put(evlist);
session->evlist = NULL;
}
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 35d65fe50e06..b5a7895debf5 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -75,7 +75,7 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
#define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y)
-void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
+static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
struct perf_thread_map *threads)
{
perf_evlist__init(&evlist->core);
@@ -88,6 +88,7 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
evlist->nr_br_cntr = -1;
metricgroup__rblist_init(&evlist->metric_events);
INIT_LIST_HEAD(&evlist->deferred_samples);
+ refcount_set(&evlist->refcnt, 1);
}
struct evlist *evlist__new(void)
@@ -139,7 +140,7 @@ struct evlist *evlist__new_default(const struct target *target, bool sample_call
return evlist;
out_err:
- evlist__delete(evlist);
+ evlist__put(evlist);
return NULL;
}
@@ -148,13 +149,19 @@ struct evlist *evlist__new_dummy(void)
struct evlist *evlist = evlist__new();
if (evlist && evlist__add_dummy(evlist)) {
- evlist__delete(evlist);
+ evlist__put(evlist);
evlist = NULL;
}
return evlist;
}
+struct evlist *evlist__get(struct evlist *evlist)
+{
+ refcount_inc(&evlist->refcnt);
+ return evlist;
+}
+
/**
* evlist__set_id_pos - set the positions of event ids.
* @evlist: selected event list
@@ -193,7 +200,7 @@ static void evlist__purge(struct evlist *evlist)
evlist->core.nr_entries = 0;
}
-void evlist__exit(struct evlist *evlist)
+static void evlist__exit(struct evlist *evlist)
{
metricgroup__rblist_exit(&evlist->metric_events);
event_enable_timer__exit(&evlist->eet);
@@ -202,11 +209,14 @@ void evlist__exit(struct evlist *evlist)
perf_evlist__exit(&evlist->core);
}
-void evlist__delete(struct evlist *evlist)
+void evlist__put(struct evlist *evlist)
{
if (evlist == NULL)
return;
+ if (!refcount_dec_and_test(&evlist->refcnt))
+ return;
+
evlist__free_stats(evlist);
evlist__munmap(evlist);
evlist__close(evlist);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index e54761c670b6..a9820a6aad5b 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -61,6 +61,7 @@ struct event_enable_timer;
struct evlist {
struct perf_evlist core;
+ refcount_t refcnt;
bool enabled;
bool no_affinity;
int id_pos;
@@ -109,10 +110,8 @@ struct evsel_str_handler {
struct evlist *evlist__new(void);
struct evlist *evlist__new_default(const struct target *target, bool sample_callchains);
struct evlist *evlist__new_dummy(void);
-void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
- struct perf_thread_map *threads);
-void evlist__exit(struct evlist *evlist);
-void evlist__delete(struct evlist *evlist);
+struct evlist *evlist__get(struct evlist *evlist);
+void evlist__put(struct evlist *evlist);
void evlist__add(struct evlist *evlist, struct evsel *entry);
void evlist__remove(struct evlist *evlist, struct evsel *evsel);
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 644769e92708..cf54bbbc8ddc 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -450,7 +450,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const
ret = parse_event(tmp, id) ? 0 : 1;
}
out:
- evlist__delete(tmp);
+ evlist__put(tmp);
return ret;
}
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f30e48eb3fc3..f9887d2fc8ed 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -4909,12 +4909,12 @@ int perf_session__read_header(struct perf_session *session)
evsel = evsel__new(&f_attr.attr);
if (evsel == NULL)
- goto out_delete_evlist;
+ goto out_put_evlist;
evsel->needs_swap = header->needs_swap;
/*
* Do it before so that if perf_evsel__alloc_id fails, this
- * entry gets purged too at evlist__delete().
+ * entry gets purged too at evlist__put().
*/
evlist__add(session->evlist, evsel);
@@ -4925,7 +4925,7 @@ int perf_session__read_header(struct perf_session *session)
* hattr->ids threads.
*/
if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
- goto out_delete_evlist;
+ goto out_put_evlist;
lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -4944,7 +4944,7 @@ int perf_session__read_header(struct perf_session *session)
perf_file_section__process);
if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
- goto out_delete_evlist;
+ goto out_put_evlist;
#else
perf_header__process_sections(header, fd, NULL, perf_file_section__process);
#endif
@@ -4953,8 +4953,8 @@ int perf_session__read_header(struct perf_session *session)
out_errno:
return -errno;
-out_delete_evlist:
- evlist__delete(session->evlist);
+out_put_evlist:
+ evlist__put(session->evlist);
session->evlist = NULL;
return -ENOMEM;
}
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 4db9578efd81..191ec2d8a250 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -214,7 +214,7 @@ static void metric__free(struct metric *m)
zfree(&m->metric_refs);
expr__ctx_free(m->pctx);
zfree(&m->modifier);
- evlist__delete(m->evlist);
+ evlist__put(m->evlist);
free(m);
}
@@ -1335,7 +1335,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
parsed_evlist = NULL;
err_out:
parse_events_error__exit(&parse_error);
- evlist__delete(parsed_evlist);
+ evlist__put(parsed_evlist);
strbuf_release(&events);
return ret;
}
@@ -1546,7 +1546,7 @@ static int parse_groups(struct evlist *perf_evlist,
if (combined_evlist) {
evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
- evlist__delete(combined_evlist);
+ evlist__put(combined_evlist);
}
list_for_each_entry(m, &metric_list, nd) {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 1497e1f2a08c..f0809be63ad8 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -2316,7 +2316,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte
/*
* There are 2 users - builtin-record and builtin-test objects.
- * Both call evlist__delete in case of error, so we dont
+ * Both call evlist__put in case of error, so we dont
* need to bother.
*/
return ret;
@@ -2519,7 +2519,7 @@ int parse_events_option_new_evlist(const struct option *opt, const char *str, in
}
ret = parse_events_option(opt, str, unset);
if (ret) {
- evlist__delete(*args->evlistp);
+ evlist__put(*args->evlistp);
*args->evlistp = NULL;
}
diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
index e1904a330b28..f61c4ec52827 100644
--- a/tools/perf/util/perf_api_probe.c
+++ b/tools/perf/util/perf_api_probe.c
@@ -57,7 +57,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const cha
err = 0;
out_delete:
- evlist__delete(evlist);
+ evlist__put(evlist);
return err;
}
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 1e6c99efff90..aeecdb497fac 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1272,7 +1272,7 @@ static int pyrf_evsel__setup_types(void)
struct pyrf_evlist {
PyObject_HEAD
- struct evlist evlist;
+ struct evlist *evlist;
};
static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
@@ -1285,15 +1285,22 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
return -1;
+ evlist__put(pevlist->evlist);
+ pevlist->evlist = evlist__new();
+ if (!pevlist->evlist) {
+ PyErr_NoMemory();
+ return -1;
+ }
threads = ((struct pyrf_thread_map *)pthreads)->threads;
cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
- evlist__init(&pevlist->evlist, cpus, threads);
+ perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads);
+
return 0;
}
static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
{
- evlist__exit(&pevlist->evlist);
+ evlist__put(pevlist->evlist);
Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
}
@@ -1302,7 +1309,7 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist)
struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
if (pcpu_map)
- pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus);
+ pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus);
return (PyObject *)pcpu_map;
}
@@ -1315,7 +1322,7 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
if (!list)
return NULL;
- for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
+ for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node;
node = rb_next(node)) {
struct metric_event *me = container_of(node, struct metric_event, nd);
struct list_head *pos;
@@ -1421,7 +1428,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread))
return NULL;
- for (node = rb_first_cached(&pevlist->evlist.metric_events.entries);
+ for (node = rb_first_cached(&pevlist->evlist->metric_events.entries);
mexp == NULL && node;
node = rb_next(node)) {
struct metric_event *me = container_of(node, struct metric_event, nd);
@@ -1437,7 +1444,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
if (e->metric_events[0] == NULL)
continue;
- evlist__for_each_entry(&pevlist->evlist, pos2) {
+ evlist__for_each_entry(pevlist->evlist, pos2) {
if (pos2->metric_leader != e->metric_events[0])
continue;
cpu_idx = perf_cpu_map__idx(pos2->core.cpus,
@@ -1482,7 +1489,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
PyObject *args, PyObject *kwargs)
{
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
static char *kwlist[] = { "pages", "overwrite", NULL };
int pages = 128, overwrite = false;
@@ -1502,7 +1509,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
PyObject *args, PyObject *kwargs)
{
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
static char *kwlist[] = { "timeout", NULL };
int timeout = -1, n;
@@ -1522,7 +1529,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
PyObject *args __maybe_unused,
PyObject *kwargs __maybe_unused)
{
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
PyObject *list = PyList_New(0);
int i;
@@ -1551,7 +1558,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
PyObject *args,
PyObject *kwargs __maybe_unused)
{
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
PyObject *pevsel;
struct evsel *evsel;
@@ -1583,7 +1590,7 @@ static struct mmap *get_md(struct evlist *evlist, int cpu)
static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
PyObject *args, PyObject *kwargs)
{
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
union perf_event *event;
int sample_id_all = 1, cpu;
static char *kwlist[] = { "cpu", "sample_id_all", NULL };
@@ -1640,7 +1647,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
PyObject *args, PyObject *kwargs)
{
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
if (evlist__open(evlist) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
@@ -1653,7 +1660,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist)
{
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
evlist__close(evlist);
@@ -1679,7 +1686,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
.no_buffering = true,
.no_inherit = true,
};
- struct evlist *evlist = &pevlist->evlist;
+ struct evlist *evlist = pevlist->evlist;
evlist__config(evlist, &opts, &callchain_param);
Py_INCREF(Py_None);
@@ -1688,14 +1695,14 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist)
{
- evlist__disable(&pevlist->evlist);
+ evlist__disable(pevlist->evlist);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist)
{
- evlist__enable(&pevlist->evlist);
+ evlist__enable(pevlist->evlist);
Py_INCREF(Py_None);
return Py_None;
}
@@ -1786,7 +1793,23 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj)
{
struct pyrf_evlist *pevlist = (void *)obj;
- return pevlist->evlist.core.nr_entries;
+ return pevlist->evlist->core.nr_entries;
+}
+
+static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
+{
+ struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
+
+ if (!pevsel)
+ return NULL;
+
+ memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
+ evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
+
+ evsel__clone(&pevsel->evsel, evsel);
+ if (evsel__is_group_leader(evsel))
+ evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
+ return (PyObject *)pevsel;
}
static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
@@ -1794,17 +1817,16 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
struct pyrf_evlist *pevlist = (void *)obj;
struct evsel *pos;
- if (i >= pevlist->evlist.core.nr_entries) {
+ if (i >= pevlist->evlist->core.nr_entries) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
return NULL;
}
- evlist__for_each_entry(&pevlist->evlist, pos) {
+ evlist__for_each_entry(pevlist->evlist, pos) {
if (i-- == 0)
break;
}
-
- return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
+ return pyrf_evsel__from_evsel(pos);
}
static PyObject *pyrf_evlist__str(PyObject *self)
@@ -1816,7 +1838,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
PyObject *result;
strbuf_addstr(&sb, "evlist([");
- evlist__for_each_entry(&pevlist->evlist, pos) {
+ evlist__for_each_entry(pevlist->evlist, pos) {
if (!first)
strbuf_addch(&sb, ',');
if (!pos->pmu)
@@ -1852,9 +1874,19 @@ static PyTypeObject pyrf_evlist__type = {
.tp_str = pyrf_evlist__str,
};
+static PyObject *pyrf_evlist__new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ struct pyrf_evlist *pevlist;
+
+ pevlist = (struct pyrf_evlist *)PyType_GenericNew(type, args, kwargs);
+ if (pevlist)
+ pevlist->evlist = NULL;
+ return (PyObject *)pevlist;
+}
+
static int pyrf_evlist__setup_types(void)
{
- pyrf_evlist__type.tp_new = PyType_GenericNew;
+ pyrf_evlist__type.tp_new = pyrf_evlist__new;
return PyType_Ready(&pyrf_evlist__type);
}
@@ -1957,157 +1989,74 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
return PyLong_FromLong(tp_pmu__id(sys, name));
}
-static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
-{
- struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
-
- if (!pevsel)
- return NULL;
-
- memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
- evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
-
- evsel__clone(&pevsel->evsel, evsel);
- if (evsel__is_group_leader(evsel))
- evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
- return (PyObject *)pevsel;
-}
-
-static int evlist__pos(struct evlist *evlist, struct evsel *evsel)
-{
- struct evsel *pos;
- int idx = 0;
-
- evlist__for_each_entry(evlist, pos) {
- if (evsel == pos)
- return idx;
- idx++;
- }
- return -1;
-}
-
-static struct evsel *evlist__at(struct evlist *evlist, int idx)
-{
- struct evsel *pos;
- int idx2 = 0;
-
- evlist__for_each_entry(evlist, pos) {
- if (idx == idx2)
- return pos;
- idx2++;
- }
- return NULL;
-}
-
static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
{
struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
- struct evsel *pos;
- struct rb_node *node;
if (!pevlist)
return NULL;
- memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
- evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
- evlist__for_each_entry(evlist, pos) {
- struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
-
- evlist__add(&pevlist->evlist, &pevsel->evsel);
- }
- evlist__for_each_entry(&pevlist->evlist, pos) {
- struct evsel *leader = evsel__leader(pos);
-
- if (pos != leader) {
- int idx = evlist__pos(evlist, leader);
-
- if (idx >= 0)
- evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx));
- else if (leader == NULL)
- evsel__set_leader(pos, pos);
- }
-
- leader = pos->metric_leader;
-
- if (pos != leader) {
- int idx = evlist__pos(evlist, leader);
-
- if (idx >= 0)
- pos->metric_leader = evlist__at(&pevlist->evlist, idx);
- else if (leader == NULL)
- pos->metric_leader = pos;
- }
- }
- metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
- &pevlist->evlist.metric_events,
- &evlist->metric_events);
- for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
- node = rb_next(node)) {
- struct metric_event *me = container_of(node, struct metric_event, nd);
- struct list_head *mpos;
- int idx = evlist__pos(evlist, me->evsel);
-
- if (idx >= 0)
- me->evsel = evlist__at(&pevlist->evlist, idx);
- list_for_each(mpos, &me->head) {
- struct metric_expr *e = container_of(mpos, struct metric_expr, nd);
-
- for (int j = 0; e->metric_events[j]; j++) {
- idx = evlist__pos(evlist, e->metric_events[j]);
- if (idx >= 0)
- e->metric_events[j] = evlist__at(&pevlist->evlist, idx);
- }
- }
- }
+ pevlist->evlist = evlist__get(evlist);
return (PyObject *)pevlist;
}
static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
{
const char *input;
- struct evlist evlist = {};
+ struct evlist *evlist = evlist__new();
struct parse_events_error err;
PyObject *result;
PyObject *pcpus = NULL, *pthreads = NULL;
struct perf_cpu_map *cpus;
struct perf_thread_map *threads;
- if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
+ if (!evlist)
+ return PyErr_NoMemory();
+
+ if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads)) {
+ evlist__put(evlist);
return NULL;
+ }
threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
parse_events_error__init(&err);
- evlist__init(&evlist, cpus, threads);
- if (parse_events(&evlist, input, &err)) {
+ perf_evlist__set_maps(&evlist->core, cpus, threads);
+ if (parse_events(evlist, input, &err)) {
parse_events_error__print(&err, input);
PyErr_SetFromErrno(PyExc_OSError);
+ evlist__put(evlist);
return NULL;
}
- result = pyrf_evlist__from_evlist(&evlist);
- evlist__exit(&evlist);
+ result = pyrf_evlist__from_evlist(evlist);
+ evlist__put(evlist);
return result;
}
static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
{
const char *input, *pmu = NULL;
- struct evlist evlist = {};
+ struct evlist *evlist = evlist__new();
PyObject *result;
PyObject *pcpus = NULL, *pthreads = NULL;
struct perf_cpu_map *cpus;
struct perf_thread_map *threads;
int ret;
- if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads))
+ if (!evlist)
+ return PyErr_NoMemory();
+
+ if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads)) {
+ evlist__put(evlist);
return NULL;
+ }
threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
- evlist__init(&evlist, cpus, threads);
- ret = metricgroup__parse_groups(&evlist, pmu ?: "all", input,
+ perf_evlist__set_maps(&evlist->core, cpus, threads);
+ ret = metricgroup__parse_groups(evlist, pmu ?: "all", input,
/*metric_no_group=*/ false,
/*metric_no_merge=*/ false,
/*metric_no_threshold=*/ true,
@@ -2115,12 +2064,13 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
/*system_wide=*/true,
/*hardware_aware_grouping=*/ false);
if (ret) {
+ evlist__put(evlist);
errno = -ret;
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
- result = pyrf_evlist__from_evlist(&evlist);
- evlist__exit(&evlist);
+ result = pyrf_evlist__from_evlist(evlist);
+ evlist__put(evlist);
return result;
}
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index e867de8ddaaa..8a5fc7d5e43c 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -264,7 +264,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str)
ret = true;
out_delete:
- evlist__delete(temp_evlist);
+ evlist__put(temp_evlist);
return ret;
}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index fe0de2a0277f..1ac6cd43c38b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -264,7 +264,7 @@ void perf_session__delete(struct perf_session *session)
machines__exit(&session->machines);
if (session->data) {
if (perf_data__is_read(session->data))
- evlist__delete(session->evlist);
+ evlist__put(session->evlist);
perf_data__close(session->data);
}
#ifdef HAVE_LIBTRACEEVENT
diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
index 388846f17bc1..b84a5463e039 100644
--- a/tools/perf/util/sideband_evlist.c
+++ b/tools/perf/util/sideband_evlist.c
@@ -102,7 +102,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
return 0;
if (evlist__create_maps(evlist, target))
- goto out_delete_evlist;
+ goto out_put_evlist;
if (evlist->core.nr_entries > 1) {
bool can_sample_identifier = perf_can_sample_identifier();
@@ -116,25 +116,25 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
evlist__for_each_entry(evlist, counter) {
if (evsel__open(counter, evlist->core.user_requested_cpus,
evlist->core.threads) < 0)
- goto out_delete_evlist;
+ goto out_put_evlist;
}
if (evlist__mmap(evlist, UINT_MAX))
- goto out_delete_evlist;
+ goto out_put_evlist;
evlist__for_each_entry(evlist, counter) {
if (evsel__enable(counter))
- goto out_delete_evlist;
+ goto out_put_evlist;
}
evlist->thread.done = 0;
if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
- goto out_delete_evlist;
+ goto out_put_evlist;
return 0;
-out_delete_evlist:
- evlist__delete(evlist);
+out_put_evlist:
+ evlist__put(evlist);
evlist = NULL;
return -1;
}
@@ -145,5 +145,5 @@ void evlist__stop_sb_thread(struct evlist *evlist)
return;
evlist->thread.done = 1;
pthread_join(evlist->thread.th, NULL);
- evlist__delete(evlist);
+ evlist__put(evlist);
}
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 15/59] perf python: Add python session abstraction wrapping perf's session
From: Ian Rogers @ 2026-04-25 22:49 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Sessions are necessary to be able to use perf.data files within a
tool. Add a wrapper python type that incorporates the tool. Allow a
sample callback to be passed when creating the session. When
process_events is run this callback will be called, if supplied, for
sample events.
An example use looks like:
```
$ perf record -e cycles,instructions -a sleep 3
$ PYTHONPATH=..../perf/python python3
Python 3.13.7 (main, Aug 20 2025, 22:17:40) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import perf
>>> count=0
... def handle_sample(x):
... global count
... if count < 3:
... print(dir(x))
... count = count + 1
... perf.session(perf.data("perf.data"),sample=handle_sample).process_events()
...
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type']
```
Also, add the ability to get the thread associated with a session. For
threads, allow the comm string to be retrieved. This can be useful for
filtering threads. Connect up some of the standard event handling in
psession->tool to better support queries of the machine. Also connect
up the symbols.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2:
1. Fixed Potential Crash in pyrf_thread__comm : Used
thread__comm_str() to safely retrieve the command name, avoiding a
crash if thread__comm() returns NULL.
2. Fixed Double Free Risk: Zeroed out user_regs , intr_regs , and
callchain in the shallow copy of perf_sample to prevent Python from
attempting to free pointers it doesn't own.
3. Fixed Memory Leak & Exception Handling in Callback: Handled the
return value of PyObject_CallFunction() to avoid leaks, and checked
for failure to abort the loop and propagate Python exceptions
cleanly.
4. Enforced Type Safety: Used O! with &pyrf_data__type in
PyArg_ParseTupleAndKeywords to prevent bad casts from passing
arbitrary objects as perf.data.
5. Added Missing Build ID Handler: Registered
perf_event__process_build_id to allow correct symbol resolution.
6. Fixed Double Free Crash on Init Failure: Set session and pdata to
NULL on failure to prevent tp_dealloc from double-freeing them.
7. Preserved C-level Errors: Made pyrf_session__process_events return
the error code integer rather than always returning None .
---
v7:
- Fixed NULL comm handling.
- Avoided swallowing exceptions in module init.
- Fixed checkpatch warning for missing blank line.
---
tools/perf/util/python.c | 279 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 273 insertions(+), 6 deletions(-)
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index aa63c7ffe822..1af53480661f 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -9,8 +9,10 @@
#include <perf/mmap.h>
#include "callchain.h"
+#include "comm.h"
#include "counts.h"
#include "data.h"
+#include "debug.h"
#include "event.h"
#include "evlist.h"
#include "evsel.h"
@@ -20,8 +22,12 @@
#include "pmus.h"
#include "print_binary.h"
#include "record.h"
+#include "session.h"
#include "strbuf.h"
+#include "symbol.h"
+#include "thread.h"
#include "thread_map.h"
+#include "tool.h"
#include "tp_pmu.h"
#include "trace-event.h"
#include "util/sample.h"
@@ -2413,6 +2419,256 @@ static int pyrf_data__setup_types(void)
return PyType_Ready(&pyrf_data__type);
}
+struct pyrf_thread {
+ PyObject_HEAD
+
+ struct thread *thread;
+};
+
+static void pyrf_thread__delete(struct pyrf_thread *pthread)
+{
+ thread__put(pthread->thread);
+ Py_TYPE(pthread)->tp_free((PyObject *)pthread);
+}
+
+static PyObject *pyrf_thread__comm(PyObject *obj)
+{
+ struct pyrf_thread *pthread = (void *)obj;
+ const char *str = thread__comm_str(pthread->thread);
+
+ if (!str)
+ Py_RETURN_NONE;
+
+ return PyUnicode_FromString(str);
+}
+
+static PyMethodDef pyrf_thread__methods[] = {
+ {
+ .ml_name = "comm",
+ .ml_meth = (PyCFunction)pyrf_thread__comm,
+ .ml_flags = METH_NOARGS,
+ .ml_doc = PyDoc_STR("Comm(and) associated with this thread.")
+ },
+ { .ml_name = NULL, }
+};
+
+static const char pyrf_thread__doc[] = PyDoc_STR("perf thread object.");
+
+static PyTypeObject pyrf_thread__type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "perf.thread",
+ .tp_basicsize = sizeof(struct pyrf_thread),
+ .tp_dealloc = (destructor)pyrf_thread__delete,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ .tp_methods = pyrf_thread__methods,
+ .tp_doc = pyrf_thread__doc,
+};
+
+static int pyrf_thread__setup_types(void)
+{
+ return PyType_Ready(&pyrf_thread__type);
+}
+
+static PyObject *pyrf_thread__from_thread(struct thread *thread)
+{
+ struct pyrf_thread *pthread = PyObject_New(struct pyrf_thread, &pyrf_thread__type);
+
+ if (!pthread)
+ return NULL;
+
+ pthread->thread = thread__get(thread);
+ return (PyObject *)pthread;
+}
+
+struct pyrf_session {
+ PyObject_HEAD
+
+ struct perf_session *session;
+ struct perf_tool tool;
+ struct pyrf_data *pdata;
+ PyObject *sample;
+ PyObject *stat;
+};
+
+static int pyrf_session_tool__sample(const struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct evsel *evsel,
+ struct machine *machine __maybe_unused)
+{
+ struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool);
+ PyObject *pyevent = pyrf_event__new(event);
+ struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
+ PyObject *ret;
+
+ if (pyevent == NULL)
+ return -ENOMEM;
+
+ memcpy(&pevent->event, event, event->header.size);
+ if (evsel__parse_sample(evsel, &pevent->event, &pevent->sample) < 0) {
+ Py_DECREF(pyevent);
+ return -1;
+ }
+ /* Avoid shallow copy pointing to lazily allocated memory that would be double freed. */
+ pevent->sample.user_regs = NULL;
+ pevent->sample.intr_regs = NULL;
+ if (pevent->sample.merged_callchain)
+ pevent->sample.callchain = NULL;
+
+ ret = PyObject_CallFunction(psession->sample, "O", pyevent);
+ if (!ret) {
+ PyErr_Print();
+ Py_DECREF(pyevent);
+ return -1;
+ }
+ Py_DECREF(ret);
+ Py_DECREF(pyevent);
+ return 0;
+}
+
+static PyObject *pyrf_session__find_thread(struct pyrf_session *psession, PyObject *args)
+{
+ struct machine *machine;
+ struct thread *thread = NULL;
+ PyObject *result;
+ int pid;
+
+ if (!PyArg_ParseTuple(args, "i", &pid))
+ return NULL;
+
+ machine = &psession->session->machines.host;
+ thread = machine__find_thread(machine, pid, pid);
+
+ if (!thread) {
+ machine = perf_session__find_machine(psession->session, pid);
+ if (machine)
+ thread = machine__find_thread(machine, pid, pid);
+ }
+
+ if (!thread) {
+ PyErr_Format(PyExc_TypeError, "Failed to find thread %d", pid);
+ return NULL;
+ }
+ result = pyrf_thread__from_thread(thread);
+ thread__put(thread);
+ return result;
+}
+
+static int pyrf_session__init(struct pyrf_session *psession, PyObject *args, PyObject *kwargs)
+{
+ struct pyrf_data *pdata;
+ PyObject *sample = NULL;
+ static char *kwlist[] = { "data", "sample", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &pyrf_data__type, &pdata,
+ &sample))
+ return -1;
+
+ Py_INCREF(pdata);
+ psession->pdata = pdata;
+ perf_tool__init(&psession->tool, /*ordered_events=*/true);
+ psession->tool.ordering_requires_timestamps = true;
+
+ #define ADD_TOOL(name) \
+ do { \
+ if (name) { \
+ if (!PyCallable_Check(name)) { \
+ PyErr_SetString(PyExc_TypeError, #name " must be callable"); \
+ return -1; \
+ } \
+ psession->tool.name = pyrf_session_tool__##name; \
+ Py_INCREF(name); \
+ psession->name = name; \
+ } \
+ } while (0)
+
+ ADD_TOOL(sample);
+ #undef ADD_TOOL
+
+ psession->tool.comm = perf_event__process_comm;
+ psession->tool.mmap = perf_event__process_mmap;
+ psession->tool.mmap2 = perf_event__process_mmap2;
+ psession->tool.namespaces = perf_event__process_namespaces;
+ psession->tool.cgroup = perf_event__process_cgroup;
+ psession->tool.exit = perf_event__process_exit;
+ psession->tool.fork = perf_event__process_fork;
+ psession->tool.ksymbol = perf_event__process_ksymbol;
+ psession->tool.text_poke = perf_event__process_text_poke;
+ psession->tool.build_id = perf_event__process_build_id;
+ psession->session = perf_session__new(&pdata->data, &psession->tool);
+ if (IS_ERR(psession->session)) {
+ PyErr_Format(PyExc_IOError, "failed to create session: %ld",
+ PTR_ERR(psession->session));
+ psession->session = NULL;
+ Py_DECREF(pdata);
+ psession->pdata = NULL;
+ return -1;
+ }
+
+ if (symbol__init(perf_session__env(psession->session)) < 0) {
+ perf_session__delete(psession->session);
+ psession->session = NULL;
+ Py_DECREF(psession->pdata);
+ psession->pdata = NULL;
+ return -1;
+ }
+
+ if (perf_session__create_kernel_maps(psession->session) < 0)
+ pr_warning("Cannot read kernel map\n");
+
+ return 0;
+}
+
+static void pyrf_session__delete(struct pyrf_session *psession)
+{
+ Py_XDECREF(psession->pdata);
+ Py_XDECREF(psession->sample);
+ perf_session__delete(psession->session);
+ Py_TYPE(psession)->tp_free((PyObject *)psession);
+}
+
+static PyObject *pyrf_session__find_thread_events(struct pyrf_session *psession)
+{
+ int err = perf_session__process_events(psession->session);
+
+ return PyLong_FromLong(err);
+}
+
+static PyMethodDef pyrf_session__methods[] = {
+ {
+ .ml_name = "process_events",
+ .ml_meth = (PyCFunction)pyrf_session__find_thread_events,
+ .ml_flags = METH_NOARGS,
+ .ml_doc = PyDoc_STR("Iterate and process events.")
+ },
+ {
+ .ml_name = "find_thread",
+ .ml_meth = (PyCFunction)pyrf_session__find_thread,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = PyDoc_STR("Returns the thread associated with a pid.")
+ },
+ { .ml_name = NULL, }
+};
+
+static const char pyrf_session__doc[] = PyDoc_STR("perf session object.");
+
+static PyTypeObject pyrf_session__type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "perf.session",
+ .tp_basicsize = sizeof(struct pyrf_session),
+ .tp_dealloc = (destructor)pyrf_session__delete,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ .tp_methods = pyrf_session__methods,
+ .tp_doc = pyrf_session__doc,
+ .tp_init = (initproc)pyrf_session__init,
+};
+
+static int pyrf_session__setup_types(void)
+{
+ pyrf_session__type.tp_new = PyType_GenericNew;
+ return PyType_Ready(&pyrf_session__type);
+}
+
static PyMethodDef perf__methods[] = {
{
.ml_name = "metrics",
@@ -2467,8 +2723,10 @@ PyMODINIT_FUNC PyInit_perf(void)
};
PyObject *module = PyModule_Create(&moduledef);
- if (module == NULL ||
- pyrf_event__setup_types() < 0 ||
+ if (module == NULL)
+ return NULL;
+
+ if (pyrf_event__setup_types() < 0 ||
pyrf_evlist__setup_types() < 0 ||
pyrf_evsel__setup_types() < 0 ||
pyrf_thread_map__setup_types() < 0 ||
@@ -2476,8 +2734,12 @@ PyMODINIT_FUNC PyInit_perf(void)
pyrf_pmu_iterator__setup_types() < 0 ||
pyrf_pmu__setup_types() < 0 ||
pyrf_counts_values__setup_types() < 0 ||
- pyrf_data__setup_types() < 0)
- return module;
+ pyrf_data__setup_types() < 0 ||
+ pyrf_session__setup_types() < 0 ||
+ pyrf_thread__setup_types() < 0) {
+ Py_DECREF(module);
+ return NULL;
+ }
/* The page_size is placed in util object. */
page_size = sysconf(_SC_PAGE_SIZE);
@@ -2527,6 +2789,9 @@ PyMODINIT_FUNC PyInit_perf(void)
Py_INCREF(&pyrf_data__type);
PyModule_AddObject(module, "data", (PyObject *)&pyrf_data__type);
+ Py_INCREF(&pyrf_session__type);
+ PyModule_AddObject(module, "session", (PyObject *)&pyrf_session__type);
+
dict = PyModule_GetDict(module);
if (dict == NULL)
goto error;
@@ -2540,7 +2805,9 @@ PyMODINIT_FUNC PyInit_perf(void)
}
error:
- if (PyErr_Occurred())
- PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
+ if (PyErr_Occurred()) {
+ Py_XDECREF(module);
+ return NULL;
+ }
return module;
}
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 11/59] perf evsel: Add reference count
From: Ian Rogers @ 2026-04-25 22:49 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
As with evlist this a no-op for most of the perf tool. The reference
count is set to 1 at allocation, the put will see the 1, decrement it
and perform the delete. The purpose for adding the reference count is
for the python code. Prior to this change the python code would clone
evsels, but this has issues if events are opened, etc. leading to
assertion failures. With a reference count the same evsel can be used
and the reference count incremented for the python usage. To not
change the python evsel API getset functions are added for the evsel
members, no set function is provided for size as it doesn't make sense
to alter this.
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2:
1. Fixed Potential Crash in pyrf_event__new : Initialized
pevent->evsel = NULL; to avoid garbage pointer dereference if
evlist__event2evsel() fails in read_on_cpu .
2. Fixed Memory Leak in pyrf_evsel__init : Added
evsel__put(pevsel->evsel) before overwriting it to handle repeated
__init__ calls.
3. Fixed Exception Contract: Added PyErr_NoMemory() when evsel__new()
fails in pyrf_evsel__init .
4. Fixed NULL Pointer Dereference on Property Access: Added a custom
tp_getattro ( pyrf_evsel__getattro ) to pyrf_evsel__type to check
if pevsel->evsel is NULL and raise a ValueError if so, covering all
property accesses.
5. Fixed Reference Count in pyrf_evlist__add : Added evsel__get(evsel)
when adding to the evlist .
6. Fixed Reference Count in pyrf_evlist__read_on_cpu : Added
evsel__get(evsel) when assigning to pevent->evsel .
v7:
- Added pyrf_evsel__new to zero-initialize pevsel->evsel to fix
crash on re-initialization.
---
tools/perf/builtin-trace.c | 12 +-
tools/perf/tests/evsel-tp-sched.c | 4 +-
tools/perf/tests/openat-syscall-all-cpus.c | 6 +-
tools/perf/tests/openat-syscall.c | 6 +-
tools/perf/util/bpf_counter_cgroup.c | 2 +-
tools/perf/util/cgroup.c | 2 +-
tools/perf/util/evlist.c | 2 +-
tools/perf/util/evsel.c | 26 ++-
tools/perf/util/evsel.h | 11 +-
tools/perf/util/parse-events.y | 2 +-
tools/perf/util/pfm.c | 2 +-
tools/perf/util/print-events.c | 2 +-
tools/perf/util/python.c | 243 +++++++++++++++++----
tools/perf/util/session.c | 1 +
14 files changed, 248 insertions(+), 73 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index da703d762433..6ea935c13538 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -448,10 +448,10 @@ static int evsel__init_tp_ptr_field(struct evsel *evsel, struct tp_field *field,
({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
-static void evsel__delete_priv(struct evsel *evsel)
+static void evsel__put_and_free_priv(struct evsel *evsel)
{
zfree(&evsel->priv);
- evsel__delete(evsel);
+ evsel__put(evsel);
}
static int evsel__init_syscall_tp(struct evsel *evsel)
@@ -531,7 +531,7 @@ static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *
return evsel;
out_delete:
- evsel__delete_priv(evsel);
+ evsel__put_and_free_priv(evsel);
return NULL;
}
@@ -3584,7 +3584,7 @@ static bool evlist__add_vfs_getname(struct evlist *evlist)
list_del_init(&evsel->core.node);
evsel->evlist = NULL;
- evsel__delete(evsel);
+ evsel__put(evsel);
}
return found;
@@ -3698,9 +3698,9 @@ static int trace__add_syscall_newtp(struct trace *trace)
return ret;
out_delete_sys_exit:
- evsel__delete_priv(sys_exit);
+ evsel__put_and_free_priv(sys_exit);
out_delete_sys_enter:
- evsel__delete_priv(sys_enter);
+ evsel__put_and_free_priv(sys_enter);
goto out;
}
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 226196fb9677..9e456f88a13a 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -64,7 +64,7 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse
if (evsel__test_field(evsel, "next_prio", 4, true))
ret = TEST_FAIL;
- evsel__delete(evsel);
+ evsel__put(evsel);
evsel = evsel__newtp("sched", "sched_wakeup");
@@ -85,7 +85,7 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse
if (evsel__test_field(evsel, "target_cpu", 4, true))
ret = TEST_FAIL;
- evsel__delete(evsel);
+ evsel__put(evsel);
return ret;
}
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c
index 0be43f8db3bd..cc63df2b3bc5 100644
--- a/tools/perf/tests/openat-syscall-all-cpus.c
+++ b/tools/perf/tests/openat-syscall-all-cpus.c
@@ -59,7 +59,7 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb
"tweak /proc/sys/kernel/perf_event_paranoid?\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
err = TEST_SKIP;
- goto out_evsel_delete;
+ goto out_evsel_put;
}
perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
@@ -116,8 +116,8 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb
evsel__free_counts(evsel);
out_close_fd:
perf_evsel__close_fd(&evsel->core);
-out_evsel_delete:
- evsel__delete(evsel);
+out_evsel_put:
+ evsel__put(evsel);
out_cpu_map_delete:
perf_cpu_map__put(cpus);
out_thread_map_delete:
diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c
index b54cbe5f1808..9f16f0dd3a29 100644
--- a/tools/perf/tests/openat-syscall.c
+++ b/tools/perf/tests/openat-syscall.c
@@ -42,7 +42,7 @@ static int test__openat_syscall_event(struct test_suite *test __maybe_unused,
"tweak /proc/sys/kernel/perf_event_paranoid?\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
err = TEST_SKIP;
- goto out_evsel_delete;
+ goto out_evsel_put;
}
for (i = 0; i < nr_openat_calls; ++i) {
@@ -64,8 +64,8 @@ static int test__openat_syscall_event(struct test_suite *test __maybe_unused,
err = TEST_OK;
out_close_fd:
perf_evsel__close_fd(&evsel->core);
-out_evsel_delete:
- evsel__delete(evsel);
+out_evsel_put:
+ evsel__put(evsel);
out_thread_map_delete:
perf_thread_map__put(threads);
return err;
diff --git a/tools/perf/util/bpf_counter_cgroup.c b/tools/perf/util/bpf_counter_cgroup.c
index 519fee3dc3d0..339df94ef438 100644
--- a/tools/perf/util/bpf_counter_cgroup.c
+++ b/tools/perf/util/bpf_counter_cgroup.c
@@ -316,7 +316,7 @@ static int bperf_cgrp__destroy(struct evsel *evsel)
return 0;
bperf_cgroup_bpf__destroy(skel);
- evsel__delete(cgrp_switch); // it'll destroy on_switch progs too
+ evsel__put(cgrp_switch); // it'll destroy on_switch progs too
return 0;
}
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 652a45aac828..914744724467 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -469,7 +469,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
/* copy the list and set to the new cgroup. */
evlist__for_each_entry(orig_list, pos) {
- struct evsel *evsel = evsel__clone(/*dest=*/NULL, pos);
+ struct evsel *evsel = evsel__clone(pos);
if (evsel == NULL)
goto out_err;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index b5a7895debf5..a362f338f104 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -194,7 +194,7 @@ static void evlist__purge(struct evlist *evlist)
evlist__for_each_entry_safe(evlist, n, pos) {
list_del_init(&pos->core.node);
pos->evlist = NULL;
- evsel__delete(pos);
+ evsel__put(pos);
}
evlist->core.nr_entries = 0;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e03727d395e9..a54aae079c22 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -388,10 +388,11 @@ bool evsel__is_function_event(struct evsel *evsel)
#undef FUNCTION_EVENT
}
-void evsel__init(struct evsel *evsel,
+static void evsel__init(struct evsel *evsel,
struct perf_event_attr *attr, int idx)
{
perf_evsel__init(&evsel->core, attr, idx);
+ refcount_set(&evsel->refcnt, 1);
evsel->tracking = !idx;
evsel->unit = strdup("");
evsel->scale = 1.0;
@@ -472,7 +473,7 @@ static int evsel__copy_config_terms(struct evsel *dst, struct evsel *src)
* The assumption is that @orig is not configured nor opened yet.
* So we only care about the attributes that can be set while it's parsed.
*/
-struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
+struct evsel *evsel__clone(struct evsel *orig)
{
struct evsel *evsel;
@@ -485,11 +486,7 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
if (orig->bpf_obj)
return NULL;
- if (dest)
- evsel = dest;
- else
- evsel = evsel__new(&orig->core.attr);
-
+ evsel = evsel__new(&orig->core.attr);
if (evsel == NULL)
return NULL;
@@ -574,7 +571,7 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
return evsel;
out_err:
- evsel__delete(evsel);
+ evsel__put(evsel);
return NULL;
}
@@ -633,6 +630,12 @@ struct evsel *evsel__newtp_idx(const char *sys, const char *name, int idx, bool
return ERR_PTR(err);
}
+struct evsel *evsel__get(struct evsel *evsel)
+{
+ refcount_inc(&evsel->refcnt);
+ return evsel;
+}
+
#ifdef HAVE_LIBTRACEEVENT
struct tep_event *evsel__tp_format(struct evsel *evsel)
{
@@ -1857,7 +1860,7 @@ void evsel__set_priv_destructor(void (*destructor)(void *priv))
evsel__priv_destructor = destructor;
}
-void evsel__exit(struct evsel *evsel)
+static void evsel__exit(struct evsel *evsel)
{
assert(list_empty(&evsel->core.node));
assert(evsel->evlist == NULL);
@@ -1892,11 +1895,14 @@ void evsel__exit(struct evsel *evsel)
xyarray__delete(evsel->start_times);
}
-void evsel__delete(struct evsel *evsel)
+void evsel__put(struct evsel *evsel)
{
if (!evsel)
return;
+ if (!refcount_dec_and_test(&evsel->refcnt))
+ return;
+
evsel__exit(evsel);
free(evsel);
}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b099c8e5dd86..35b1bbca9036 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -6,6 +6,7 @@
#include <linux/list.h>
#include <linux/perf_event.h>
+#include <linux/refcount.h>
#include <linux/types.h>
#include <sys/types.h>
@@ -47,6 +48,7 @@ typedef int (evsel__sb_cb_t)(union perf_event *event, void *data);
struct evsel {
struct perf_evsel core;
struct evlist *evlist;
+ refcount_t refcnt;
off_t id_offset;
int id_pos;
int is_pos;
@@ -262,7 +264,7 @@ static inline struct evsel *evsel__new(struct perf_event_attr *attr)
return evsel__new_idx(attr, 0);
}
-struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig);
+struct evsel *evsel__clone(struct evsel *orig);
int copy_config_terms(struct list_head *dst, struct list_head *src);
void free_config_terms(struct list_head *config_terms);
@@ -277,14 +279,13 @@ static inline struct evsel *evsel__newtp(const char *sys, const char *name)
return evsel__newtp_idx(sys, name, 0, true);
}
+struct evsel *evsel__get(struct evsel *evsel);
+void evsel__put(struct evsel *evsel);
+
#ifdef HAVE_LIBTRACEEVENT
struct tep_event *evsel__tp_format(struct evsel *evsel);
#endif
-void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx);
-void evsel__exit(struct evsel *evsel);
-void evsel__delete(struct evsel *evsel);
-
void evsel__set_priv_destructor(void (*destructor)(void *priv));
struct callchain_param;
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index c194de5ec1ec..b531b1f0ceb3 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -47,7 +47,7 @@ static void free_list_evsel(struct list_head* list_evsel)
list_for_each_entry_safe(evsel, tmp, list_evsel, core.node) {
list_del_init(&evsel->core.node);
- evsel__delete(evsel);
+ evsel__put(evsel);
}
free(list_evsel);
}
diff --git a/tools/perf/util/pfm.c b/tools/perf/util/pfm.c
index d9043f4afbe7..5f53c2f68a96 100644
--- a/tools/perf/util/pfm.c
+++ b/tools/perf/util/pfm.c
@@ -159,7 +159,7 @@ static bool is_libpfm_event_supported(const char *name, struct perf_cpu_map *cpu
result = false;
evsel__close(evsel);
- evsel__delete(evsel);
+ evsel__put(evsel);
return result;
}
diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c
index cb27e2898aa0..0242243681b6 100644
--- a/tools/perf/util/print-events.c
+++ b/tools/perf/util/print-events.c
@@ -174,7 +174,7 @@ bool is_event_supported(u8 type, u64 config)
}
evsel__close(evsel);
- evsel__delete(evsel);
+ evsel__put(evsel);
}
perf_thread_map__put(tmap);
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index aeecdb497fac..a0ec63d39969 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -274,6 +274,7 @@ static PyMemberDef pyrf_sample_event__members[] = {
static void pyrf_sample_event__delete(struct pyrf_event *pevent)
{
+ evsel__put(pevent->evsel);
perf_sample__exit(&pevent->sample);
Py_TYPE(pevent)->tp_free((PyObject*)pevent);
}
@@ -506,8 +507,10 @@ static PyObject *pyrf_event__new(const union perf_event *event)
ptype = pyrf_event__type[event->header.type];
pevent = PyObject_New(struct pyrf_event, ptype);
- if (pevent != NULL)
+ if (pevent != NULL) {
memcpy(&pevent->event, event, event->header.size);
+ pevent->evsel = NULL;
+ }
return (PyObject *)pevent;
}
@@ -945,7 +948,7 @@ static int pyrf_counts_values__setup_types(void)
struct pyrf_evsel {
PyObject_HEAD
- struct evsel evsel;
+ struct evsel *evsel;
};
static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
@@ -1053,20 +1056,25 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
attr.sample_id_all = sample_id_all;
attr.size = sizeof(attr);
- evsel__init(&pevsel->evsel, &attr, idx);
+ evsel__put(pevsel->evsel);
+ pevsel->evsel = evsel__new(&attr);
+ if (!pevsel->evsel) {
+ PyErr_NoMemory();
+ return -1;
+ }
return 0;
}
static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
{
- evsel__exit(&pevsel->evsel);
+ evsel__put(pevsel->evsel);
Py_TYPE(pevsel)->tp_free((PyObject*)pevsel);
}
static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
PyObject *args, PyObject *kwargs)
{
- struct evsel *evsel = &pevsel->evsel;
+ struct evsel *evsel = pevsel->evsel;
struct perf_cpu_map *cpus = NULL;
struct perf_thread_map *threads = NULL;
PyObject *pcpus = NULL, *pthreads = NULL;
@@ -1102,7 +1110,7 @@ static PyObject *pyrf_evsel__cpus(struct pyrf_evsel *pevsel)
struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
if (pcpu_map)
- pcpu_map->cpus = perf_cpu_map__get(pevsel->evsel.core.cpus);
+ pcpu_map->cpus = perf_cpu_map__get(pevsel->evsel->core.cpus);
return (PyObject *)pcpu_map;
}
@@ -1113,7 +1121,7 @@ static PyObject *pyrf_evsel__threads(struct pyrf_evsel *pevsel)
PyObject_New(struct pyrf_thread_map, &pyrf_thread_map__type);
if (pthread_map)
- pthread_map->threads = perf_thread_map__get(pevsel->evsel.core.threads);
+ pthread_map->threads = perf_thread_map__get(pevsel->evsel->core.threads);
return (PyObject *)pthread_map;
}
@@ -1147,7 +1155,7 @@ static int evsel__ensure_counts(struct evsel *evsel)
static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
PyObject *args, PyObject *kwargs)
{
- struct evsel *evsel = &pevsel->evsel;
+ struct evsel *evsel = pevsel->evsel;
int cpu = 0, cpu_idx, thread = 0, thread_idx;
struct perf_counts_values *old_count, *new_count;
struct pyrf_counts_values *count_values = PyObject_New(struct pyrf_counts_values,
@@ -1192,7 +1200,7 @@ static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
static PyObject *pyrf_evsel__str(PyObject *self)
{
struct pyrf_evsel *pevsel = (void *)self;
- struct evsel *evsel = &pevsel->evsel;
+ struct evsel *evsel = pevsel->evsel;
return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel));
}
@@ -1225,30 +1233,183 @@ static PyMethodDef pyrf_evsel__methods[] = {
{ .ml_name = NULL, }
};
-#define evsel_member_def(member, ptype, help) \
- { #member, ptype, \
- offsetof(struct pyrf_evsel, evsel.member), \
- 0, help }
+static PyObject *pyrf_evsel__get_tracking(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
-#define evsel_attr_member_def(member, ptype, help) \
- { #member, ptype, \
- offsetof(struct pyrf_evsel, evsel.core.attr.member), \
- 0, help }
+ if (pevsel->evsel->tracking)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
-static PyMemberDef pyrf_evsel__members[] = {
- evsel_member_def(tracking, T_BOOL, "tracking event."),
- evsel_attr_member_def(type, T_UINT, "attribute type."),
- evsel_attr_member_def(size, T_UINT, "attribute size."),
- evsel_attr_member_def(config, T_ULONGLONG, "attribute config."),
- evsel_attr_member_def(sample_period, T_ULONGLONG, "attribute sample_period."),
- evsel_attr_member_def(sample_type, T_ULONGLONG, "attribute sample_type."),
- evsel_attr_member_def(read_format, T_ULONGLONG, "attribute read_format."),
- evsel_attr_member_def(wakeup_events, T_UINT, "attribute wakeup_events."),
- { .name = NULL, },
+static int pyrf_evsel__set_tracking(PyObject *self, PyObject *val, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ pevsel->evsel->tracking = Py_IsTrue(val) ? true : false;
+ return 0;
+}
+
+static int pyrf_evsel__set_attr_config(PyObject *self, PyObject *val, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ pevsel->evsel->core.attr.config = PyLong_AsUnsignedLongLong(val);
+ return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_config(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.config);
+}
+
+static int pyrf_evsel__set_attr_read_format(PyObject *self, PyObject *val, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ pevsel->evsel->core.attr.read_format = PyLong_AsUnsignedLongLong(val);
+ return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_read_format(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.read_format);
+}
+
+static int pyrf_evsel__set_attr_sample_period(PyObject *self, PyObject *val, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ pevsel->evsel->core.attr.sample_period = PyLong_AsUnsignedLongLong(val);
+ return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_sample_period(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.sample_period);
+}
+
+static int pyrf_evsel__set_attr_sample_type(PyObject *self, PyObject *val, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ pevsel->evsel->core.attr.sample_type = PyLong_AsUnsignedLongLong(val);
+ return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_sample_type(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.sample_type);
+}
+
+static PyObject *pyrf_evsel__get_attr_size(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.size);
+}
+
+static int pyrf_evsel__set_attr_type(PyObject *self, PyObject *val, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ pevsel->evsel->core.attr.type = PyLong_AsUnsignedLong(val);
+ return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_type(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.type);
+}
+
+static int pyrf_evsel__set_attr_wakeup_events(PyObject *self, PyObject *val, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ pevsel->evsel->core.attr.wakeup_events = PyLong_AsUnsignedLong(val);
+ return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_wakeup_events(PyObject *self, void */*closure*/)
+{
+ struct pyrf_evsel *pevsel = (void *)self;
+
+ return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.wakeup_events);
+}
+
+static PyGetSetDef pyrf_evsel__getset[] = {
+ {
+ .name = "tracking",
+ .get = pyrf_evsel__get_tracking,
+ .set = pyrf_evsel__set_tracking,
+ .doc = "tracking event.",
+ },
+ {
+ .name = "config",
+ .get = pyrf_evsel__get_attr_config,
+ .set = pyrf_evsel__set_attr_config,
+ .doc = "attribute config.",
+ },
+ {
+ .name = "read_format",
+ .get = pyrf_evsel__get_attr_read_format,
+ .set = pyrf_evsel__set_attr_read_format,
+ .doc = "attribute read_format.",
+ },
+ {
+ .name = "sample_period",
+ .get = pyrf_evsel__get_attr_sample_period,
+ .set = pyrf_evsel__set_attr_sample_period,
+ .doc = "attribute sample_period.",
+ },
+ {
+ .name = "sample_type",
+ .get = pyrf_evsel__get_attr_sample_type,
+ .set = pyrf_evsel__set_attr_sample_type,
+ .doc = "attribute sample_type.",
+ },
+ {
+ .name = "size",
+ .get = pyrf_evsel__get_attr_size,
+ .doc = "attribute size.",
+ },
+ {
+ .name = "type",
+ .get = pyrf_evsel__get_attr_type,
+ .set = pyrf_evsel__set_attr_type,
+ .doc = "attribute type.",
+ },
+ {
+ .name = "wakeup_events",
+ .get = pyrf_evsel__get_attr_wakeup_events,
+ .set = pyrf_evsel__set_attr_wakeup_events,
+ .doc = "attribute wakeup_events.",
+ },
+ { .name = NULL},
};
static const char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
+static PyObject *pyrf_evsel__getattro(struct pyrf_evsel *pevsel, PyObject *attr_name)
+{
+ if (!pevsel->evsel) {
+ PyErr_SetString(PyExc_ValueError, "evsel not initialized");
+ return NULL;
+ }
+ return PyObject_GenericGetAttr((PyObject *) pevsel, attr_name);
+}
+
static PyTypeObject pyrf_evsel__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.evsel",
@@ -1256,16 +1417,27 @@ static PyTypeObject pyrf_evsel__type = {
.tp_dealloc = (destructor)pyrf_evsel__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_evsel__doc,
- .tp_members = pyrf_evsel__members,
+ .tp_getset = pyrf_evsel__getset,
.tp_methods = pyrf_evsel__methods,
.tp_init = (initproc)pyrf_evsel__init,
.tp_str = pyrf_evsel__str,
.tp_repr = pyrf_evsel__str,
+ .tp_getattro = (getattrofunc) pyrf_evsel__getattro,
};
+static PyObject *pyrf_evsel__new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ struct pyrf_evsel *pevsel;
+
+ pevsel = (struct pyrf_evsel *)PyType_GenericNew(type, args, kwargs);
+ if (pevsel)
+ pevsel->evsel = NULL;
+ return (PyObject *)pevsel;
+}
+
static int pyrf_evsel__setup_types(void)
{
- pyrf_evsel__type.tp_new = PyType_GenericNew;
+ pyrf_evsel__type.tp_new = pyrf_evsel__new;
return PyType_Ready(&pyrf_evsel__type);
}
@@ -1566,9 +1738,9 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
return NULL;
Py_INCREF(pevsel);
- evsel = &((struct pyrf_evsel *)pevsel)->evsel;
+ evsel = ((struct pyrf_evsel *)pevsel)->evsel;
evsel->core.idx = evlist->core.nr_entries;
- evlist__add(evlist, evsel);
+ evlist__add(evlist, evsel__get(evsel));
return Py_BuildValue("i", evlist->core.nr_entries);
}
@@ -1626,7 +1798,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
return Py_None;
}
- pevent->evsel = evsel;
+ pevent->evsel = evsel__get(evsel);
perf_mmap__consume(&md->core);
@@ -1803,12 +1975,7 @@ static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
if (!pevsel)
return NULL;
- memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
- evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
-
- evsel__clone(&pevsel->evsel, evsel);
- if (evsel__is_group_leader(evsel))
- evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
+ pevsel->evsel = evsel__get(evsel);
return (PyObject *)pevsel;
}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1ac6cd43c38b..deb5b9dfe44c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1373,6 +1373,7 @@ static int evlist__deliver_deferred_callchain(struct evlist *evlist,
sample->evsel = evlist__id2evsel(evlist, sample->id);
ret = tool->callchain_deferred(tool, event, sample,
sample->evsel, machine);
+ evsel__put(sample->evsel);
sample->evsel = saved_evsel;
return ret;
}
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 14/59] perf python: Add wrapper for perf_data file abstraction
From: Ian Rogers @ 2026-04-25 22:49 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
The perf_data struct is needed for session supported.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2:
1. Fixed Memory & FD Leaks in pyrf_data__init : Added cleanup of old
state (closing file and freeing path) if __init__ is called
multiple times on the same object.
2. Fixed Invalid Free in pyrf_data__delete : Ensured pdata->data.path
is always dynamically allocated via strdup() , even for the default
"perf.data" . This avoids passing a static string literal to free().
3. Fixed NULL Pointer Dereference in pyrf_data__str : Added a check
for NULL path to prevent segfaults if str() or repr() is called on
an uninitialized object.
4. Guarded fd Argument Usage: Added a check to ensure that if an fd is
provided, it corresponds to a pipe, failing gracefully with a
ValueError otherwise.
v7:
- Added pyrf_data__new to zero-initialize pdata->data to fix
crash on re-initialization.
---
tools/perf/util/python.c | 103 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 102 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 2ba3556c4f16..aa63c7ffe822 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -10,6 +10,7 @@
#include "callchain.h"
#include "counts.h"
+#include "data.h"
#include "event.h"
#include "evlist.h"
#include "evsel.h"
@@ -2316,6 +2317,102 @@ static PyObject *pyrf__metrics(PyObject *self, PyObject *args)
return list;
}
+struct pyrf_data {
+ PyObject_HEAD
+
+ struct perf_data data;
+};
+
+static int pyrf_data__init(struct pyrf_data *pdata, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "path", "fd", NULL };
+ char *path = NULL;
+ int fd = -1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|si", kwlist, &path, &fd))
+ return -1;
+
+ if (pdata->data.open)
+ perf_data__close(&pdata->data);
+ free((char *)pdata->data.path);
+
+ if (!path)
+ path = "perf.data";
+
+ pdata->data.path = strdup(path);
+ if (!pdata->data.path) {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ if (fd != -1) {
+ struct stat st;
+
+ if (fstat(fd, &st) < 0 || !S_ISFIFO(st.st_mode)) {
+ PyErr_SetString(PyExc_ValueError,
+ "fd argument is only supported for pipes");
+ free((char *)pdata->data.path);
+ pdata->data.path = NULL;
+ return -1;
+ }
+ }
+
+ pdata->data.mode = PERF_DATA_MODE_READ;
+ pdata->data.file.fd = fd;
+ if (perf_data__open(&pdata->data) < 0) {
+ PyErr_Format(PyExc_IOError, "Failed to open perf data: %s",
+ pdata->data.path ? pdata->data.path : "perf.data");
+ return -1;
+ }
+ return 0;
+}
+
+static void pyrf_data__delete(struct pyrf_data *pdata)
+{
+ perf_data__close(&pdata->data);
+ free((char *)pdata->data.path);
+ Py_TYPE(pdata)->tp_free((PyObject *)pdata);
+}
+
+static PyObject *pyrf_data__str(PyObject *self)
+{
+ const struct pyrf_data *pdata = (const struct pyrf_data *)self;
+
+ if (!pdata->data.path)
+ return PyUnicode_FromString("[uninitialized]");
+ return PyUnicode_FromString(pdata->data.path);
+}
+
+static PyObject *pyrf_data__new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ struct pyrf_data *pdata;
+
+ pdata = (struct pyrf_data *)PyType_GenericNew(type, args, kwargs);
+ if (pdata)
+ memset(&pdata->data, 0, sizeof(pdata->data));
+ return (PyObject *)pdata;
+}
+
+static const char pyrf_data__doc[] = PyDoc_STR("perf data file object.");
+
+static PyTypeObject pyrf_data__type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "perf.data",
+ .tp_basicsize = sizeof(struct pyrf_data),
+ .tp_dealloc = (destructor)pyrf_data__delete,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ .tp_doc = pyrf_data__doc,
+ .tp_init = (initproc)pyrf_data__init,
+ .tp_repr = pyrf_data__str,
+ .tp_str = pyrf_data__str,
+};
+
+static int pyrf_data__setup_types(void)
+{
+ pyrf_data__type.tp_new = pyrf_data__new;
+ return PyType_Ready(&pyrf_data__type);
+}
+
static PyMethodDef perf__methods[] = {
{
.ml_name = "metrics",
@@ -2378,7 +2475,8 @@ PyMODINIT_FUNC PyInit_perf(void)
pyrf_cpu_map__setup_types() < 0 ||
pyrf_pmu_iterator__setup_types() < 0 ||
pyrf_pmu__setup_types() < 0 ||
- pyrf_counts_values__setup_types() < 0)
+ pyrf_counts_values__setup_types() < 0 ||
+ pyrf_data__setup_types() < 0)
return module;
/* The page_size is placed in util object. */
@@ -2426,6 +2524,9 @@ PyMODINIT_FUNC PyInit_perf(void)
Py_INCREF(&pyrf_counts_values__type);
PyModule_AddObject(module, "counts_values", (PyObject *)&pyrf_counts_values__type);
+ Py_INCREF(&pyrf_data__type);
+ PyModule_AddObject(module, "data", (PyObject *)&pyrf_data__type);
+
dict = PyModule_GetDict(module);
if (dict == NULL)
goto error;
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 13/59] perf python: Use evsel in sample in pyrf_event
From: Ian Rogers @ 2026-04-25 22:49 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Avoid a duplicated evsel by using the one in sample. Add
evsel__get/put to the evsel in perf_sample.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/evsel.c | 2 +-
tools/perf/util/python.c | 10 +++-------
tools/perf/util/sample.c | 17 ++++++++++++-----
3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3015b9b4b4da..9b16d832810f 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -3235,7 +3235,7 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
union u64_swap u;
perf_sample__init(data, /*all=*/true);
- data->evsel = evsel;
+ data->evsel = evsel__get(evsel);
data->cpu = data->pid = data->tid = -1;
data->stream_id = data->id = data->time = -1ULL;
data->period = evsel->core.attr.sample_period;
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 22cc57914ad4..2ba3556c4f16 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -43,7 +43,6 @@ PyMODINIT_FUNC PyInit_perf(void);
struct pyrf_event {
PyObject_HEAD
- struct evsel *evsel;
struct perf_sample sample;
union perf_event event;
};
@@ -274,7 +273,6 @@ static PyMemberDef pyrf_sample_event__members[] = {
static void pyrf_sample_event__delete(struct pyrf_event *pevent)
{
- evsel__put(pevent->evsel);
perf_sample__exit(&pevent->sample);
Py_TYPE(pevent)->tp_free((PyObject*)pevent);
}
@@ -296,7 +294,7 @@ static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent)
#ifdef HAVE_LIBTRACEEVENT
static bool is_tracepoint(const struct pyrf_event *pevent)
{
- return pevent->evsel->core.attr.type == PERF_TYPE_TRACEPOINT;
+ return pevent->sample.evsel->core.attr.type == PERF_TYPE_TRACEPOINT;
}
static PyObject*
@@ -343,7 +341,7 @@ tracepoint_field(const struct pyrf_event *pe, struct tep_format_field *field)
static PyObject*
get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
{
- struct evsel *evsel = pevent->evsel;
+ struct evsel *evsel = pevent->sample.evsel;
struct tep_event *tp_format = evsel__tp_format(evsel);
struct tep_format_field *field;
@@ -509,7 +507,7 @@ static PyObject *pyrf_event__new(const union perf_event *event)
pevent = PyObject_New(struct pyrf_event, ptype);
if (pevent != NULL) {
memcpy(&pevent->event, event, event->header.size);
- pevent->evsel = NULL;
+ perf_sample__init(&pevent->sample, /*all=*/false);
}
return (PyObject *)pevent;
}
@@ -1798,8 +1796,6 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
return Py_None;
}
- pevent->evsel = evsel__get(evsel);
-
perf_mmap__consume(&md->core);
err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample);
diff --git a/tools/perf/util/sample.c b/tools/perf/util/sample.c
index cf73329326d7..7ec534dedc5c 100644
--- a/tools/perf/util/sample.c
+++ b/tools/perf/util/sample.c
@@ -1,18 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include "sample.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <elf.h>
+#include <linux/zalloc.h>
+
#include "debug.h"
+#include "evsel.h"
#include "thread.h"
-#include <elf.h>
+#include "../../arch/x86/include/asm/insn.h"
+
#ifndef EM_CSKY
#define EM_CSKY 252
#endif
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258
#endif
-#include <linux/zalloc.h>
-#include <stdlib.h>
-#include <string.h>
-#include "../../arch/x86/include/asm/insn.h"
void perf_sample__init(struct perf_sample *sample, bool all)
{
@@ -29,6 +34,8 @@ void perf_sample__init(struct perf_sample *sample, bool all)
void perf_sample__exit(struct perf_sample *sample)
{
+ evsel__put(sample->evsel);
+ sample->evsel = NULL;
zfree(&sample->user_regs);
zfree(&sample->intr_regs);
if (sample->merged_callchain) {
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 09/59] perf data: Add open flag
From: Ian Rogers @ 2026-04-25 22:49 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Avoid double opens and ensure only open files are closed. This
addresses some issues with python integration where the data file
wants to be opened before being given to a session.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
Changes in v2:
1. Fixed File Rotation: In perf_data__switch() , I added data->open =
false; after the file is closed. This ensures that the subsequent
perf_data__open() call will not exit early and will successfully
open the new file.
2. Fixed Memory Leak: In open_dir() , I added a call to
zfree(&data->file.path) if mkdir() fails, preventing the leak of
the path string.
---
tools/perf/util/data.c | 26 ++++++++++++++++++++++----
tools/perf/util/data.h | 4 +++-
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 94dc534a7386..17baf71897d1 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -346,8 +346,10 @@ static int open_dir(struct perf_data *data)
return -1;
if (perf_data__is_write(data) &&
- mkdir(data->path, S_IRWXU) < 0)
+ mkdir(data->path, S_IRWXU) < 0) {
+ zfree(&data->file.path);
return -1;
+ }
ret = open_file(data);
@@ -360,9 +362,16 @@ static int open_dir(struct perf_data *data)
int perf_data__open(struct perf_data *data)
{
- if (check_pipe(data))
+ int ret;
+
+ if (data->open)
return 0;
+ if (check_pipe(data)) {
+ data->open = true;
+ return 0;
+ }
+
/* currently it allows stdio for pipe only */
data->file.use_stdio = false;
@@ -375,16 +384,24 @@ int perf_data__open(struct perf_data *data)
if (perf_data__is_read(data))
data->is_dir = is_dir(data);
- return perf_data__is_dir(data) ?
- open_dir(data) : open_file_dup(data);
+ ret = perf_data__is_dir(data) ? open_dir(data) : open_file_dup(data);
+
+ if (!ret)
+ data->open = true;
+
+ return ret;
}
void perf_data__close(struct perf_data *data)
{
+ if (!data->open)
+ return;
+
if (perf_data__is_dir(data))
perf_data__close_dir(data);
perf_data_file__close(&data->file);
+ data->open = false;
}
static ssize_t perf_data_file__read(struct perf_data_file *file, void *buf, size_t size)
@@ -457,6 +474,7 @@ int perf_data__switch(struct perf_data *data,
if (!at_exit) {
perf_data_file__close(&data->file);
+ data->open = false;
ret = perf_data__open(data);
if (ret < 0)
goto out;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 8299fb5fa7da..76f57f60361f 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -50,6 +50,8 @@ struct perf_data {
const char *path;
/** @file: Underlying file to be used. */
struct perf_data_file file;
+ /** @open: Has the file or directory been opened. */
+ bool open;
/** @is_pipe: Underlying file is a pipe. */
bool is_pipe;
/** @is_dir: Underlying file is a directory. */
@@ -59,7 +61,7 @@ struct perf_data {
/** @in_place_update: A file opened for reading but will be written to. */
bool in_place_update;
/** @mode: Read or write mode. */
- enum perf_data_mode mode;
+ enum perf_data_mode mode:8;
struct {
/** @version: perf_dir_version. */
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 08/59] perf evsel/evlist: Avoid unnecessary #includes
From: Ian Rogers @ 2026-04-25 22:49 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Use forward declarations and remove unnecessary #includes in
evsel.h. Sort the forward declarations in evsel.h and evlist.h.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/evlist.h | 15 +++++++++------
tools/perf/util/evsel.h | 20 +++++++++++---------
2 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index e507f5f20ef6..e54761c670b6 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -2,29 +2,32 @@
#ifndef __PERF_EVLIST_H
#define __PERF_EVLIST_H 1
+#include <signal.h>
+
#include <linux/compiler.h>
#include <linux/kernel.h>
-#include <linux/refcount.h>
#include <linux/list.h>
+#include <linux/refcount.h>
+#include <pthread.h>
+#include <unistd.h>
+
#include <api/fd/array.h>
#include <internal/evlist.h>
#include <internal/evsel.h>
#include <perf/evlist.h>
+
#include "affinity.h"
#include "events_stats.h"
#include "evsel.h"
#include "rblist.h"
-#include <pthread.h>
-#include <signal.h>
-#include <unistd.h>
-struct pollfd;
-struct thread_map;
struct perf_cpu_map;
struct perf_stat_config;
+struct pollfd;
struct record_opts;
struct strbuf;
struct target;
+struct thread_map;
/*
* State machine of bkw_mmap_state:
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 339b5c08a33d..b099c8e5dd86 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -2,28 +2,30 @@
#ifndef __PERF_EVSEL_H
#define __PERF_EVSEL_H 1
-#include <linux/list.h>
#include <stdbool.h>
-#include <sys/types.h>
+
+#include <linux/list.h>
#include <linux/perf_event.h>
#include <linux/types.h>
+#include <sys/types.h>
+
#include <internal/evsel.h>
#include <perf/evsel.h>
+
#include "symbol_conf.h"
-#include "pmus.h"
-#include "pmu.h"
+struct bperf_follower_bpf;
+struct bperf_leader_bpf;
+struct bpf_counter_ops;
struct bpf_object;
struct cgroup;
+struct hashmap;
struct perf_counts;
+struct perf_pmu;
struct perf_stat_config;
struct perf_stat_evsel;
-union perf_event;
-struct bpf_counter_ops;
struct target;
-struct hashmap;
-struct bperf_leader_bpf;
-struct bperf_follower_bpf;
+union perf_event;
typedef int (evsel__sb_cb_t)(union perf_event *event, void *data);
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 06/59] perf util: Sort includes and add missed explicit dependencies
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Fix missing includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/bpf_off_cpu.c | 30 +++++-----
tools/perf/util/bpf_trace_augment.c | 8 +--
tools/perf/util/evlist.c | 91 +++++++++++++++--------------
tools/perf/util/evsel.c | 75 ++++++++++++------------
tools/perf/util/map.h | 9 ++-
tools/perf/util/perf_api_probe.c | 18 +++---
tools/perf/util/s390-sample-raw.c | 19 +++---
tools/perf/util/stat-shadow.c | 20 ++++---
tools/perf/util/stat.c | 16 +++--
9 files changed, 152 insertions(+), 134 deletions(-)
diff --git a/tools/perf/util/bpf_off_cpu.c b/tools/perf/util/bpf_off_cpu.c
index a3b699a5322f..48cb930cdd2e 100644
--- a/tools/perf/util/bpf_off_cpu.c
+++ b/tools/perf/util/bpf_off_cpu.c
@@ -1,23 +1,25 @@
// SPDX-License-Identifier: GPL-2.0
-#include "util/bpf_counter.h"
-#include "util/debug.h"
-#include "util/evsel.h"
-#include "util/evlist.h"
-#include "util/off_cpu.h"
-#include "util/perf-hooks.h"
-#include "util/record.h"
-#include "util/session.h"
-#include "util/target.h"
-#include "util/cpumap.h"
-#include "util/thread_map.h"
-#include "util/cgroup.h"
-#include "util/strlist.h"
+#include <linux/time64.h>
+
#include <bpf/bpf.h>
#include <bpf/btf.h>
#include <internal/xyarray.h>
-#include <linux/time64.h>
+#include "bpf_counter.h"
#include "bpf_skel/off_cpu.skel.h"
+#include "cgroup.h"
+#include "cpumap.h"
+#include "debug.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "off_cpu.h"
+#include "parse-events.h"
+#include "perf-hooks.h"
+#include "record.h"
+#include "session.h"
+#include "strlist.h"
+#include "target.h"
+#include "thread_map.h"
#define MAX_STACKS 32
#define MAX_PROC 4096
diff --git a/tools/perf/util/bpf_trace_augment.c b/tools/perf/util/bpf_trace_augment.c
index 9e706f0fa53d..a9cf2a77ded1 100644
--- a/tools/perf/util/bpf_trace_augment.c
+++ b/tools/perf/util/bpf_trace_augment.c
@@ -1,11 +1,11 @@
#include <bpf/libbpf.h>
#include <internal/xyarray.h>
-#include "util/debug.h"
-#include "util/evlist.h"
-#include "util/trace_augment.h"
-
#include "bpf_skel/augmented_raw_syscalls.skel.h"
+#include "debug.h"
+#include "evlist.h"
+#include "parse-events.h"
+#include "trace_augment.h"
static struct augmented_raw_syscalls_bpf *skel;
static struct evsel *bpf_output;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ee971d15b3c6..35d65fe50e06 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -5,67 +5,68 @@
* Parts came from builtin-{top,stat,record}.c, see those files for further
* copyright notes.
*/
-#include <api/fs/fs.h>
+#include "evlist.h"
+
#include <errno.h>
#include <inttypes.h>
-#include <poll.h>
-#include "cpumap.h"
-#include "util/mmap.h"
-#include "thread_map.h"
-#include "target.h"
-#include "dwarf-regs.h"
-#include "evlist.h"
-#include "evsel.h"
-#include "record.h"
-#include "debug.h"
-#include "units.h"
-#include "bpf_counter.h"
-#include <internal/lib.h> // page_size
-#include "affinity.h"
-#include "../perf.h"
-#include "asm/bug.h"
-#include "bpf-event.h"
-#include "util/event.h"
-#include "util/string2.h"
-#include "util/perf_api_probe.h"
-#include "util/evsel_fprintf.h"
-#include "util/pmu.h"
-#include "util/sample.h"
-#include "util/bpf-filter.h"
-#include "util/stat.h"
-#include "util/util.h"
-#include "util/env.h"
-#include "util/intel-tpebs.h"
-#include "util/metricgroup.h"
-#include "util/strbuf.h"
#include <signal.h>
-#include <unistd.h>
-#include <sched.h>
#include <stdlib.h>
-#include "parse-events.h"
-#include <subcmd/parse-options.h>
-
#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/timerfd.h>
-#include <sys/wait.h>
-
#include <linux/bitops.h>
+#include <linux/err.h>
#include <linux/hash.h>
#include <linux/log2.h>
-#include <linux/err.h>
#include <linux/string.h>
#include <linux/time64.h>
#include <linux/zalloc.h>
+#include <poll.h>
+#include <sched.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/timerfd.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <api/fs/fs.h>
+#include <internal/lib.h> // page_size
+#include <internal/xyarray.h>
+#include <perf/cpumap.h>
#include <perf/evlist.h>
#include <perf/evsel.h>
-#include <perf/cpumap.h>
#include <perf/mmap.h>
+#include <subcmd/parse-options.h>
-#include <internal/xyarray.h>
+#include "../perf.h"
+#include "affinity.h"
+#include "asm/bug.h"
+#include "bpf-event.h"
+#include "bpf-filter.h"
+#include "bpf_counter.h"
+#include "cpumap.h"
+#include "debug.h"
+#include "dwarf-regs.h"
+#include "env.h"
+#include "event.h"
+#include "evsel.h"
+#include "evsel_fprintf.h"
+#include "intel-tpebs.h"
+#include "metricgroup.h"
+#include "mmap.h"
+#include "parse-events.h"
+#include "perf_api_probe.h"
+#include "pmu.h"
+#include "pmus.h"
+#include "record.h"
+#include "sample.h"
+#include "stat.h"
+#include "strbuf.h"
+#include "string2.h"
+#include "target.h"
+#include "thread_map.h"
+#include "units.h"
+#include "util.h"
#ifdef LACKS_SIGQUEUE_PROTOTYPE
int sigqueue(pid_t pid, int sig, const union sigval value);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2ee87fd84d3e..e03727d395e9 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -11,68 +11,71 @@
*/
#define __SANE_USERSPACE_TYPES__
-#include <byteswap.h>
+#include "evsel.h"
+
#include <errno.h>
#include <inttypes.h>
+#include <stdlib.h>
+
+#include <dirent.h>
#include <linux/bitops.h>
-#include <api/fs/fs.h>
-#include <api/fs/tracing_path.h>
-#include <linux/hw_breakpoint.h>
-#include <linux/perf_event.h>
#include <linux/compiler.h>
+#include <linux/ctype.h>
#include <linux/err.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/perf_event.h>
#include <linux/zalloc.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/types.h>
-#include <dirent.h>
-#include <stdlib.h>
+
+#include <api/fs/fs.h>
+#include <api/fs/tracing_path.h>
+#include <byteswap.h>
+#include <internal/lib.h>
+#include <internal/threadmap.h>
+#include <internal/xyarray.h>
+#include <perf/cpumap.h>
#include <perf/evsel.h>
+
+#include "../perf-sys.h"
#include "asm/bug.h"
+#include "bpf-filter.h"
#include "bpf_counter.h"
#include "callchain.h"
#include "cgroup.h"
#include "counts.h"
+#include "debug.h"
+#include "drm_pmu.h"
#include "dwarf-regs.h"
+#include "env.h"
#include "event.h"
-#include "evsel.h"
-#include "time-utils.h"
-#include "util/env.h"
-#include "util/evsel_config.h"
-#include "util/evsel_fprintf.h"
#include "evlist.h"
-#include <perf/cpumap.h>
-#include "thread_map.h"
-#include "target.h"
+#include "evsel_config.h"
+#include "evsel_fprintf.h"
+#include "hashmap.h"
+#include "hist.h"
+#include "hwmon_pmu.h"
+#include "intel-tpebs.h"
+#include "memswap.h"
+#include "off_cpu.h"
+#include "parse-branch-options.h"
#include "perf_regs.h"
+#include "pmu.h"
+#include "pmus.h"
#include "record.h"
-#include "debug.h"
-#include "trace-event.h"
+#include "rlimit.h"
#include "session.h"
#include "stat.h"
#include "string2.h"
-#include "memswap.h"
-#include "util.h"
-#include "util/hashmap.h"
-#include "off_cpu.h"
-#include "pmu.h"
-#include "pmus.h"
-#include "drm_pmu.h"
-#include "hwmon_pmu.h"
+#include "target.h"
+#include "thread_map.h"
+#include "time-utils.h"
#include "tool_pmu.h"
#include "tp_pmu.h"
-#include "rlimit.h"
-#include "../perf-sys.h"
-#include "util/parse-branch-options.h"
-#include "util/bpf-filter.h"
-#include "util/hist.h"
-#include <internal/xyarray.h>
-#include <internal/lib.h>
-#include <internal/threadmap.h>
-#include "util/intel-tpebs.h"
-
-#include <linux/ctype.h>
+#include "trace-event.h"
+#include "util.h"
#ifdef HAVE_LIBTRACEEVENT
#include <event-parse.h>
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 979b3e11b9bc..fb0279810ae9 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -2,14 +2,13 @@
#ifndef __PERF_MAP_H
#define __PERF_MAP_H
-#include <linux/refcount.h>
-#include <linux/compiler.h>
-#include <linux/list.h>
-#include <linux/rbtree.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
-#include <stdbool.h>
+
+#include <linux/refcount.h>
#include <linux/types.h>
+
#include <internal/rc_check.h>
struct dso;
diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
index 6ecf38314f01..e1904a330b28 100644
--- a/tools/perf/util/perf_api_probe.c
+++ b/tools/perf/util/perf_api_probe.c
@@ -1,14 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#include "perf_api_probe.h"
-#include "perf-sys.h"
-#include "util/cloexec.h"
-#include "util/evlist.h"
-#include "util/evsel.h"
-#include "util/parse-events.h"
-#include "util/perf_api_probe.h"
-#include <perf/cpumap.h>
#include <errno.h>
+#include <perf/cpumap.h>
+
+#include "cloexec.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "parse-events.h"
+#include "perf-sys.h"
+#include "pmu.h"
+#include "pmus.h"
+
typedef void (*setup_probe_fn_t)(struct evsel *evsel);
static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str)
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index c6ae0ae8d86a..6bf0edf80d4e 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -12,25 +12,26 @@
* sample was taken from.
*/
-#include <unistd.h>
+#include <inttypes.h>
#include <stdio.h>
#include <string.h>
-#include <inttypes.h>
-#include <sys/stat.h>
+#include <asm/byteorder.h>
#include <linux/compiler.h>
#include <linux/err.h>
-#include <asm/byteorder.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "color.h"
#include "debug.h"
-#include "session.h"
#include "evlist.h"
-#include "color.h"
#include "hashmap.h"
-#include "sample-raw.h"
+#include "pmu.h"
+#include "pmus.h"
#include "s390-cpumcf-kernel.h"
-#include "util/pmu.h"
-#include "util/sample.h"
+#include "sample-raw.h"
+#include "sample.h"
+#include "session.h"
static size_t ctrset_size(struct cf_ctrset_entry *set)
{
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index bc2d44df7baf..48524450326d 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -2,20 +2,24 @@
#include <errno.h>
#include <math.h>
#include <stdio.h>
-#include "evsel.h"
-#include "stat.h"
+
+#include <linux/zalloc.h>
+
+#include "cgroup.h"
#include "color.h"
#include "debug.h"
-#include "pmu.h"
-#include "rblist.h"
#include "evlist.h"
+#include "evsel.h"
#include "expr.h"
-#include "metricgroup.h"
-#include "cgroup.h"
-#include "units.h"
+#include "hashmap.h"
#include "iostat.h"
-#include "util/hashmap.h"
+#include "metricgroup.h"
+#include "pmu.h"
+#include "pmus.h"
+#include "rblist.h"
+#include "stat.h"
#include "tool_pmu.h"
+#include "units.h"
static bool tool_pmu__is_time_event(const struct perf_stat_config *config,
const struct evsel *evsel, int *tool_aggr_idx)
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 14d169e22e8f..66eb9a66a4f7 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -1,21 +1,25 @@
// SPDX-License-Identifier: GPL-2.0
+#include "stat.h"
+
#include <errno.h>
-#include <linux/err.h>
#include <inttypes.h>
#include <math.h>
#include <string.h>
+
+#include <linux/err.h>
+#include <linux/zalloc.h>
+
#include "counts.h"
#include "cpumap.h"
#include "debug.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "hashmap.h"
#include "header.h"
-#include "stat.h"
+#include "pmu.h"
#include "session.h"
#include "target.h"
-#include "evlist.h"
-#include "evsel.h"
#include "thread_map.h"
-#include "util/hashmap.h"
-#include <linux/zalloc.h>
void update_stats(struct stats *stats, u64 val)
{
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 07/59] perf python: Add missed explicit dependencies
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Fix missing #include of pmus.h found while cleaning the evsel/evlist
header files.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/python.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index cc1019d29a5d..1e6c99efff90 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -5,26 +5,29 @@
#include <poll.h>
#include <linux/err.h>
#include <perf/cpumap.h>
-#ifdef HAVE_LIBTRACEEVENT
-#include <event-parse.h>
-#endif
+#include <internal/lib.h>
#include <perf/mmap.h>
+
#include "callchain.h"
#include "counts.h"
+#include "event.h"
#include "evlist.h"
#include "evsel.h"
-#include "event.h"
#include "expr.h"
+#include "metricgroup.h"
+#include "mmap.h"
+#include "pmus.h"
#include "print_binary.h"
#include "record.h"
#include "strbuf.h"
#include "thread_map.h"
#include "tp_pmu.h"
#include "trace-event.h"
-#include "metricgroup.h"
-#include "mmap.h"
#include "util/sample.h"
-#include <internal/lib.h>
+
+#ifdef HAVE_LIBTRACEEVENT
+#include <event-parse.h>
+#endif
PyMODINIT_FUNC PyInit_perf(void);
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 05/59] perf script: Sort includes and add missed explicit dependencies
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Fix missing #include of pmu.h found while cleaning the evsel/evlist
header files. Sort the remaining header files for consistency with the
rest of the code. Doing this exposed a missing forward declaration of
addr_location in print_insn.h, add this and sort the forward
declarations.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-script.c | 111 ++++++++++++++++++-----------------
tools/perf/util/print_insn.h | 5 +-
2 files changed, 60 insertions(+), 56 deletions(-)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c8ac9f01a36b..853b141a0d50 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1,74 +1,77 @@
// SPDX-License-Identifier: GPL-2.0
-#include "builtin.h"
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <linux/bitmap.h>
+#include <linux/compiler.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/stringify.h>
+#include <linux/time64.h>
+#include <linux/unaligned.h>
+#include <linux/zalloc.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <perf/evlist.h>
+#include <subcmd/exec-cmd.h>
+#include <subcmd/pager.h>
+#include <subcmd/parse-options.h>
+
+#include "asm/bug.h"
+#include "builtin.h"
+#include "perf.h"
+#include "print_binary.h"
+#include "print_insn.h"
+#include "ui/ui.h"
+#include "util/annotate.h"
+#include "util/auxtrace.h"
+#include "util/cgroup.h"
+#include "util/color.h"
#include "util/counts.h"
+#include "util/cpumap.h"
+#include "util/data.h"
#include "util/debug.h"
+#include "util/dlfilter.h"
#include "util/dso.h"
-#include <subcmd/exec-cmd.h>
-#include "util/header.h"
-#include <subcmd/parse-options.h>
-#include "util/perf_regs.h"
-#include "util/session.h"
-#include "util/tool.h"
-#include "util/map.h"
-#include "util/srcline.h"
-#include "util/symbol.h"
-#include "util/thread.h"
-#include "util/trace-event.h"
+#include "util/dump-insn.h"
#include "util/env.h"
+#include "util/event.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/evsel_fprintf.h"
#include "util/evswitch.h"
+#include "util/header.h"
+#include "util/map.h"
+#include "util/mem-events.h"
+#include "util/mem-info.h"
+#include "util/metricgroup.h"
+#include "util/path.h"
+#include "util/perf_regs.h"
+#include "util/pmu.h"
+#include "util/record.h"
+#include "util/session.h"
#include "util/sort.h"
-#include "util/data.h"
-#include "util/auxtrace.h"
-#include "util/cpumap.h"
-#include "util/thread_map.h"
+#include "util/srcline.h"
#include "util/stat.h"
-#include "util/color.h"
#include "util/string2.h"
+#include "util/symbol.h"
#include "util/thread-stack.h"
+#include "util/thread.h"
+#include "util/thread_map.h"
#include "util/time-utils.h"
-#include "util/path.h"
-#include "util/event.h"
-#include "util/mem-info.h"
-#include "util/metricgroup.h"
-#include "ui/ui.h"
-#include "print_binary.h"
-#include "print_insn.h"
-#include <linux/bitmap.h>
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/stringify.h>
-#include <linux/time64.h>
-#include <linux/zalloc.h>
-#include <linux/unaligned.h>
-#include <sys/utsname.h>
-#include "asm/bug.h"
-#include "util/mem-events.h"
-#include "util/dump-insn.h"
-#include <dirent.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <subcmd/pager.h>
-#include <perf/evlist.h>
-#include <linux/err.h>
-#include "util/dlfilter.h"
-#include "util/record.h"
+#include "util/tool.h"
+#include "util/trace-event.h"
#include "util/util.h"
-#include "util/cgroup.h"
-#include "util/annotate.h"
-#include "perf.h"
-#include <linux/ctype.h>
#ifdef HAVE_LIBTRACEEVENT
#include <event-parse.h>
#endif
diff --git a/tools/perf/util/print_insn.h b/tools/perf/util/print_insn.h
index 07d11af3fc1c..a54f7e858e49 100644
--- a/tools/perf/util/print_insn.h
+++ b/tools/perf/util/print_insn.h
@@ -5,10 +5,11 @@
#include <stddef.h>
#include <stdio.h>
-struct perf_sample;
-struct thread;
+struct addr_location;
struct machine;
struct perf_insn;
+struct perf_sample;
+struct thread;
#define PRINT_INSN_IMM_HEX (1<<0)
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 03/59] perf arch x86: Sort includes and add missed explicit dependencies
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Fix missing #includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/arch/x86/util/intel-bts.c | 20 +++++++++++--------
tools/perf/arch/x86/util/intel-pt.c | 29 +++++++++++++++-------------
2 files changed, 28 insertions(+), 21 deletions(-)
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 85c8186300c8..100a23d27998 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -4,26 +4,30 @@
* Copyright (c) 2013-2015, Intel Corporation.
*/
+#include "../../../util/intel-bts.h"
+
#include <errno.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
+
#include <linux/bitops.h>
+#include <linux/kernel.h>
#include <linux/log2.h>
+#include <linux/types.h>
#include <linux/zalloc.h>
+#include <internal/lib.h> // page_size
+
+#include "../../../util/auxtrace.h"
#include "../../../util/cpumap.h"
+#include "../../../util/debug.h"
#include "../../../util/event.h"
-#include "../../../util/evsel.h"
#include "../../../util/evlist.h"
+#include "../../../util/evsel.h"
#include "../../../util/mmap.h"
-#include "../../../util/session.h"
+#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
-#include "../../../util/debug.h"
#include "../../../util/record.h"
+#include "../../../util/session.h"
#include "../../../util/tsc.h"
-#include "../../../util/auxtrace.h"
-#include "../../../util/intel-bts.h"
-#include <internal/lib.h> // page_size
#define KiB(x) ((x) * 1024)
#define MiB(x) ((x) * 1024 * 1024)
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index c131a727774f..0307ff15d9fc 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -3,36 +3,39 @@
* intel_pt.c: Intel Processor Trace support
* Copyright (c) 2013-2015, Intel Corporation.
*/
+#include "../../../util/intel-pt.h"
#include <errno.h>
#include <stdbool.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
+
#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
#include <linux/log2.h>
+#include <linux/types.h>
#include <linux/zalloc.h>
-#include <linux/err.h>
-#include "../../../util/session.h"
+#include <api/fs/fs.h>
+#include <internal/lib.h> // page_size
+#include <subcmd/parse-options.h>
+
+#include "../../../util/auxtrace.h"
+#include "../../../util/config.h"
+#include "../../../util/cpumap.h"
+#include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/evlist.h"
#include "../../../util/evsel.h"
#include "../../../util/evsel_config.h"
-#include "../../../util/config.h"
-#include "../../../util/cpumap.h"
#include "../../../util/mmap.h"
-#include <subcmd/parse-options.h>
#include "../../../util/parse-events.h"
-#include "../../../util/pmus.h"
-#include "../../../util/debug.h"
-#include "../../../util/auxtrace.h"
#include "../../../util/perf_api_probe.h"
+#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
#include "../../../util/record.h"
+#include "../../../util/session.h"
#include "../../../util/target.h"
#include "../../../util/tsc.h"
-#include <internal/lib.h> // page_size
-#include "../../../util/intel-pt.h"
-#include <api/fs/fs.h>
#include "cpuid.h"
#define KiB(x) ((x) * 1024)
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 04/59] perf tests: Sort includes and add missed explicit dependencies
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Fix missing #includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/hwmon_pmu.c | 14 +++++++++-----
tools/perf/tests/mmap-basic.c | 18 +++++++++++-------
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
index 4aa4aac94f09..ada6e445c4c4 100644
--- a/tools/perf/tests/hwmon_pmu.c
+++ b/tools/perf/tests/hwmon_pmu.c
@@ -1,15 +1,19 @@
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
-#include "debug.h"
-#include "evlist.h"
#include "hwmon_pmu.h"
-#include "parse-events.h"
-#include "tests.h"
+
#include <errno.h>
+
#include <fcntl.h>
-#include <sys/stat.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <sys/stat.h>
+
+#include "debug.h"
+#include "evlist.h"
+#include "parse-events.h"
+#include "pmus.h"
+#include "tests.h"
static const struct test_event {
const char *name;
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 3313c236104e..8d04f6edb004 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -1,25 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
-#include <fcntl.h>
#include <inttypes.h>
#include <stdlib.h>
+
+#include <fcntl.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
#include <perf/cpumap.h>
+#include <perf/evlist.h>
+#include <perf/mmap.h>
#include "cpumap.h"
#include "debug.h"
#include "event.h"
#include "evlist.h"
#include "evsel.h"
-#include "thread_map.h"
+#include "pmu.h"
+#include "pmus.h"
#include "tests.h"
+#include "thread_map.h"
#include "util/affinity.h"
#include "util/mmap.h"
#include "util/sample.h"
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <perf/evlist.h>
-#include <perf/mmap.h>
/*
* This test will generate random numbers of calls to some getpid syscalls,
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 02/59] perf arch arm: Sort includes and add missed explicit dependencies
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
Fix missing #includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/arch/arm/util/cs-etm.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index b7a839de8707..cdf8e3e60606 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -3,10 +3,13 @@
* Copyright(C) 2015 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*/
+#include "../../../util/cs-etm.h"
+
+#include <errno.h>
+#include <stdlib.h>
-#include <api/fs/fs.h>
-#include <linux/bits.h>
#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/compiler.h>
#include <linux/coresight-pmu.h>
#include <linux/kernel.h>
@@ -14,25 +17,24 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/zalloc.h>
+#include <sys/stat.h>
+
+#include <api/fs/fs.h>
+#include <internal/lib.h> // page_size
-#include "cs-etm.h"
-#include "../../../util/debug.h"
-#include "../../../util/record.h"
#include "../../../util/auxtrace.h"
#include "../../../util/cpumap.h"
+#include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/evlist.h"
#include "../../../util/evsel.h"
-#include "../../../util/perf_api_probe.h"
#include "../../../util/evsel_config.h"
+#include "../../../util/perf_api_probe.h"
+#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
-#include "../../../util/cs-etm.h"
-#include <internal/lib.h> // page_size
+#include "../../../util/record.h"
#include "../../../util/session.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/stat.h>
+#include "cs-etm.h"
struct cs_etm_recording {
struct auxtrace_record itr;
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 00/59] perf: Reorganize scripting support
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425174858.3922152-1-irogers@google.com>
The perf script command has long supported running Python and Perl scripts by
embedding libpython and libperl. This approach has several drawbacks:
- overhead by creating Python dictionaries for every event (whether used or
not),
- complex build dependencies on specific Python/Perl versions,
- complications with threading due to perf being the interpreter,
- no clear way to run standalone scripts like ilist.py.
This series takes a different approach with some initial implementation posted
as an RFC last October:
https://lore.kernel.org/linux-perf-users/20251029053413.355154-1-irogers@google.com/
with the motivation coming up on the mailing list earlier:
https://lore.kernel.org/lkml/CAP-5=fWDqE8SYfOLZkg_0=4Ayx6E7O+h7uUp4NDeCFkiN4b7-w@mail.gmail.com/
The changes remove the embedded libpython and libperl support from perf
entirely. Instead, they expand the existing perf Python module to provide full
access to perf data files and events, allowing scripts to be run as standalone
Python applications.
To demonstrate the benefits, we ported all existing Python and Perl scripts to
use the new Python session API. The performance improvement is dramatic. For
example, porting mem-phys-addr.py:
Before (using embedded libpython in perf script):
```
$ perf mem record a sleep 1
$ time perf script tools/perf/scripts/python/mem-phys-addr.py
Event: cpu_core/mem-loads-aux/
Memory type count percentage
--------------------------------------- ---------- ----------
0-fff : Reserved 3217 100.0
real 0m3.754s
user 0m0.023s
sys 0m0.018s
```
After (using standalone Python script with perf module):
```
$ PYTHONPATH=/tmp/perf/python time python3 tools/perf/python/mem-phys-addr.py
Event: evsel(cpu_core/mem-loads-aux/)
Memory type count percentage
--------------------------------------- ---------- ----------
0-fff : Reserved 3217 100.0
real 0m0.106s
user 0m0.021s
sys 0m0.020s
```
This is a roughly 35x speedup!
The change is large (11291 insertions, 15964 deletions, net 4673
deletions) due to porting all existing perl and python code to the new
API. Gemini was used to achieve this and to improve the code
quality. Removing support may be controversial, however, the first 52
patches are additive and merging those would allow us to focus on the
remaining 6 patches that finalize the new perf script behavior.
---
v7 Changes
----------
- Fixed heap out-of-bounds in `pyrf_event__new` by adding comprehensive
size checks for all event types.
- Fixed undefined symbol `syscalltbl__id` when building without
libtraceevent by making `syscalltbl.o` unconditional in `Build`.
- Fixed several issues in `python.c`:
- Handled NULL return from `thread__comm_str` in `pyrf_thread__comm`.
- Avoided swallowing exceptions in module initialization.
- Added custom `tp_new` methods for `evlist`, `evsel`, and `data` types
to zero-initialize pointers and avoid crashes on re-initialization.
- Fixed lower priority review comments:
- Avoided permanent iterator exhaustion on `brstack` in
`perf_brstack_max.py` by converting it to a list.
- Removed dead code (unused `self.unhandled` dictionary) in
`failed-syscalls-by-pid.py`.
v6 Changes
----------
- Refactored `pyrf_event__new` to take `evsel` and `session` arguments,
and use dynamic allocation based on the actual event size to improve
memory safety and efficiency.
- Moved callchain and branch stack resolution logic from
`pyrf_session_tool__sample` into `pyrf_event__new`, centralizing
initialization.
- Added an optional keyword-only `elf_machine` argument to `syscall_name`
and `syscall_id` functions to allow specifying non-host architectures,
defaulting to `EM_HOST`.
- Renamed `process` method to `find_thread` in the Python API and C
implementation for better intention-revealing naming.
- Fixed a terminal injection vulnerability in `flamegraph.py` by not
printing unverified downloaded content in the prompt.
- Fixed CWD exposure and symlink attack risks in `gecko.py` by using a
secure temporary directory for the HTTP server.
- Fixed a severe performance issue in `event_analyzing_sample.py` by
removing SQLite autocommit mode and batching commits.
- Fixed `AttributeError` crashes in `rw-by-file.py` and `rw-by-pid.py` by
correctly extracting event names.
- Fixed man page formatting issues in `perf-script-python.txt` by using
indented code blocks.
- Updated `perf.pyi` stubs file to reflect all API changes.
- Verified all commit messages with `checkpatch.pl` and ensured lines are
wrapped appropriately.
- Fixed segmentation faults in `perf sched stats` in diff mode.
v5 Changes
----------
Resending due to partial send of v4 due to a quota limit.
v4 Changes
----------
1. Git Fixup Cleanups
- Squashed the lingering `fixup!` commit remaining from the previous session back
into `perf check-perf-trace: Port check-perf-trace to use python module`.
v3 Changes
----------
1. Memory Safety & Reference Counting Fixes
- Stored transient mmap event data inside the Python object's permanent
`pevent->event` and invoked `evsel__parse_sample()` to safely point
attributes into it, resolving Use-After-Free vulnerabilities.
- Nullified `sample->evsel` after calling `evsel__put()` in
`perf_sample__exit()` to protect against potential refcount double-put
crashes in error paths.
- Reordered operations inside `evlist__remove()` to invoke
`perf_evlist__remove()` before reference release.
- Patched an `evsel` reference leak inside `evlist__deliver_deferred_callchain()`.
2. Sashiko AI Review Cleanups
- Corrected the broken event name equality check in `gecko.py` to search
for a substring match within the parsed event string.
- Fixed a latent `AttributeError` crash in `task-analyzer.py` by properly
assigning the session instance.
- Safeguarded thread reporting in `check-perf-trace.py` by utilizing
`sample_tid` instead of `sample_pid`, and wrapping the session thread
resolution in a try-except block.
3. Omitted Minor Issues
- The minor review comments (such as permanent iterator exhaustion on
`brstack`, or dead-code in `failed-syscalls-by-pid.py`) have been omitted
because they do not affect correctness, lead to crashes, or require
significant architectural rework.
v2 Changes
----------
1. String Match and Event Name Accuracy
- Replaced loose substring event matching across the script suite with exact
matches or specific prefix constraints (syscalls:sys_exit_,
evsel(skb:kfree_skb), etc.).
- Added getattr() safety checks to prevent script failures caused by
unresolved attributes from older kernel traces.
2. OOM and Memory Protections
- Refactored netdev-times.py to compute and process network statistics
chronologically on-the-fly, eliminating an unbounded in-memory list
that caused Out-Of-Memory crashes on large files.
- Implemented threshold limits on intel-pt-events.py to cap memory allocation
during event interleaving.
- Optimized export-to-sqlite.py to periodically commit database transactions
(every 10,000 samples) to reduce temporary SQLite journal sizes.
3. Portability & Environment Independence
- Re-keyed internal tracking dictionaries in scripts like powerpc-hcalls.py to
use thread PIDs instead of CPUs, ensuring correctness when threads migrate.
- Switched net_dropmonitor.py from host-specific /proc/kallsyms parsing to
perf's built-in symbol resolution API.
- Added the --iomem parameter to mem-phys-addr.py to support offline analysis
of data collected on different architectures.
4. Standalone Scripting Improvements
- Patched builtin-script.c to ensure --input parameters are successfully passed
down to standalone execution pipelines via execvp().
- Guarded against string buffer overflows during .py extension path resolving.
5. Code Cleanups
- Removed stale perl subdirectories from being detected by the TUI script
browser.
- Ran the entire script suite through mypy and pylint to achieve strict static
type checking and resolve unreferenced variables.
Ian Rogers (59):
perf inject: Fix itrace branch stack synthesis
perf arch arm: Sort includes and add missed explicit dependencies
perf arch x86: Sort includes and add missed explicit dependencies
perf tests: Sort includes and add missed explicit dependencies
perf script: Sort includes and add missed explicit dependencies
perf util: Sort includes and add missed explicit dependencies
perf python: Add missed explicit dependencies
perf evsel/evlist: Avoid unnecessary #includes
perf data: Add open flag
perf evlist: Add reference count
perf evsel: Add reference count
perf evlist: Add reference count checking
perf python: Use evsel in sample in pyrf_event
perf python: Add wrapper for perf_data file abstraction
perf python: Add python session abstraction wrapping perf's session
perf python: Add syscall name/id to convert syscall number and name
perf python: Refactor and add accessors to sample event
perf python: Add callchain support
perf python: Add config file access
perf python: Extend API for stat events in python.c
perf python: Expose brstack in sample event
perf python: Add perf.pyi stubs file
perf python: Add LiveSession helper
perf python: Move exported-sql-viewer.py and parallel-perf.py to
tools/perf/python/
perf stat-cpi: Port stat-cpi to use python module
perf mem-phys-addr: Port mem-phys-addr to use python module
perf syscall-counts: Port syscall-counts to use python module
perf syscall-counts-by-pid: Port syscall-counts-by-pid to use python
module
perf futex-contention: Port futex-contention to use python module
perf flamegraph: Port flamegraph to use python module
perf gecko: Port gecko to use python module
perf arm-cs-trace-disasm: Port arm-cs-trace-disasm to use python
module
perf check-perf-trace: Port check-perf-trace to use python module
perf compaction-times: Port compaction-times to use python module
perf event_analyzing_sample: Port event_analyzing_sample to use python
module
perf export-to-sqlite: Port export-to-sqlite to use python module
perf export-to-postgresql: Port export-to-postgresql to use python
module
perf failed-syscalls-by-pid: Port failed-syscalls-by-pid to use python
module
perf intel-pt-events: Port intel-pt-events/libxed to use python module
perf net_dropmonitor: Port net_dropmonitor to use python module
perf netdev-times: Port netdev-times to use python module
perf powerpc-hcalls: Port powerpc-hcalls to use python module
perf sched-migration: Port sched-migration/SchedGui to use python
module
perf sctop: Port sctop to use python module
perf stackcollapse: Port stackcollapse to use python module
perf task-analyzer: Port task-analyzer to use python module
perf failed-syscalls: Port failed-syscalls to use python module
perf rw-by-file: Port rw-by-file to use python module
perf rw-by-pid: Port rw-by-pid to use python module
perf rwtop: Port rwtop to use python module
perf wakeup-latency: Port wakeup-latency to use python module
perf test: Migrate Intel PT virtual LBR test to use Python API
perf: Remove libperl support, legacy Perl scripts and tests
perf: Remove libpython support and legacy Python scripts
perf Makefile: Update Python script installation path
perf script: Refactor to support standalone scripts and remove legacy
features
perf Documentation: Update for standalone Python scripts and remove
obsolete data
perf python: Improve perf script -l descriptions
perf sched stats: Fix segmentation faults in diff mode
tools/build/Makefile.feature | 5 +-
tools/build/feature/Makefile | 23 +-
tools/build/feature/test-all.c | 6 +-
tools/build/feature/test-libperl.c | 10 -
tools/build/feature/test-libpython.c | 10 -
tools/build/feature/test-python-module.c | 12 +
tools/perf/Documentation/perf-check.txt | 2 -
tools/perf/Documentation/perf-script-perl.txt | 216 --
.../perf/Documentation/perf-script-python.txt | 713 +-----
tools/perf/Documentation/perf-script.txt | 70 +-
tools/perf/Makefile.config | 37 +-
tools/perf/Makefile.perf | 22 +-
tools/perf/arch/arm/util/cs-etm.c | 36 +-
tools/perf/arch/arm64/util/arm-spe.c | 8 +-
tools/perf/arch/arm64/util/hisi-ptt.c | 2 +-
tools/perf/arch/x86/tests/hybrid.c | 22 +-
tools/perf/arch/x86/tests/topdown.c | 2 +-
tools/perf/arch/x86/util/auxtrace.c | 2 +-
tools/perf/arch/x86/util/intel-bts.c | 26 +-
tools/perf/arch/x86/util/intel-pt.c | 38 +-
tools/perf/arch/x86/util/iostat.c | 8 +-
tools/perf/bench/evlist-open-close.c | 29 +-
tools/perf/bench/inject-buildid.c | 9 +-
tools/perf/builtin-annotate.c | 2 +-
tools/perf/builtin-check.c | 3 +-
tools/perf/builtin-ftrace.c | 14 +-
tools/perf/builtin-inject.c | 81 +-
tools/perf/builtin-kvm.c | 14 +-
tools/perf/builtin-kwork.c | 8 +-
tools/perf/builtin-lock.c | 2 +-
tools/perf/builtin-record.c | 95 +-
tools/perf/builtin-report.c | 6 +-
tools/perf/builtin-sched.c | 111 +-
tools/perf/builtin-script.c | 895 +++----
tools/perf/builtin-stat.c | 81 +-
tools/perf/builtin-top.c | 104 +-
tools/perf/builtin-trace.c | 60 +-
tools/perf/python/SchedGui.py | 219 ++
tools/perf/python/arm-cs-trace-disasm.py | 338 +++
tools/perf/python/check-perf-trace.py | 113 +
tools/perf/python/compaction-times.py | 326 +++
tools/perf/python/counting.py | 1 +
tools/perf/python/event_analyzing_sample.py | 297 +++
tools/perf/python/export-to-postgresql.py | 701 ++++++
tools/perf/python/export-to-sqlite.py | 372 +++
.../python/exported-sql-viewer.py | 6 +-
tools/perf/python/failed-syscalls-by-pid.py | 116 +
tools/perf/python/failed-syscalls.py | 78 +
tools/perf/python/flamegraph.py | 250 ++
tools/perf/python/futex-contention.py | 87 +
tools/perf/python/gecko.py | 385 +++
tools/perf/python/intel-pt-events.py | 435 ++++
tools/perf/python/libxed.py | 122 +
.../{scripts => }/python/mem-phys-addr.py | 66 +-
tools/perf/python/net_dropmonitor.py | 58 +
tools/perf/python/netdev-times.py | 472 ++++
.../{scripts => }/python/parallel-perf.py | 0
tools/perf/python/perf.pyi | 581 +++++
tools/perf/python/perf_live.py | 48 +
tools/perf/python/powerpc-hcalls.py | 211 ++
tools/perf/python/rw-by-file.py | 103 +
tools/perf/python/rw-by-pid.py | 158 ++
tools/perf/python/rwtop.py | 219 ++
tools/perf/python/sched-migration.py | 469 ++++
tools/perf/python/sctop.py | 186 ++
tools/perf/python/stackcollapse.py | 126 +
tools/perf/python/stat-cpi.py | 151 ++
tools/perf/python/syscall-counts-by-pid.py | 88 +
tools/perf/python/syscall-counts.py | 72 +
tools/perf/python/task-analyzer.py | 547 ++++
tools/perf/python/tracepoint.py | 1 +
tools/perf/python/twatch.py | 1 +
tools/perf/python/wakeup-latency.py | 88 +
tools/perf/scripts/Build | 4 -
tools/perf/scripts/perl/Perf-Trace-Util/Build | 9 -
.../scripts/perl/Perf-Trace-Util/Context.c | 122 -
.../scripts/perl/Perf-Trace-Util/Context.xs | 42 -
.../scripts/perl/Perf-Trace-Util/Makefile.PL | 18 -
.../perf/scripts/perl/Perf-Trace-Util/README | 59 -
.../Perf-Trace-Util/lib/Perf/Trace/Context.pm | 55 -
.../Perf-Trace-Util/lib/Perf/Trace/Core.pm | 192 --
.../Perf-Trace-Util/lib/Perf/Trace/Util.pm | 94 -
.../perf/scripts/perl/Perf-Trace-Util/typemap | 1 -
.../scripts/perl/bin/check-perf-trace-record | 2 -
.../scripts/perl/bin/failed-syscalls-record | 3 -
.../scripts/perl/bin/failed-syscalls-report | 10 -
tools/perf/scripts/perl/bin/rw-by-file-record | 3 -
tools/perf/scripts/perl/bin/rw-by-file-report | 10 -
tools/perf/scripts/perl/bin/rw-by-pid-record | 2 -
tools/perf/scripts/perl/bin/rw-by-pid-report | 3 -
tools/perf/scripts/perl/bin/rwtop-record | 2 -
tools/perf/scripts/perl/bin/rwtop-report | 20 -
.../scripts/perl/bin/wakeup-latency-record | 6 -
.../scripts/perl/bin/wakeup-latency-report | 3 -
tools/perf/scripts/perl/check-perf-trace.pl | 106 -
tools/perf/scripts/perl/failed-syscalls.pl | 47 -
tools/perf/scripts/perl/rw-by-file.pl | 106 -
tools/perf/scripts/perl/rw-by-pid.pl | 184 --
tools/perf/scripts/perl/rwtop.pl | 203 --
tools/perf/scripts/perl/wakeup-latency.pl | 107 -
.../perf/scripts/python/Perf-Trace-Util/Build | 4 -
.../scripts/python/Perf-Trace-Util/Context.c | 225 --
.../Perf-Trace-Util/lib/Perf/Trace/Core.py | 116 -
.../lib/Perf/Trace/EventClass.py | 97 -
.../lib/Perf/Trace/SchedGui.py | 184 --
.../Perf-Trace-Util/lib/Perf/Trace/Util.py | 92 -
.../scripts/python/arm-cs-trace-disasm.py | 355 ---
.../python/bin/compaction-times-record | 2 -
.../python/bin/compaction-times-report | 4 -
.../python/bin/event_analyzing_sample-record | 8 -
.../python/bin/event_analyzing_sample-report | 3 -
.../python/bin/export-to-postgresql-record | 8 -
.../python/bin/export-to-postgresql-report | 29 -
.../python/bin/export-to-sqlite-record | 8 -
.../python/bin/export-to-sqlite-report | 29 -
.../python/bin/failed-syscalls-by-pid-record | 3 -
.../python/bin/failed-syscalls-by-pid-report | 10 -
.../perf/scripts/python/bin/flamegraph-record | 2 -
.../perf/scripts/python/bin/flamegraph-report | 3 -
.../python/bin/futex-contention-record | 2 -
.../python/bin/futex-contention-report | 4 -
tools/perf/scripts/python/bin/gecko-record | 2 -
tools/perf/scripts/python/bin/gecko-report | 7 -
.../scripts/python/bin/intel-pt-events-record | 13 -
.../scripts/python/bin/intel-pt-events-report | 3 -
.../scripts/python/bin/mem-phys-addr-record | 19 -
.../scripts/python/bin/mem-phys-addr-report | 3 -
.../scripts/python/bin/net_dropmonitor-record | 2 -
.../scripts/python/bin/net_dropmonitor-report | 4 -
.../scripts/python/bin/netdev-times-record | 8 -
.../scripts/python/bin/netdev-times-report | 5 -
.../scripts/python/bin/powerpc-hcalls-record | 2 -
.../scripts/python/bin/powerpc-hcalls-report | 2 -
.../scripts/python/bin/sched-migration-record | 2 -
.../scripts/python/bin/sched-migration-report | 3 -
tools/perf/scripts/python/bin/sctop-record | 3 -
tools/perf/scripts/python/bin/sctop-report | 24 -
.../scripts/python/bin/stackcollapse-record | 8 -
.../scripts/python/bin/stackcollapse-report | 3 -
.../python/bin/syscall-counts-by-pid-record | 3 -
.../python/bin/syscall-counts-by-pid-report | 10 -
.../scripts/python/bin/syscall-counts-record | 3 -
.../scripts/python/bin/syscall-counts-report | 10 -
.../scripts/python/bin/task-analyzer-record | 2 -
.../scripts/python/bin/task-analyzer-report | 3 -
tools/perf/scripts/python/check-perf-trace.py | 84 -
tools/perf/scripts/python/compaction-times.py | 311 ---
.../scripts/python/event_analyzing_sample.py | 192 --
.../scripts/python/export-to-postgresql.py | 1114 ---------
tools/perf/scripts/python/export-to-sqlite.py | 799 ------
.../scripts/python/failed-syscalls-by-pid.py | 79 -
tools/perf/scripts/python/flamegraph.py | 267 --
tools/perf/scripts/python/futex-contention.py | 57 -
tools/perf/scripts/python/gecko.py | 395 ---
tools/perf/scripts/python/intel-pt-events.py | 494 ----
tools/perf/scripts/python/libxed.py | 107 -
tools/perf/scripts/python/net_dropmonitor.py | 78 -
tools/perf/scripts/python/netdev-times.py | 473 ----
tools/perf/scripts/python/powerpc-hcalls.py | 202 --
tools/perf/scripts/python/sched-migration.py | 462 ----
tools/perf/scripts/python/sctop.py | 89 -
tools/perf/scripts/python/stackcollapse.py | 127 -
tools/perf/scripts/python/stat-cpi.py | 79 -
.../scripts/python/syscall-counts-by-pid.py | 75 -
tools/perf/scripts/python/syscall-counts.py | 65 -
tools/perf/scripts/python/task-analyzer.py | 934 -------
tools/perf/tests/backward-ring-buffer.c | 26 +-
tools/perf/tests/code-reading.c | 14 +-
tools/perf/tests/dlfilter-test.c | 8 +-
tools/perf/tests/event-times.c | 6 +-
tools/perf/tests/event_update.c | 4 +-
tools/perf/tests/evsel-roundtrip-name.c | 8 +-
tools/perf/tests/evsel-tp-sched.c | 4 +-
tools/perf/tests/expand-cgroup.c | 12 +-
tools/perf/tests/hists_cumulate.c | 2 +-
tools/perf/tests/hists_filter.c | 2 +-
tools/perf/tests/hists_link.c | 2 +-
tools/perf/tests/hists_output.c | 2 +-
tools/perf/tests/hwmon_pmu.c | 21 +-
tools/perf/tests/keep-tracking.c | 10 +-
tools/perf/tests/make | 9 +-
tools/perf/tests/mmap-basic.c | 42 +-
tools/perf/tests/openat-syscall-all-cpus.c | 6 +-
tools/perf/tests/openat-syscall-tp-fields.c | 26 +-
tools/perf/tests/openat-syscall.c | 6 +-
tools/perf/tests/parse-events.c | 139 +-
tools/perf/tests/parse-metric.c | 8 +-
tools/perf/tests/parse-no-sample-id-all.c | 2 +-
tools/perf/tests/perf-record.c | 38 +-
tools/perf/tests/perf-time-to-tsc.c | 12 +-
tools/perf/tests/pfm.c | 12 +-
tools/perf/tests/pmu-events.c | 11 +-
tools/perf/tests/pmu.c | 4 +-
tools/perf/tests/sample-parsing.c | 39 +-
.../perf/tests/shell/lib/perf_brstack_max.py | 43 +
tools/perf/tests/shell/script.sh | 4 +-
tools/perf/tests/shell/script_perl.sh | 102 -
tools/perf/tests/shell/script_python.sh | 113 -
.../tests/shell/test_arm_coresight_disasm.sh | 12 +-
tools/perf/tests/shell/test_intel_pt.sh | 35 +-
tools/perf/tests/shell/test_task_analyzer.sh | 79 +-
tools/perf/tests/sw-clock.c | 20 +-
tools/perf/tests/switch-tracking.c | 10 +-
tools/perf/tests/task-exit.c | 20 +-
tools/perf/tests/time-utils-test.c | 14 +-
tools/perf/tests/tool_pmu.c | 7 +-
tools/perf/tests/topology.c | 4 +-
tools/perf/ui/browsers/annotate.c | 2 +-
tools/perf/ui/browsers/hists.c | 22 +-
tools/perf/ui/browsers/scripts.c | 21 +-
tools/perf/util/Build | 3 +-
tools/perf/util/amd-sample-raw.c | 2 +-
tools/perf/util/annotate-data.c | 2 +-
tools/perf/util/annotate.c | 10 +-
tools/perf/util/arm-spe.c | 7 +-
tools/perf/util/auxtrace.c | 14 +-
tools/perf/util/block-info.c | 4 +-
tools/perf/util/bpf_counter.c | 2 +-
tools/perf/util/bpf_counter_cgroup.c | 10 +-
tools/perf/util/bpf_ftrace.c | 9 +-
tools/perf/util/bpf_lock_contention.c | 12 +-
tools/perf/util/bpf_off_cpu.c | 44 +-
tools/perf/util/bpf_trace_augment.c | 8 +-
tools/perf/util/cgroup.c | 26 +-
tools/perf/util/cs-etm.c | 6 +-
tools/perf/util/data-convert-bt.c | 2 +-
tools/perf/util/data.c | 26 +-
tools/perf/util/data.h | 4 +-
tools/perf/util/evlist.c | 487 ++--
tools/perf/util/evlist.h | 273 +-
tools/perf/util/evsel.c | 109 +-
tools/perf/util/evsel.h | 35 +-
tools/perf/util/expr.c | 2 +-
tools/perf/util/header.c | 51 +-
tools/perf/util/header.h | 2 +-
tools/perf/util/intel-bts.c | 3 +-
tools/perf/util/intel-pt.c | 13 +-
tools/perf/util/intel-tpebs.c | 7 +-
tools/perf/util/map.h | 9 +-
tools/perf/util/metricgroup.c | 12 +-
tools/perf/util/parse-events.c | 10 +-
tools/perf/util/parse-events.y | 2 +-
tools/perf/util/perf_api_probe.c | 20 +-
tools/perf/util/pfm.c | 4 +-
tools/perf/util/print-events.c | 2 +-
tools/perf/util/print_insn.h | 5 +-
tools/perf/util/python.c | 2098 ++++++++++++++--
tools/perf/util/record.c | 11 +-
tools/perf/util/s390-sample-raw.c | 19 +-
tools/perf/util/sample-raw.c | 4 +-
tools/perf/util/sample.c | 17 +-
tools/perf/util/scripting-engines/Build | 9 -
.../util/scripting-engines/trace-event-perl.c | 773 ------
.../scripting-engines/trace-event-python.c | 2209 -----------------
tools/perf/util/session.c | 59 +-
tools/perf/util/sideband_evlist.c | 40 +-
tools/perf/util/sort.c | 2 +-
tools/perf/util/stat-display.c | 6 +-
tools/perf/util/stat-shadow.c | 24 +-
tools/perf/util/stat.c | 20 +-
tools/perf/util/stream.c | 4 +-
tools/perf/util/synthetic-events.c | 36 +-
tools/perf/util/synthetic-events.h | 6 +-
tools/perf/util/time-utils.c | 12 +-
tools/perf/util/top.c | 4 +-
tools/perf/util/trace-event-parse.c | 65 -
tools/perf/util/trace-event-scripting.c | 410 ---
tools/perf/util/trace-event.h | 75 +-
268 files changed, 11592 insertions(+), 16034 deletions(-)
delete mode 100644 tools/build/feature/test-libperl.c
delete mode 100644 tools/build/feature/test-libpython.c
create mode 100644 tools/build/feature/test-python-module.c
delete mode 100644 tools/perf/Documentation/perf-script-perl.txt
create mode 100755 tools/perf/python/SchedGui.py
create mode 100755 tools/perf/python/arm-cs-trace-disasm.py
create mode 100755 tools/perf/python/check-perf-trace.py
create mode 100755 tools/perf/python/compaction-times.py
create mode 100755 tools/perf/python/event_analyzing_sample.py
create mode 100755 tools/perf/python/export-to-postgresql.py
create mode 100755 tools/perf/python/export-to-sqlite.py
rename tools/perf/{scripts => }/python/exported-sql-viewer.py (99%)
create mode 100755 tools/perf/python/failed-syscalls-by-pid.py
create mode 100755 tools/perf/python/failed-syscalls.py
create mode 100755 tools/perf/python/flamegraph.py
create mode 100755 tools/perf/python/futex-contention.py
create mode 100755 tools/perf/python/gecko.py
create mode 100755 tools/perf/python/intel-pt-events.py
create mode 100755 tools/perf/python/libxed.py
rename tools/perf/{scripts => }/python/mem-phys-addr.py (73%)
mode change 100644 => 100755
create mode 100755 tools/perf/python/net_dropmonitor.py
create mode 100755 tools/perf/python/netdev-times.py
rename tools/perf/{scripts => }/python/parallel-perf.py (100%)
create mode 100644 tools/perf/python/perf.pyi
create mode 100755 tools/perf/python/perf_live.py
create mode 100755 tools/perf/python/powerpc-hcalls.py
create mode 100755 tools/perf/python/rw-by-file.py
create mode 100755 tools/perf/python/rw-by-pid.py
create mode 100755 tools/perf/python/rwtop.py
create mode 100755 tools/perf/python/sched-migration.py
create mode 100755 tools/perf/python/sctop.py
create mode 100755 tools/perf/python/stackcollapse.py
create mode 100755 tools/perf/python/stat-cpi.py
create mode 100755 tools/perf/python/syscall-counts-by-pid.py
create mode 100755 tools/perf/python/syscall-counts.py
create mode 100755 tools/perf/python/task-analyzer.py
create mode 100755 tools/perf/python/wakeup-latency.py
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Build
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Context.c
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/README
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/typemap
delete mode 100644 tools/perf/scripts/perl/bin/check-perf-trace-record
delete mode 100644 tools/perf/scripts/perl/bin/failed-syscalls-record
delete mode 100644 tools/perf/scripts/perl/bin/failed-syscalls-report
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-file-record
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-file-report
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-pid-record
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-pid-report
delete mode 100644 tools/perf/scripts/perl/bin/rwtop-record
delete mode 100644 tools/perf/scripts/perl/bin/rwtop-report
delete mode 100644 tools/perf/scripts/perl/bin/wakeup-latency-record
delete mode 100644 tools/perf/scripts/perl/bin/wakeup-latency-report
delete mode 100644 tools/perf/scripts/perl/check-perf-trace.pl
delete mode 100644 tools/perf/scripts/perl/failed-syscalls.pl
delete mode 100644 tools/perf/scripts/perl/rw-by-file.pl
delete mode 100644 tools/perf/scripts/perl/rw-by-pid.pl
delete mode 100644 tools/perf/scripts/perl/rwtop.pl
delete mode 100644 tools/perf/scripts/perl/wakeup-latency.pl
delete mode 100644 tools/perf/scripts/python/Perf-Trace-Util/Build
delete mode 100644 tools/perf/scripts/python/Perf-Trace-Util/Context.c
delete mode 100644 tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
delete mode 100755 tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py
delete mode 100644 tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
delete mode 100644 tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
delete mode 100755 tools/perf/scripts/python/arm-cs-trace-disasm.py
delete mode 100644 tools/perf/scripts/python/bin/compaction-times-record
delete mode 100644 tools/perf/scripts/python/bin/compaction-times-report
delete mode 100644 tools/perf/scripts/python/bin/event_analyzing_sample-record
delete mode 100644 tools/perf/scripts/python/bin/event_analyzing_sample-report
delete mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-record
delete mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-report
delete mode 100644 tools/perf/scripts/python/bin/export-to-sqlite-record
delete mode 100644 tools/perf/scripts/python/bin/export-to-sqlite-report
delete mode 100644 tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
delete mode 100644 tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
delete mode 100755 tools/perf/scripts/python/bin/flamegraph-record
delete mode 100755 tools/perf/scripts/python/bin/flamegraph-report
delete mode 100644 tools/perf/scripts/python/bin/futex-contention-record
delete mode 100644 tools/perf/scripts/python/bin/futex-contention-report
delete mode 100644 tools/perf/scripts/python/bin/gecko-record
delete mode 100755 tools/perf/scripts/python/bin/gecko-report
delete mode 100644 tools/perf/scripts/python/bin/intel-pt-events-record
delete mode 100644 tools/perf/scripts/python/bin/intel-pt-events-report
delete mode 100644 tools/perf/scripts/python/bin/mem-phys-addr-record
delete mode 100644 tools/perf/scripts/python/bin/mem-phys-addr-report
delete mode 100755 tools/perf/scripts/python/bin/net_dropmonitor-record
delete mode 100755 tools/perf/scripts/python/bin/net_dropmonitor-report
delete mode 100644 tools/perf/scripts/python/bin/netdev-times-record
delete mode 100644 tools/perf/scripts/python/bin/netdev-times-report
delete mode 100644 tools/perf/scripts/python/bin/powerpc-hcalls-record
delete mode 100644 tools/perf/scripts/python/bin/powerpc-hcalls-report
delete mode 100644 tools/perf/scripts/python/bin/sched-migration-record
delete mode 100644 tools/perf/scripts/python/bin/sched-migration-report
delete mode 100644 tools/perf/scripts/python/bin/sctop-record
delete mode 100644 tools/perf/scripts/python/bin/sctop-report
delete mode 100755 tools/perf/scripts/python/bin/stackcollapse-record
delete mode 100755 tools/perf/scripts/python/bin/stackcollapse-report
delete mode 100644 tools/perf/scripts/python/bin/syscall-counts-by-pid-record
delete mode 100644 tools/perf/scripts/python/bin/syscall-counts-by-pid-report
delete mode 100644 tools/perf/scripts/python/bin/syscall-counts-record
delete mode 100644 tools/perf/scripts/python/bin/syscall-counts-report
delete mode 100755 tools/perf/scripts/python/bin/task-analyzer-record
delete mode 100755 tools/perf/scripts/python/bin/task-analyzer-report
delete mode 100644 tools/perf/scripts/python/check-perf-trace.py
delete mode 100644 tools/perf/scripts/python/compaction-times.py
delete mode 100644 tools/perf/scripts/python/event_analyzing_sample.py
delete mode 100644 tools/perf/scripts/python/export-to-postgresql.py
delete mode 100644 tools/perf/scripts/python/export-to-sqlite.py
delete mode 100644 tools/perf/scripts/python/failed-syscalls-by-pid.py
delete mode 100755 tools/perf/scripts/python/flamegraph.py
delete mode 100644 tools/perf/scripts/python/futex-contention.py
delete mode 100644 tools/perf/scripts/python/gecko.py
delete mode 100644 tools/perf/scripts/python/intel-pt-events.py
delete mode 100644 tools/perf/scripts/python/libxed.py
delete mode 100755 tools/perf/scripts/python/net_dropmonitor.py
delete mode 100644 tools/perf/scripts/python/netdev-times.py
delete mode 100644 tools/perf/scripts/python/powerpc-hcalls.py
delete mode 100644 tools/perf/scripts/python/sched-migration.py
delete mode 100644 tools/perf/scripts/python/sctop.py
delete mode 100755 tools/perf/scripts/python/stackcollapse.py
delete mode 100644 tools/perf/scripts/python/stat-cpi.py
delete mode 100644 tools/perf/scripts/python/syscall-counts-by-pid.py
delete mode 100644 tools/perf/scripts/python/syscall-counts.py
delete mode 100755 tools/perf/scripts/python/task-analyzer.py
create mode 100644 tools/perf/tests/shell/lib/perf_brstack_max.py
delete mode 100755 tools/perf/tests/shell/script_perl.sh
delete mode 100755 tools/perf/tests/shell/script_python.sh
delete mode 100644 tools/perf/util/scripting-engines/Build
delete mode 100644 tools/perf/util/scripting-engines/trace-event-perl.c
delete mode 100644 tools/perf/util/scripting-engines/trace-event-python.c
delete mode 100644 tools/perf/util/trace-event-scripting.c
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply
* [PATCH v7 01/59] perf inject: Fix itrace branch stack synthesis
From: Ian Rogers @ 2026-04-25 22:48 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224951.174663-1-irogers@google.com>
When using "perf inject --itrace=L" to synthesize branch stacks from
AUX data, several issues caused failures:
1. The synthesized samples were delivered without the
PERF_SAMPLE_BRANCH_STACK flag if it was not in the original event's
sample_type. Fixed by using sample_type | evsel->synth_sample_type
in intel_pt_deliver_synth_event.
2. The record layout was misaligned because of inconsistent handling
of PERF_SAMPLE_BRANCH_HW_INDEX. Fixed by explicitly writing nr and
hw_idx in perf_event__synthesize_sample.
3. Modifying evsel->core.attr.sample_type early in __cmd_inject caused
parse failures for subsequent records in the input file. Fixed by
moving this modification to just before writing the header.
4. perf_event__repipe_sample was narrowed to only synthesize samples
when branch stack injection was requested, and restored the use of
perf_inject__cut_auxtrace_sample as a fallback to preserve
functionality.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
Issues fixed in v2:
1. Potential Heap Overflow in perf_event__repipe_sample : Addressed by
adding a check that prints an error and returns -EFAULT if the
calculated event size exceeds PERF_SAMPLE_MAX_SIZE , as you
requested.
2. Header vs Payload Mismatch in __cmd_inject : Addressed by narrowing
the condition so that HEADER_BRANCH_STACK is only set in the file
header if add_last_branch was true.
3. NULL Pointer Dereference in intel-pt.c : Addressed by updating the
condition in intel_pt_do_synth_pebs_sample to fill sample.
branch_stack if it was synthesized, even if not in the original
sample_type .
4. Unsafe Reads for events lacking HW_INDEX in synthetic-events.c :
Addressed by using the perf_sample__branch_entries() macro and
checking sample->no_hw_idx .
5. Size mismatch in perf_event__sample_event_size : Addressed by
passing branch_sample_type to it and conditioning the hw_idx size on
PERF_SAMPLE_BRANCH_HW_INDEX .
---
tools/perf/bench/inject-buildid.c | 9 ++--
tools/perf/builtin-inject.c | 77 ++++++++++++++++++++++++++++--
tools/perf/tests/dlfilter-test.c | 8 +++-
tools/perf/tests/sample-parsing.c | 5 +-
tools/perf/util/arm-spe.c | 7 ++-
tools/perf/util/cs-etm.c | 6 ++-
tools/perf/util/intel-bts.c | 3 +-
tools/perf/util/intel-pt.c | 13 +++--
tools/perf/util/synthetic-events.c | 25 +++++++---
tools/perf/util/synthetic-events.h | 6 ++-
10 files changed, 129 insertions(+), 30 deletions(-)
diff --git a/tools/perf/bench/inject-buildid.c b/tools/perf/bench/inject-buildid.c
index aad572a78d7f..bfd2c5ec9488 100644
--- a/tools/perf/bench/inject-buildid.c
+++ b/tools/perf/bench/inject-buildid.c
@@ -228,9 +228,12 @@ static ssize_t synthesize_sample(struct bench_data *data, struct bench_dso *dso,
event.header.type = PERF_RECORD_SAMPLE;
event.header.misc = PERF_RECORD_MISC_USER;
- event.header.size = perf_event__sample_event_size(&sample, bench_sample_type, 0);
-
- perf_event__synthesize_sample(&event, bench_sample_type, 0, &sample);
+ event.header.size = perf_event__sample_event_size(&sample, bench_sample_type,
+ /*read_format=*/0,
+ /*branch_sample_type=*/0);
+ perf_event__synthesize_sample(&event, bench_sample_type,
+ /*read_format=*/0,
+ /*branch_sample_type=*/0, &sample);
return writen(data->input_pipe[1], &event, event.header.size);
}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index f174bc69cec4..88c0ef4f5ff1 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -375,7 +375,59 @@ static int perf_event__repipe_sample(const struct perf_tool *tool,
build_id__mark_dso_hit(tool, event, sample, evsel, machine);
- if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
+ if (inject->itrace_synth_opts.set &&
+ (inject->itrace_synth_opts.last_branch ||
+ inject->itrace_synth_opts.add_last_branch)) {
+ union perf_event *event_copy = (void *)inject->event_copy;
+ struct branch_stack dummy_bs = { .nr = 0 };
+ int err;
+ size_t sz;
+ u64 orig_type = evsel->core.attr.sample_type;
+ u64 orig_branch_type = evsel->core.attr.branch_sample_type;
+
+ if (event_copy == NULL) {
+ inject->event_copy = malloc(PERF_SAMPLE_MAX_SIZE);
+ if (!inject->event_copy)
+ return -ENOMEM;
+
+ event_copy = (void *)inject->event_copy;
+ }
+
+ if (!sample->branch_stack)
+ sample->branch_stack = &dummy_bs;
+
+ if (inject->itrace_synth_opts.add_last_branch) {
+ /* Temporarily add in type bits for synthesis. */
+ evsel->core.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+ evsel->core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
+ evsel->core.attr.sample_type &= ~PERF_SAMPLE_AUX;
+ }
+
+ sz = perf_event__sample_event_size(sample, evsel->core.attr.sample_type,
+ evsel->core.attr.read_format,
+ evsel->core.attr.branch_sample_type);
+
+ if (sz > PERF_SAMPLE_MAX_SIZE) {
+ pr_err("Sample size %zu exceeds max size %d\n", sz, PERF_SAMPLE_MAX_SIZE);
+ return -EFAULT;
+ }
+
+ event_copy->header.type = PERF_RECORD_SAMPLE;
+ event_copy->header.size = sz;
+
+ err = perf_event__synthesize_sample(event_copy, evsel->core.attr.sample_type,
+ evsel->core.attr.read_format,
+ evsel->core.attr.branch_sample_type, sample);
+
+ evsel->core.attr.sample_type = orig_type;
+ evsel->core.attr.branch_sample_type = orig_branch_type;
+
+ if (err) {
+ pr_err("Failed to synthesize sample\n");
+ return err;
+ }
+ event = event_copy;
+ } else if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
event = perf_inject__cut_auxtrace_sample(inject, event, sample);
if (IS_ERR(event))
return PTR_ERR(event);
@@ -464,7 +516,8 @@ static int perf_event__convert_sample_callchain(const struct perf_tool *tool,
sample_type &= ~(PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER);
perf_event__synthesize_sample(event_copy, sample_type,
- evsel->core.attr.read_format, sample);
+ evsel->core.attr.read_format,
+ evsel->core.attr.branch_sample_type, sample);
return perf_event__repipe_synth(tool, event_copy);
}
@@ -1100,7 +1153,8 @@ static int perf_inject__sched_stat(const struct perf_tool *tool,
sample_sw.period = sample->period;
sample_sw.time = sample->time;
perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type,
- evsel->core.attr.read_format, &sample_sw);
+ evsel->core.attr.read_format,
+ evsel->core.attr.branch_sample_type, &sample_sw);
build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
ret = perf_event__repipe(tool, event_sw, &sample_sw, machine);
perf_sample__exit(&sample_sw);
@@ -2434,12 +2488,25 @@ static int __cmd_inject(struct perf_inject *inject)
* synthesized hardware events, so clear the feature flag.
*/
if (inject->itrace_synth_opts.set) {
+ struct evsel *evsel;
+
perf_header__clear_feat(&session->header,
HEADER_AUXTRACE);
- if (inject->itrace_synth_opts.last_branch ||
- inject->itrace_synth_opts.add_last_branch)
+
+ evlist__for_each_entry(session->evlist, evsel) {
+ evsel->core.attr.sample_type &= ~PERF_SAMPLE_AUX;
+ }
+
+ if (inject->itrace_synth_opts.add_last_branch) {
perf_header__set_feat(&session->header,
HEADER_BRANCH_STACK);
+
+ evlist__for_each_entry(session->evlist, evsel) {
+ evsel->core.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+ evsel->core.attr.branch_sample_type |=
+ PERF_SAMPLE_BRANCH_HW_INDEX;
+ }
+ }
}
/*
diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c
index e63790c61d53..204663571943 100644
--- a/tools/perf/tests/dlfilter-test.c
+++ b/tools/perf/tests/dlfilter-test.c
@@ -188,8 +188,12 @@ static int write_sample(struct test_data *td, u64 sample_type, u64 id, pid_t pid
event->header.type = PERF_RECORD_SAMPLE;
event->header.misc = PERF_RECORD_MISC_USER;
- event->header.size = perf_event__sample_event_size(&sample, sample_type, 0);
- err = perf_event__synthesize_sample(event, sample_type, 0, &sample);
+ event->header.size = perf_event__sample_event_size(&sample, sample_type,
+ /*read_format=*/0,
+ /*branch_sample_type=*/0);
+ err = perf_event__synthesize_sample(event, sample_type,
+ /*read_format=*/0,
+ /*branch_sample_type=*/0, &sample);
if (err)
return test_result("perf_event__synthesize_sample() failed", TEST_FAIL);
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index a7327c942ca2..55f0b73ca20e 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -310,7 +310,8 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
sample.read.one.lost = 1;
}
- sz = perf_event__sample_event_size(&sample, sample_type, read_format);
+ sz = perf_event__sample_event_size(&sample, sample_type, read_format,
+ evsel.core.attr.branch_sample_type);
bufsz = sz + 4096; /* Add a bit for overrun checking */
event = malloc(bufsz);
if (!event) {
@@ -324,7 +325,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
event->header.size = sz;
err = perf_event__synthesize_sample(event, sample_type, read_format,
- &sample);
+ evsel.core.attr.branch_sample_type, &sample);
if (err) {
pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
"perf_event__synthesize_sample", sample_type, err);
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
index e5835042acdf..c4ed9f10e731 100644
--- a/tools/perf/util/arm-spe.c
+++ b/tools/perf/util/arm-spe.c
@@ -484,8 +484,11 @@ static void arm_spe__prep_branch_stack(struct arm_spe_queue *speq)
static int arm_spe__inject_event(union perf_event *event, struct perf_sample *sample, u64 type)
{
- event->header.size = perf_event__sample_event_size(sample, type, 0);
- return perf_event__synthesize_sample(event, type, 0, sample);
+ event->header.type = PERF_RECORD_SAMPLE;
+ event->header.size = perf_event__sample_event_size(sample, type, /*read_format=*/0,
+ /*branch_sample_type=*/0);
+ return perf_event__synthesize_sample(event, type, /*read_format=*/0,
+ /*branch_sample_type=*/0, sample);
}
static inline int
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 8a639d2e51a4..1ebc1a6a5e75 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -1425,8 +1425,10 @@ static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
static int cs_etm__inject_event(union perf_event *event,
struct perf_sample *sample, u64 type)
{
- event->header.size = perf_event__sample_event_size(sample, type, 0);
- return perf_event__synthesize_sample(event, type, 0, sample);
+ event->header.size = perf_event__sample_event_size(sample, type, /*read_format=*/0,
+ /*branch_sample_type=*/0);
+ return perf_event__synthesize_sample(event, type, /*read_format=*/0,
+ /*branch_sample_type=*/0, sample);
}
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
index 382255393fb3..0b18ebd13f7c 100644
--- a/tools/perf/util/intel-bts.c
+++ b/tools/perf/util/intel-bts.c
@@ -303,7 +303,8 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
event.sample.header.size = bts->branches_event_size;
ret = perf_event__synthesize_sample(&event,
bts->branches_sample_type,
- 0, &sample);
+ /*read_format=*/0, /*branch_sample_type=*/0,
+ &sample);
if (ret)
return ret;
}
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index fc9eec8b54b8..2dce6106c038 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -1731,8 +1731,12 @@ static void intel_pt_prep_b_sample(struct intel_pt *pt,
static int intel_pt_inject_event(union perf_event *event,
struct perf_sample *sample, u64 type)
{
- event->header.size = perf_event__sample_event_size(sample, type, 0);
- return perf_event__synthesize_sample(event, type, 0, sample);
+ event->header.type = PERF_RECORD_SAMPLE;
+ event->header.size = perf_event__sample_event_size(sample, type, /*read_format=*/0,
+ /*branch_sample_type=*/0);
+
+ return perf_event__synthesize_sample(event, type, /*read_format=*/0,
+ /*branch_sample_type=*/0, sample);
}
static inline int intel_pt_opt_inject(struct intel_pt *pt,
@@ -2486,7 +2490,7 @@ static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evse
intel_pt_add_xmm(intr_regs, pos, items, regs_mask);
}
- if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
+ if ((sample_type | evsel->synth_sample_type) & PERF_SAMPLE_BRANCH_STACK) {
if (items->mask[INTEL_PT_LBR_0_POS] ||
items->mask[INTEL_PT_LBR_1_POS] ||
items->mask[INTEL_PT_LBR_2_POS]) {
@@ -2557,7 +2561,8 @@ static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evse
sample.transaction = txn;
}
- ret = intel_pt_deliver_synth_event(pt, event, &sample, sample_type);
+ ret = intel_pt_deliver_synth_event(pt, event, &sample,
+ sample_type | evsel->synth_sample_type);
perf_sample__exit(&sample);
return ret;
}
diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
index 85bee747f4cd..2461f25a4d7d 100644
--- a/tools/perf/util/synthetic-events.c
+++ b/tools/perf/util/synthetic-events.c
@@ -1455,7 +1455,8 @@ int perf_event__synthesize_stat_round(const struct perf_tool *tool,
return process(tool, (union perf_event *) &event, NULL, machine);
}
-size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format)
+size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format,
+ u64 branch_sample_type)
{
size_t sz, result = sizeof(struct perf_record_sample);
@@ -1515,8 +1516,10 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_BRANCH_STACK) {
sz = sample->branch_stack->nr * sizeof(struct branch_entry);
- /* nr, hw_idx */
- sz += 2 * sizeof(u64);
+ /* nr */
+ sz += sizeof(u64);
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX)
+ sz += sizeof(u64);
result += sz;
}
@@ -1605,7 +1608,7 @@ static __u64 *copy_read_group_values(__u64 *array, __u64 read_format,
}
int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
- const struct perf_sample *sample)
+ u64 branch_sample_type, const struct perf_sample *sample)
{
__u64 *array;
size_t sz;
@@ -1719,9 +1722,17 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
if (type & PERF_SAMPLE_BRANCH_STACK) {
sz = sample->branch_stack->nr * sizeof(struct branch_entry);
- /* nr, hw_idx */
- sz += 2 * sizeof(u64);
- memcpy(array, sample->branch_stack, sz);
+
+ *array++ = sample->branch_stack->nr;
+
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX) {
+ if (sample->no_hw_idx)
+ *array++ = 0;
+ else
+ *array++ = sample->branch_stack->hw_idx;
+ }
+
+ memcpy(array, perf_sample__branch_entries((struct perf_sample *)sample), sz);
array = (void *)array + sz;
}
diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h
index b0edad0c3100..8c7f49f9ccf5 100644
--- a/tools/perf/util/synthetic-events.h
+++ b/tools/perf/util/synthetic-events.h
@@ -81,7 +81,8 @@ int perf_event__synthesize_mmap_events(const struct perf_tool *tool, union perf_
int perf_event__synthesize_modules(const struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
int perf_event__synthesize_namespaces(const struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct machine *machine);
int perf_event__synthesize_cgroups(const struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
-int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, const struct perf_sample *sample);
+int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
+ u64 branch_sample_type, const struct perf_sample *sample);
int perf_event__synthesize_stat_config(const struct perf_tool *tool, struct perf_stat_config *config, perf_event__handler_t process, struct machine *machine);
int perf_event__synthesize_stat_events(struct perf_stat_config *config, const struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process, bool attrs);
int perf_event__synthesize_stat_round(const struct perf_tool *tool, u64 time, u64 type, perf_event__handler_t process, struct machine *machine);
@@ -97,7 +98,8 @@ void perf_event__synthesize_final_bpf_metadata(struct perf_session *session,
int perf_tool__process_synth_event(const struct perf_tool *tool, union perf_event *event, struct machine *machine, perf_event__handler_t process);
-size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format);
+size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
+ u64 read_format, u64 branch_sample_type);
int __machine__synthesize_threads(struct machine *machine, const struct perf_tool *tool,
struct target *target, struct perf_thread_map *threads,
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 53/59] perf: Remove libperl support, legacy Perl scripts and tests
From: Ian Rogers @ 2026-04-25 22:44 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
Remove libperl support from perf, along with legacy Perl scripts
and their corresponding tests.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v5:
1. Fix Buffer Overflows: Added bounds checks in `check_ev_match()` and
`find_scripts()` to prevent stack and heap buffer overflows when
parsing long event or script names.
---
tools/build/Makefile.feature | 1 -
tools/build/feature/Makefile | 19 +-
tools/build/feature/test-libperl.c | 10 -
tools/perf/Documentation/perf-check.txt | 1 -
tools/perf/Makefile.config | 22 +-
tools/perf/Makefile.perf | 11 +-
tools/perf/builtin-check.c | 2 +-
tools/perf/builtin-script.c | 4 +-
tools/perf/scripts/Build | 4 +-
tools/perf/scripts/perl/Perf-Trace-Util/Build | 9 -
.../scripts/perl/Perf-Trace-Util/Context.c | 122 ---
.../scripts/perl/Perf-Trace-Util/Context.xs | 42 -
.../scripts/perl/Perf-Trace-Util/Makefile.PL | 18 -
.../perf/scripts/perl/Perf-Trace-Util/README | 59 --
.../Perf-Trace-Util/lib/Perf/Trace/Context.pm | 55 --
.../Perf-Trace-Util/lib/Perf/Trace/Core.pm | 192 -----
.../Perf-Trace-Util/lib/Perf/Trace/Util.pm | 94 ---
.../perf/scripts/perl/Perf-Trace-Util/typemap | 1 -
.../scripts/perl/bin/check-perf-trace-record | 2 -
.../scripts/perl/bin/failed-syscalls-record | 3 -
.../scripts/perl/bin/failed-syscalls-report | 10 -
tools/perf/scripts/perl/bin/rw-by-file-record | 3 -
tools/perf/scripts/perl/bin/rw-by-file-report | 10 -
tools/perf/scripts/perl/bin/rw-by-pid-record | 2 -
tools/perf/scripts/perl/bin/rw-by-pid-report | 3 -
tools/perf/scripts/perl/bin/rwtop-record | 2 -
tools/perf/scripts/perl/bin/rwtop-report | 20 -
.../scripts/perl/bin/wakeup-latency-record | 6 -
.../scripts/perl/bin/wakeup-latency-report | 3 -
tools/perf/scripts/perl/check-perf-trace.pl | 106 ---
tools/perf/scripts/perl/failed-syscalls.pl | 47 --
tools/perf/scripts/perl/rw-by-file.pl | 106 ---
tools/perf/scripts/perl/rw-by-pid.pl | 184 -----
tools/perf/scripts/perl/rwtop.pl | 203 -----
tools/perf/scripts/perl/wakeup-latency.pl | 107 ---
tools/perf/tests/make | 4 +-
tools/perf/tests/shell/script_perl.sh | 102 ---
tools/perf/ui/browsers/scripts.c | 21 +-
tools/perf/util/scripting-engines/Build | 6 +-
.../util/scripting-engines/trace-event-perl.c | 773 ------------------
tools/perf/util/trace-event-scripting.c | 65 --
tools/perf/util/trace-event.h | 2 +-
42 files changed, 25 insertions(+), 2431 deletions(-)
delete mode 100644 tools/build/feature/test-libperl.c
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Build
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Context.c
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/README
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/typemap
delete mode 100644 tools/perf/scripts/perl/bin/check-perf-trace-record
delete mode 100644 tools/perf/scripts/perl/bin/failed-syscalls-record
delete mode 100644 tools/perf/scripts/perl/bin/failed-syscalls-report
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-file-record
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-file-report
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-pid-record
delete mode 100644 tools/perf/scripts/perl/bin/rw-by-pid-report
delete mode 100644 tools/perf/scripts/perl/bin/rwtop-record
delete mode 100644 tools/perf/scripts/perl/bin/rwtop-report
delete mode 100644 tools/perf/scripts/perl/bin/wakeup-latency-record
delete mode 100644 tools/perf/scripts/perl/bin/wakeup-latency-report
delete mode 100644 tools/perf/scripts/perl/check-perf-trace.pl
delete mode 100644 tools/perf/scripts/perl/failed-syscalls.pl
delete mode 100644 tools/perf/scripts/perl/rw-by-file.pl
delete mode 100644 tools/perf/scripts/perl/rw-by-pid.pl
delete mode 100644 tools/perf/scripts/perl/rwtop.pl
delete mode 100644 tools/perf/scripts/perl/wakeup-latency.pl
delete mode 100755 tools/perf/tests/shell/script_perl.sh
delete mode 100644 tools/perf/util/scripting-engines/trace-event-perl.c
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 0b7a7c38cb88..96d4382144c4 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -118,7 +118,6 @@ FEATURE_TESTS_EXTRA := \
libbfd-liberty \
libbfd-liberty-z \
libopencsd \
- libperl \
cxx \
llvm \
clang \
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index f163a245837a..60e3df8142a5 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -30,7 +30,6 @@ FILES= \
test-libdebuginfod.bin \
test-libnuma.bin \
test-numa_num_possible_cpus.bin \
- test-libperl.bin \
test-libpython.bin \
test-libslang.bin \
test-libtraceevent.bin \
@@ -113,7 +112,7 @@ __BUILD = $(CC) $(CFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(
BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
BUILD_BFD = $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
BUILD_ALL = $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -lslang \
- $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -ldl -lz -llzma -lzstd \
+ $(FLAGS_PYTHON_EMBED) -ldl -lz -llzma -lzstd \
$(shell $(PKG_CONFIG) --libs --cflags openssl 2>/dev/null)
__BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS)
@@ -253,22 +252,6 @@ $(OUTPUT)test-gtk2-infobar.bin:
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
-PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
-PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
-PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
-PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null)
-FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
-
-ifeq ($(CC_NO_CLANG), 0)
- PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS))
- PERL_EMBED_CCOPTS := $(filter-out -flto=auto -ffat-lto-objects, $(PERL_EMBED_CCOPTS))
- PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS))
- FLAGS_PERL_EMBED += -Wno-compound-token-split-by-macro
-endif
-
-$(OUTPUT)test-libperl.bin:
- $(BUILD) $(FLAGS_PERL_EMBED)
-
$(OUTPUT)test-libpython.bin:
$(BUILD) $(FLAGS_PYTHON_EMBED)
diff --git a/tools/build/feature/test-libperl.c b/tools/build/feature/test-libperl.c
deleted file mode 100644
index 0415f437eb31..000000000000
--- a/tools/build/feature/test-libperl.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <EXTERN.h>
-#include <perl.h>
-
-int main(void)
-{
- perl_alloc();
-
- return 0;
-}
diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt
index 09e1d35677f5..60fa9ea43a58 100644
--- a/tools/perf/Documentation/perf-check.txt
+++ b/tools/perf/Documentation/perf-check.txt
@@ -58,7 +58,6 @@ feature::
libLLVM / HAVE_LIBLLVM_SUPPORT
libnuma / HAVE_LIBNUMA_SUPPORT
libopencsd / HAVE_CSTRACE_SUPPORT
- libperl / HAVE_LIBPERL_SUPPORT
libpfm4 / HAVE_LIBPFM
libpython / HAVE_LIBPYTHON_SUPPORT
libslang / HAVE_SLANG_SUPPORT
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 333ddd0e4bd8..db30e73c5efc 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -820,26 +820,7 @@ ifdef GTK2
endif
endif
-ifdef LIBPERL
- PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
- PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
- PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
- PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null)
- PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS))
- PERL_EMBED_CCOPTS := $(filter-out -flto% -ffat-lto-objects, $(PERL_EMBED_CCOPTS))
- PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS))
- FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
-
- $(call feature_check,libperl)
- ifneq ($(feature-libperl), 1)
- $(error Missing perl devel files. Please install perl-ExtUtils-Embed/libperl-dev)
- else
- LDFLAGS += $(PERL_EMBED_LDFLAGS)
- EXTLIBS += $(PERL_EMBED_LIBADD)
- CFLAGS += -DHAVE_LIBPERL_SUPPORT
- $(call detected,CONFIG_LIBPERL)
- endif
-endif
+
ifeq ($(feature-timerfd), 1)
CFLAGS += -DHAVE_TIMERFD_SUPPORT
@@ -1321,7 +1302,6 @@ $(call detected_var,tipdir_SQ)
$(call detected_var,srcdir_SQ)
$(call detected_var,LIBDIR)
$(call detected_var,GTK_CFLAGS)
-$(call detected_var,PERL_EMBED_CCOPTS)
$(call detected_var,PYTHON_EMBED_CCOPTS)
ifneq ($(BISON_FILE_PREFIX_MAP),)
$(call detected_var,BISON_FILE_PREFIX_MAP)
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index cee19c923c06..7bf349198622 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -17,7 +17,7 @@ include ../scripts/utilities.mak
#
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
#
-# Define LIBPERL to enable perl script extension.
+
#
# Define NO_LIBPYTHON to disable python script extension.
#
@@ -1098,14 +1098,7 @@ endif
$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
$(call QUIET_INSTALL, perf-iostat) \
$(INSTALL) $(OUTPUT)perf-iostat -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
-ifdef LIBPERL
- $(call QUIET_INSTALL, perl-scripts) \
- $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
- $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
- $(INSTALL) scripts/perl/*.pl -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
- $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \
- $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
-endif
+
ifndef NO_LIBPYTHON
$(call QUIET_INSTALL, python-scripts) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c
index 3641d263b345..944038814d62 100644
--- a/tools/perf/builtin-check.c
+++ b/tools/perf/builtin-check.c
@@ -51,7 +51,7 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("libLLVM", HAVE_LIBLLVM_SUPPORT),
FEATURE_STATUS("libnuma", HAVE_LIBNUMA_SUPPORT),
FEATURE_STATUS("libopencsd", HAVE_CSTRACE_SUPPORT),
- FEATURE_STATUS_TIP("libperl", HAVE_LIBPERL_SUPPORT, "Deprecated, use LIBPERL=1 and install perl-ExtUtils-Embed/libperl-dev to build with it"),
+
FEATURE_STATUS("libpfm4", HAVE_LIBPFM),
FEATURE_STATUS("libpython", HAVE_LIBPYTHON_SUPPORT),
FEATURE_STATUS("libslang", HAVE_SLANG_SUPPORT),
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 3e3692088154..c0949556d1bb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -2621,9 +2621,7 @@ static void process_stat_interval(u64 tstamp)
static void setup_scripting(void)
{
-#ifdef HAVE_LIBTRACEEVENT
- setup_perl_scripting();
-#endif
+
setup_python_scripting();
}
diff --git a/tools/perf/scripts/Build b/tools/perf/scripts/Build
index 91229a1fe3ff..d72cf9ad45fe 100644
--- a/tools/perf/scripts/Build
+++ b/tools/perf/scripts/Build
@@ -1,6 +1,4 @@
-ifeq ($(CONFIG_LIBTRACEEVENT),y)
- perf-util-$(CONFIG_LIBPERL) += perl/Perf-Trace-Util/
-endif
+
perf-util-$(CONFIG_LIBPYTHON) += python/Perf-Trace-Util/
ifdef MYPY
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Build b/tools/perf/scripts/perl/Perf-Trace-Util/Build
deleted file mode 100644
index 01a1a0ed51ae..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Build
+++ /dev/null
@@ -1,9 +0,0 @@
-perf-util-y += Context.o
-
-CFLAGS_Context.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum
-CFLAGS_Context.o += -Wno-unused-parameter -Wno-nested-externs -Wno-undef
-CFLAGS_Context.o += -Wno-switch-default -Wno-shadow -Wno-thread-safety-analysis
-
-ifeq ($(CC_NO_CLANG), 1)
- CFLAGS_Context.o += -Wno-unused-command-line-argument
-endif
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
deleted file mode 100644
index 25c47d23a130..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * This file was generated automatically by ExtUtils::ParseXS version 2.18_02 from the
- * contents of Context.xs. Do not edit this file, edit Context.xs instead.
- *
- * ANY CHANGES MADE HERE WILL BE LOST!
- */
-#include <stdbool.h>
-#ifndef HAS_BOOL
-# define HAS_BOOL 1
-#endif
-#line 1 "Context.xs"
-/*
- * Context.xs. XS interfaces for perf script.
- *
- * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
- */
-
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-#include "../../../util/trace-event.h"
-
-#ifndef PERL_UNUSED_VAR
-# define PERL_UNUSED_VAR(var) if (0) var = var
-#endif
-
-#line 42 "Context.c"
-
-XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
-XS(XS_Perf__Trace__Context_common_pc)
-{
-#ifdef dVAR
- dVAR; dXSARGS;
-#else
- dXSARGS;
-#endif
- if (items != 1)
- Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_pc", "context");
- PERL_UNUSED_VAR(cv); /* -W */
- {
- struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
- int RETVAL;
- dXSTARG;
-
- RETVAL = common_pc(context);
- XSprePUSH; PUSHi((IV)RETVAL);
- }
- XSRETURN(1);
-}
-
-
-XS(XS_Perf__Trace__Context_common_flags); /* prototype to pass -Wmissing-prototypes */
-XS(XS_Perf__Trace__Context_common_flags)
-{
-#ifdef dVAR
- dVAR; dXSARGS;
-#else
- dXSARGS;
-#endif
- if (items != 1)
- Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_flags", "context");
- PERL_UNUSED_VAR(cv); /* -W */
- {
- struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
- int RETVAL;
- dXSTARG;
-
- RETVAL = common_flags(context);
- XSprePUSH; PUSHi((IV)RETVAL);
- }
- XSRETURN(1);
-}
-
-
-XS(XS_Perf__Trace__Context_common_lock_depth); /* prototype to pass -Wmissing-prototypes */
-XS(XS_Perf__Trace__Context_common_lock_depth)
-{
-#ifdef dVAR
- dVAR; dXSARGS;
-#else
- dXSARGS;
-#endif
- if (items != 1)
- Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_lock_depth", "context");
- PERL_UNUSED_VAR(cv); /* -W */
- {
- struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
- int RETVAL;
- dXSTARG;
-
- RETVAL = common_lock_depth(context);
- XSprePUSH; PUSHi((IV)RETVAL);
- }
- XSRETURN(1);
-}
-
-#ifdef __cplusplus
-extern "C"
-#endif
-XS(boot_Perf__Trace__Context); /* prototype to pass -Wmissing-prototypes */
-XS(boot_Perf__Trace__Context)
-{
-#ifdef dVAR
- dVAR; dXSARGS;
-#else
- dXSARGS;
-#endif
- const char* file = __FILE__;
-
- PERL_UNUSED_VAR(cv); /* -W */
- PERL_UNUSED_VAR(items); /* -W */
- XS_VERSION_BOOTCHECK ;
-
- newXSproto("Perf::Trace::Context::common_pc", XS_Perf__Trace__Context_common_pc, file, "$");
- newXSproto("Perf::Trace::Context::common_flags", XS_Perf__Trace__Context_common_flags, file, "$");
- newXSproto("Perf::Trace::Context::common_lock_depth", XS_Perf__Trace__Context_common_lock_depth, file, "$");
- if (PL_unitcheckav)
- call_list(PL_scopestack_ix, PL_unitcheckav);
- XSRETURN_YES;
-}
-
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
deleted file mode 100644
index 8c7ea42444d1..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Context.xs. XS interfaces for perf script.
- *
- * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-#include "../../../perf.h"
-#include "../../../util/trace-event.h"
-
-MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
-PROTOTYPES: ENABLE
-
-int
-common_pc(context)
- struct scripting_context * context
-
-int
-common_flags(context)
- struct scripting_context * context
-
-int
-common_lock_depth(context)
- struct scripting_context * context
-
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL b/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
deleted file mode 100644
index e8994332d7dc..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
+++ /dev/null
@@ -1,18 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-use 5.010000;
-use ExtUtils::MakeMaker;
-# See lib/ExtUtils/MakeMaker.pm for details of how to influence
-# the contents of the Makefile that is written.
-WriteMakefile(
- NAME => 'Perf::Trace::Context',
- VERSION_FROM => 'lib/Perf/Trace/Context.pm', # finds $VERSION
- PREREQ_PM => {}, # e.g., Module::Name => 1.1
- ($] >= 5.005 ? ## Add these new keywords supported since 5.005
- (ABSTRACT_FROM => 'lib/Perf/Trace/Context.pm', # retrieve abstract from module
- AUTHOR => 'Tom Zanussi <tzanussi@gmail.com>') : ()),
- LIBS => [''], # e.g., '-lm'
- DEFINE => '-I ../..', # e.g., '-DHAVE_SOMETHING'
- INC => '-I.', # e.g., '-I. -I/usr/include/other'
- # Un-comment this if you add C files to link with later:
- OBJECT => 'Context.o', # link all the C files too
-);
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/README b/tools/perf/scripts/perl/Perf-Trace-Util/README
deleted file mode 100644
index 2f0c7f3043ee..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/README
+++ /dev/null
@@ -1,59 +0,0 @@
-Perf-Trace-Util version 0.01
-============================
-
-This module contains utility functions for use with perf script.
-
-Core.pm and Util.pm are pure Perl modules; Core.pm contains routines
-that the core perf support for Perl calls on and should always be
-'used', while Util.pm contains useful but optional utility functions
-that scripts may want to use. Context.pm contains the Perl->C
-interface that allows scripts to access data in the embedding perf
-executable; scripts wishing to do that should 'use Context.pm'.
-
-The Perl->C perf interface is completely driven by Context.xs. If you
-want to add new Perl functions that end up accessing C data in the
-perf executable, you add desciptions of the new functions here.
-scripting_context is a pointer to the perf data in the perf executable
-that you want to access - it's passed as the second parameter,
-$context, to all handler functions.
-
-After you do that:
-
- perl Makefile.PL # to create a Makefile for the next step
- make # to create Context.c
-
- edit Context.c to add const to the char* file = __FILE__ line in
- XS(boot_Perf__Trace__Context) to silence a warning/error.
-
- You can delete the Makefile, object files and anything else that was
- generated e.g. blib and shared library, etc, except for of course
- Context.c
-
- You should then be able to run the normal perf make as usual.
-
-INSTALLATION
-
-Building perf with perf script Perl scripting should install this
-module in the right place.
-
-You should make sure libperl and ExtUtils/Embed.pm are installed first
-e.g. apt-get install libperl-dev or yum install perl-ExtUtils-Embed.
-
-DEPENDENCIES
-
-This module requires these other modules and libraries:
-
- None
-
-COPYRIGHT AND LICENCE
-
-Copyright (C) 2009 by Tom Zanussi <tzanussi@gmail.com>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.10.0 or,
-at your option, any later version of Perl 5 you may have available.
-
-Alternatively, this software may be distributed under the terms of the
-GNU General Public License ("GPL") version 2 as published by the Free
-Software Foundation.
-
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
deleted file mode 100644
index 4e2f6039ac92..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
+++ /dev/null
@@ -1,55 +0,0 @@
-package Perf::Trace::Context;
-
-use 5.010000;
-use strict;
-use warnings;
-
-require Exporter;
-
-our @ISA = qw(Exporter);
-
-our %EXPORT_TAGS = ( 'all' => [ qw(
-) ] );
-
-our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
-
-our @EXPORT = qw(
- common_pc common_flags common_lock_depth
-);
-
-our $VERSION = '0.01';
-
-require XSLoader;
-XSLoader::load('Perf::Trace::Context', $VERSION);
-
-1;
-__END__
-=head1 NAME
-
-Perf::Trace::Context - Perl extension for accessing functions in perf.
-
-=head1 SYNOPSIS
-
- use Perf::Trace::Context;
-
-=head1 SEE ALSO
-
-Perf (script) documentation
-
-=head1 AUTHOR
-
-Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2009 by Tom Zanussi
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.10.0 or,
-at your option, any later version of Perl 5 you may have available.
-
-Alternatively, this software may be distributed under the terms of the
-GNU General Public License ("GPL") version 2 as published by the Free
-Software Foundation.
-
-=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
deleted file mode 100644
index 9158458d3eeb..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
+++ /dev/null
@@ -1,192 +0,0 @@
-package Perf::Trace::Core;
-
-use 5.010000;
-use strict;
-use warnings;
-
-require Exporter;
-
-our @ISA = qw(Exporter);
-
-our %EXPORT_TAGS = ( 'all' => [ qw(
-) ] );
-
-our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
-
-our @EXPORT = qw(
-define_flag_field define_flag_value flag_str dump_flag_fields
-define_symbolic_field define_symbolic_value symbol_str dump_symbolic_fields
-trace_flag_str
-);
-
-our $VERSION = '0.01';
-
-my %trace_flags = (0x00 => "NONE",
- 0x01 => "IRQS_OFF",
- 0x02 => "IRQS_NOSUPPORT",
- 0x04 => "NEED_RESCHED",
- 0x08 => "HARDIRQ",
- 0x10 => "SOFTIRQ");
-
-sub trace_flag_str
-{
- my ($value) = @_;
-
- my $string;
-
- my $print_delim = 0;
-
- foreach my $idx (sort {$a <=> $b} keys %trace_flags) {
- if (!$value && !$idx) {
- $string .= "NONE";
- last;
- }
-
- if ($idx && ($value & $idx) == $idx) {
- if ($print_delim) {
- $string .= " | ";
- }
- $string .= "$trace_flags{$idx}";
- $print_delim = 1;
- $value &= ~$idx;
- }
- }
-
- return $string;
-}
-
-my %flag_fields;
-my %symbolic_fields;
-
-sub flag_str
-{
- my ($event_name, $field_name, $value) = @_;
-
- my $string;
-
- if ($flag_fields{$event_name}{$field_name}) {
- my $print_delim = 0;
- foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event_name}{$field_name}{"values"}}) {
- if (!$value && !$idx) {
- $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
- last;
- }
- if ($idx && ($value & $idx) == $idx) {
- if ($print_delim && $flag_fields{$event_name}{$field_name}{'delim'}) {
- $string .= " $flag_fields{$event_name}{$field_name}{'delim'} ";
- }
- $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
- $print_delim = 1;
- $value &= ~$idx;
- }
- }
- }
-
- return $string;
-}
-
-sub define_flag_field
-{
- my ($event_name, $field_name, $delim) = @_;
-
- $flag_fields{$event_name}{$field_name}{"delim"} = $delim;
-}
-
-sub define_flag_value
-{
- my ($event_name, $field_name, $value, $field_str) = @_;
-
- $flag_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
-}
-
-sub dump_flag_fields
-{
- for my $event (keys %flag_fields) {
- print "event $event:\n";
- for my $field (keys %{$flag_fields{$event}}) {
- print " field: $field:\n";
- print " delim: $flag_fields{$event}{$field}{'delim'}\n";
- foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event}{$field}{"values"}}) {
- print " value $idx: $flag_fields{$event}{$field}{'values'}{$idx}\n";
- }
- }
- }
-}
-
-sub symbol_str
-{
- my ($event_name, $field_name, $value) = @_;
-
- if ($symbolic_fields{$event_name}{$field_name}) {
- foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event_name}{$field_name}{"values"}}) {
- if (!$value && !$idx) {
- return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
- last;
- }
- if ($value == $idx) {
- return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
- }
- }
- }
-
- return undef;
-}
-
-sub define_symbolic_field
-{
- my ($event_name, $field_name) = @_;
-
- # nothing to do, really
-}
-
-sub define_symbolic_value
-{
- my ($event_name, $field_name, $value, $field_str) = @_;
-
- $symbolic_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
-}
-
-sub dump_symbolic_fields
-{
- for my $event (keys %symbolic_fields) {
- print "event $event:\n";
- for my $field (keys %{$symbolic_fields{$event}}) {
- print " field: $field:\n";
- foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event}{$field}{"values"}}) {
- print " value $idx: $symbolic_fields{$event}{$field}{'values'}{$idx}\n";
- }
- }
- }
-}
-
-1;
-__END__
-=head1 NAME
-
-Perf::Trace::Core - Perl extension for perf script
-
-=head1 SYNOPSIS
-
- use Perf::Trace::Core
-
-=head1 SEE ALSO
-
-Perf (script) documentation
-
-=head1 AUTHOR
-
-Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2009 by Tom Zanussi
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.10.0 or,
-at your option, any later version of Perl 5 you may have available.
-
-Alternatively, this software may be distributed under the terms of the
-GNU General Public License ("GPL") version 2 as published by the Free
-Software Foundation.
-
-=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
deleted file mode 100644
index 053500114625..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
+++ /dev/null
@@ -1,94 +0,0 @@
-package Perf::Trace::Util;
-
-use 5.010000;
-use strict;
-use warnings;
-
-require Exporter;
-
-our @ISA = qw(Exporter);
-
-our %EXPORT_TAGS = ( 'all' => [ qw(
-) ] );
-
-our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
-
-our @EXPORT = qw(
-avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs
-clear_term
-);
-
-our $VERSION = '0.01';
-
-sub avg
-{
- my ($total, $n) = @_;
-
- return $total / $n;
-}
-
-my $NSECS_PER_SEC = 1000000000;
-
-sub nsecs
-{
- my ($secs, $nsecs) = @_;
-
- return $secs * $NSECS_PER_SEC + $nsecs;
-}
-
-sub nsecs_secs {
- my ($nsecs) = @_;
-
- return $nsecs / $NSECS_PER_SEC;
-}
-
-sub nsecs_nsecs {
- my ($nsecs) = @_;
-
- return $nsecs % $NSECS_PER_SEC;
-}
-
-sub nsecs_str {
- my ($nsecs) = @_;
-
- my $str = sprintf("%5u.%09u", nsecs_secs($nsecs), nsecs_nsecs($nsecs));
-
- return $str;
-}
-
-sub clear_term
-{
- print "\x1b[H\x1b[2J";
-}
-
-1;
-__END__
-=head1 NAME
-
-Perf::Trace::Util - Perl extension for perf script
-
-=head1 SYNOPSIS
-
- use Perf::Trace::Util;
-
-=head1 SEE ALSO
-
-Perf (script) documentation
-
-=head1 AUTHOR
-
-Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2009 by Tom Zanussi
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.10.0 or,
-at your option, any later version of Perl 5 you may have available.
-
-Alternatively, this software may be distributed under the terms of the
-GNU General Public License ("GPL") version 2 as published by the Free
-Software Foundation.
-
-=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/typemap b/tools/perf/scripts/perl/Perf-Trace-Util/typemap
deleted file mode 100644
index 840836804aa7..000000000000
--- a/tools/perf/scripts/perl/Perf-Trace-Util/typemap
+++ /dev/null
@@ -1 +0,0 @@
-struct scripting_context * T_PTR
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record
deleted file mode 100644
index 423ad6aed056..000000000000
--- a/tools/perf/scripts/perl/bin/check-perf-trace-record
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-perf record -a -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
deleted file mode 100644
index 74685f318379..000000000000
--- a/tools/perf/scripts/perl/bin/failed-syscalls-record
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-(perf record -e raw_syscalls:sys_exit $@ || \
- perf record -e syscalls:sys_exit $@) 2> /dev/null
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-report b/tools/perf/scripts/perl/bin/failed-syscalls-report
deleted file mode 100644
index 9f83cc1ad8ba..000000000000
--- a/tools/perf/scripts/perl/bin/failed-syscalls-report
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-# description: system-wide failed syscalls
-# args: [comm]
-if [ $# -gt 0 ] ; then
- if ! expr match "$1" "-" > /dev/null ; then
- comm=$1
- shift
- fi
-fi
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/failed-syscalls.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
deleted file mode 100644
index 33efc8673aae..000000000000
--- a/tools/perf/scripts/perl/bin/rw-by-file-record
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-perf record -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@
-
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
deleted file mode 100644
index 77200b3f3100..000000000000
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-# description: r/w activity for a program, by file
-# args: <comm>
-if [ $# -lt 1 ] ; then
- echo "usage: rw-by-file <comm>"
- exit
-fi
-comm=$1
-shift
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-file.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
deleted file mode 100644
index 7cb9db230448..000000000000
--- a/tools/perf/scripts/perl/bin/rw-by-pid-record
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
deleted file mode 100644
index a27b9f311f95..000000000000
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-# description: system-wide r/w activity
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-pid.pl
diff --git a/tools/perf/scripts/perl/bin/rwtop-record b/tools/perf/scripts/perl/bin/rwtop-record
deleted file mode 100644
index 7cb9db230448..000000000000
--- a/tools/perf/scripts/perl/bin/rwtop-record
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rwtop-report b/tools/perf/scripts/perl/bin/rwtop-report
deleted file mode 100644
index 83e11ec2e190..000000000000
--- a/tools/perf/scripts/perl/bin/rwtop-report
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-# description: system-wide r/w top
-# args: [interval]
-n_args=0
-for i in "$@"
-do
- if expr match "$i" "-" > /dev/null ; then
- break
- fi
- n_args=$(( $n_args + 1 ))
-done
-if [ "$n_args" -gt 1 ] ; then
- echo "usage: rwtop-report [interval]"
- exit
-fi
-if [ "$n_args" -gt 0 ] ; then
- interval=$1
- shift
-fi
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rwtop.pl $interval
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
deleted file mode 100644
index 464251a1bd7e..000000000000
--- a/tools/perf/scripts/perl/bin/wakeup-latency-record
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-perf record -e sched:sched_switch -e sched:sched_wakeup $@
-
-
-
-
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
deleted file mode 100644
index 889e8130cca5..000000000000
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-# description: system-wide min/max/avg wakeup latency
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/wakeup-latency.pl
diff --git a/tools/perf/scripts/perl/check-perf-trace.pl b/tools/perf/scripts/perl/check-perf-trace.pl
deleted file mode 100644
index d307ce8fd6ed..000000000000
--- a/tools/perf/scripts/perl/check-perf-trace.pl
+++ /dev/null
@@ -1,106 +0,0 @@
-# perf script event handlers, generated by perf script -g perl
-# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
-# Licensed under the terms of the GNU GPL License version 2
-
-# This script tests basic functionality such as flag and symbol
-# strings, common_xxx() calls back into perf, begin, end, unhandled
-# events, etc. Basically, if this script runs successfully and
-# displays expected results, perl scripting support should be ok.
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Context;
-use Perf::Trace::Util;
-
-sub trace_begin
-{
- print "trace_begin\n";
-}
-
-sub trace_end
-{
- print "trace_end\n";
-
- print_unhandled();
-}
-
-sub irq::softirq_entry
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $vec) = @_;
-
- print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm);
-
- print_uncommon($context);
-
- printf("vec=%s\n",
- symbol_str("irq::softirq_entry", "vec", $vec));
-}
-
-sub kmem::kmalloc
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $call_site, $ptr, $bytes_req, $bytes_alloc,
- $gfp_flags) = @_;
-
- print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm);
-
- print_uncommon($context);
-
- printf("call_site=%p, ptr=%p, bytes_req=%u, bytes_alloc=%u, ".
- "gfp_flags=%s\n",
- $call_site, $ptr, $bytes_req, $bytes_alloc,
-
- flag_str("kmem::kmalloc", "gfp_flags", $gfp_flags));
-}
-
-# print trace fields not included in handler args
-sub print_uncommon
-{
- my ($context) = @_;
-
- printf("common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, ",
- common_pc($context), trace_flag_str(common_flags($context)),
- common_lock_depth($context));
-
-}
-
-my %unhandled;
-
-sub print_unhandled
-{
- if ((scalar keys %unhandled) == 0) {
- return;
- }
-
- print "\nunhandled events:\n\n";
-
- printf("%-40s %10s\n", "event", "count");
- printf("%-40s %10s\n", "----------------------------------------",
- "-----------");
-
- foreach my $event_name (keys %unhandled) {
- printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
- }
-}
-
-sub trace_unhandled
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain) = @_;
-
- $unhandled{$event_name}++;
-}
-
-sub print_header
-{
- my ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;
-
- printf("%-20s %5u %05u.%09u %8u %-20s ",
- $event_name, $cpu, $secs, $nsecs, $pid, $comm);
-}
diff --git a/tools/perf/scripts/perl/failed-syscalls.pl b/tools/perf/scripts/perl/failed-syscalls.pl
deleted file mode 100644
index 05954a8f363a..000000000000
--- a/tools/perf/scripts/perl/failed-syscalls.pl
+++ /dev/null
@@ -1,47 +0,0 @@
-# failed system call counts
-# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
-# Licensed under the terms of the GNU GPL License version 2
-#
-# Displays system-wide failed system call totals
-# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Context;
-use Perf::Trace::Util;
-
-my $for_comm = shift;
-
-my %failed_syscalls;
-
-sub raw_syscalls::sys_exit
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $id, $ret) = @_;
-
- if ($ret < 0) {
- $failed_syscalls{$common_comm}++;
- }
-}
-
-sub syscalls::sys_exit
-{
- raw_syscalls::sys_exit(@_)
-}
-
-sub trace_end
-{
- printf("\nfailed syscalls by comm:\n\n");
-
- printf("%-20s %10s\n", "comm", "# errors");
- printf("%-20s %6s %10s\n", "--------------------", "----------");
-
- foreach my $comm (sort {$failed_syscalls{$b} <=> $failed_syscalls{$a}}
- keys %failed_syscalls) {
- next if ($for_comm && $comm ne $for_comm);
-
- printf("%-20s %10s\n", $comm, $failed_syscalls{$comm});
- }
-}
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
deleted file mode 100644
index 92a750b8552b..000000000000
--- a/tools/perf/scripts/perl/rw-by-file.pl
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/perl -w
-# SPDX-License-Identifier: GPL-2.0-only
-# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
-
-# Display r/w activity for files read/written to for a given program
-
-# The common_* event handler fields are the most useful fields common to
-# all events. They don't necessarily correspond to the 'common_*' fields
-# in the status files. Those fields not available as handler params can
-# be retrieved via script functions of the form get_common_*().
-
-use 5.010000;
-use strict;
-use warnings;
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Util;
-
-my $usage = "perf script -s rw-by-file.pl <comm>\n";
-
-my $for_comm = shift or die $usage;
-
-my %reads;
-my %writes;
-
-sub syscalls::sys_enter_read
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain, $nr, $fd, $buf, $count) = @_;
-
- if ($common_comm eq $for_comm) {
- $reads{$fd}{bytes_requested} += $count;
- $reads{$fd}{total_reads}++;
- }
-}
-
-sub syscalls::sys_enter_write
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain, $nr, $fd, $buf, $count) = @_;
-
- if ($common_comm eq $for_comm) {
- $writes{$fd}{bytes_written} += $count;
- $writes{$fd}{total_writes}++;
- }
-}
-
-sub trace_end
-{
- printf("file read counts for $for_comm:\n\n");
-
- printf("%6s %10s %10s\n", "fd", "# reads", "bytes_requested");
- printf("%6s %10s %10s\n", "------", "----------", "-----------");
-
- foreach my $fd (sort {$reads{$b}{bytes_requested} <=>
- $reads{$a}{bytes_requested}} keys %reads) {
- my $total_reads = $reads{$fd}{total_reads};
- my $bytes_requested = $reads{$fd}{bytes_requested};
- printf("%6u %10u %10u\n", $fd, $total_reads, $bytes_requested);
- }
-
- printf("\nfile write counts for $for_comm:\n\n");
-
- printf("%6s %10s %10s\n", "fd", "# writes", "bytes_written");
- printf("%6s %10s %10s\n", "------", "----------", "-----------");
-
- foreach my $fd (sort {$writes{$b}{bytes_written} <=>
- $writes{$a}{bytes_written}} keys %writes) {
- my $total_writes = $writes{$fd}{total_writes};
- my $bytes_written = $writes{$fd}{bytes_written};
- printf("%6u %10u %10u\n", $fd, $total_writes, $bytes_written);
- }
-
- print_unhandled();
-}
-
-my %unhandled;
-
-sub print_unhandled
-{
- if ((scalar keys %unhandled) == 0) {
- return;
- }
-
- print "\nunhandled events:\n\n";
-
- printf("%-40s %10s\n", "event", "count");
- printf("%-40s %10s\n", "----------------------------------------",
- "-----------");
-
- foreach my $event_name (keys %unhandled) {
- printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
- }
-}
-
-sub trace_unhandled
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain) = @_;
-
- $unhandled{$event_name}++;
-}
-
-
diff --git a/tools/perf/scripts/perl/rw-by-pid.pl b/tools/perf/scripts/perl/rw-by-pid.pl
deleted file mode 100644
index d789fe39caab..000000000000
--- a/tools/perf/scripts/perl/rw-by-pid.pl
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/usr/bin/perl -w
-# SPDX-License-Identifier: GPL-2.0-only
-# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
-
-# Display r/w activity for all processes
-
-# The common_* event handler fields are the most useful fields common to
-# all events. They don't necessarily correspond to the 'common_*' fields
-# in the status files. Those fields not available as handler params can
-# be retrieved via script functions of the form get_common_*().
-
-use 5.010000;
-use strict;
-use warnings;
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Util;
-
-my %reads;
-my %writes;
-
-sub syscalls::sys_exit_read
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $ret) = @_;
-
- if ($ret > 0) {
- $reads{$common_pid}{bytes_read} += $ret;
- } else {
- if (!defined ($reads{$common_pid}{bytes_read})) {
- $reads{$common_pid}{bytes_read} = 0;
- }
- $reads{$common_pid}{errors}{$ret}++;
- }
-}
-
-sub syscalls::sys_enter_read
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $fd, $buf, $count) = @_;
-
- $reads{$common_pid}{bytes_requested} += $count;
- $reads{$common_pid}{total_reads}++;
- $reads{$common_pid}{comm} = $common_comm;
-}
-
-sub syscalls::sys_exit_write
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $ret) = @_;
-
- if ($ret <= 0) {
- $writes{$common_pid}{errors}{$ret}++;
- }
-}
-
-sub syscalls::sys_enter_write
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $fd, $buf, $count) = @_;
-
- $writes{$common_pid}{bytes_written} += $count;
- $writes{$common_pid}{total_writes}++;
- $writes{$common_pid}{comm} = $common_comm;
-}
-
-sub trace_end
-{
- printf("read counts by pid:\n\n");
-
- printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
- "# reads", "bytes_requested", "bytes_read");
- printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
- "-----------", "----------", "----------");
-
- foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
- ($reads{$a}{bytes_read} || 0) } keys %reads) {
- my $comm = $reads{$pid}{comm} || "";
- my $total_reads = $reads{$pid}{total_reads} || 0;
- my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
- my $bytes_read = $reads{$pid}{bytes_read} || 0;
-
- printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
- $total_reads, $bytes_requested, $bytes_read);
- }
-
- printf("\nfailed reads by pid:\n\n");
-
- printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
- printf("%6s %20s %6s %10s\n", "------", "--------------------",
- "------", "----------");
-
- my @errcounts = ();
-
- foreach my $pid (keys %reads) {
- foreach my $error (keys %{$reads{$pid}{errors}}) {
- my $comm = $reads{$pid}{comm} || "";
- my $errcount = $reads{$pid}{errors}{$error} || 0;
- push @errcounts, [$pid, $comm, $error, $errcount];
- }
- }
-
- @errcounts = sort { $b->[3] <=> $a->[3] } @errcounts;
-
- for my $i (0 .. $#errcounts) {
- printf("%6d %-20s %6d %10s\n", $errcounts[$i][0],
- $errcounts[$i][1], $errcounts[$i][2], $errcounts[$i][3]);
- }
-
- printf("\nwrite counts by pid:\n\n");
-
- printf("%6s %20s %10s %10s\n", "pid", "comm",
- "# writes", "bytes_written");
- printf("%6s %-20s %10s %10s\n", "------", "--------------------",
- "-----------", "----------");
-
- foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
- ($writes{$a}{bytes_written} || 0)} keys %writes) {
- my $comm = $writes{$pid}{comm} || "";
- my $total_writes = $writes{$pid}{total_writes} || 0;
- my $bytes_written = $writes{$pid}{bytes_written} || 0;
-
- printf("%6s %-20s %10s %10s\n", $pid, $comm,
- $total_writes, $bytes_written);
- }
-
- printf("\nfailed writes by pid:\n\n");
-
- printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
- printf("%6s %20s %6s %10s\n", "------", "--------------------",
- "------", "----------");
-
- @errcounts = ();
-
- foreach my $pid (keys %writes) {
- foreach my $error (keys %{$writes{$pid}{errors}}) {
- my $comm = $writes{$pid}{comm} || "";
- my $errcount = $writes{$pid}{errors}{$error} || 0;
- push @errcounts, [$pid, $comm, $error, $errcount];
- }
- }
-
- @errcounts = sort { $b->[3] <=> $a->[3] } @errcounts;
-
- for my $i (0 .. $#errcounts) {
- printf("%6d %-20s %6d %10s\n", $errcounts[$i][0],
- $errcounts[$i][1], $errcounts[$i][2], $errcounts[$i][3]);
- }
-
- print_unhandled();
-}
-
-my %unhandled;
-
-sub print_unhandled
-{
- if ((scalar keys %unhandled) == 0) {
- return;
- }
-
- print "\nunhandled events:\n\n";
-
- printf("%-40s %10s\n", "event", "count");
- printf("%-40s %10s\n", "----------------------------------------",
- "-----------");
-
- foreach my $event_name (keys %unhandled) {
- printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
- }
-}
-
-sub trace_unhandled
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain) = @_;
-
- $unhandled{$event_name}++;
-}
diff --git a/tools/perf/scripts/perl/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl
deleted file mode 100644
index eba4df67af6b..000000000000
--- a/tools/perf/scripts/perl/rwtop.pl
+++ /dev/null
@@ -1,203 +0,0 @@
-#!/usr/bin/perl -w
-# SPDX-License-Identifier: GPL-2.0-only
-# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
-
-# read/write top
-#
-# Periodically displays system-wide r/w call activity, broken down by
-# pid. If an [interval] arg is specified, the display will be
-# refreshed every [interval] seconds. The default interval is 3
-# seconds.
-
-use 5.010000;
-use strict;
-use warnings;
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Util;
-use POSIX qw/SIGALRM SA_RESTART/;
-
-my $default_interval = 3;
-my $nlines = 20;
-my $print_thread;
-my $print_pending = 0;
-
-my %reads;
-my %writes;
-
-my $interval = shift;
-if (!$interval) {
- $interval = $default_interval;
-}
-
-sub syscalls::sys_exit_read
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $ret) = @_;
-
- print_check();
-
- if ($ret > 0) {
- $reads{$common_pid}{bytes_read} += $ret;
- } else {
- if (!defined ($reads{$common_pid}{bytes_read})) {
- $reads{$common_pid}{bytes_read} = 0;
- }
- $reads{$common_pid}{errors}{$ret}++;
- }
-}
-
-sub syscalls::sys_enter_read
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $fd, $buf, $count) = @_;
-
- print_check();
-
- $reads{$common_pid}{bytes_requested} += $count;
- $reads{$common_pid}{total_reads}++;
- $reads{$common_pid}{comm} = $common_comm;
-}
-
-sub syscalls::sys_exit_write
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $ret) = @_;
-
- print_check();
-
- if ($ret <= 0) {
- $writes{$common_pid}{errors}{$ret}++;
- }
-}
-
-sub syscalls::sys_enter_write
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $nr, $fd, $buf, $count) = @_;
-
- print_check();
-
- $writes{$common_pid}{bytes_written} += $count;
- $writes{$common_pid}{total_writes}++;
- $writes{$common_pid}{comm} = $common_comm;
-}
-
-sub trace_begin
-{
- my $sa = POSIX::SigAction->new(\&set_print_pending);
- $sa->flags(SA_RESTART);
- $sa->safe(1);
- POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
- alarm 1;
-}
-
-sub trace_end
-{
- print_unhandled();
- print_totals();
-}
-
-sub print_check()
-{
- if ($print_pending == 1) {
- $print_pending = 0;
- print_totals();
- }
-}
-
-sub set_print_pending()
-{
- $print_pending = 1;
- alarm $interval;
-}
-
-sub print_totals
-{
- my $count;
-
- $count = 0;
-
- clear_term();
-
- printf("\nread counts by pid:\n\n");
-
- printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
- "# reads", "bytes_req", "bytes_read");
- printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
- "----------", "----------", "----------");
-
- foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
- ($reads{$a}{bytes_read} || 0) } keys %reads) {
- my $comm = $reads{$pid}{comm} || "";
- my $total_reads = $reads{$pid}{total_reads} || 0;
- my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
- my $bytes_read = $reads{$pid}{bytes_read} || 0;
-
- printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
- $total_reads, $bytes_requested, $bytes_read);
-
- if (++$count == $nlines) {
- last;
- }
- }
-
- $count = 0;
-
- printf("\nwrite counts by pid:\n\n");
-
- printf("%6s %20s %10s %13s\n", "pid", "comm",
- "# writes", "bytes_written");
- printf("%6s %-20s %10s %13s\n", "------", "--------------------",
- "----------", "-------------");
-
- foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
- ($writes{$a}{bytes_written} || 0)} keys %writes) {
- my $comm = $writes{$pid}{comm} || "";
- my $total_writes = $writes{$pid}{total_writes} || 0;
- my $bytes_written = $writes{$pid}{bytes_written} || 0;
-
- printf("%6s %-20s %10s %13s\n", $pid, $comm,
- $total_writes, $bytes_written);
-
- if (++$count == $nlines) {
- last;
- }
- }
-
- %reads = ();
- %writes = ();
-}
-
-my %unhandled;
-
-sub print_unhandled
-{
- if ((scalar keys %unhandled) == 0) {
- return;
- }
-
- print "\nunhandled events:\n\n";
-
- printf("%-40s %10s\n", "event", "count");
- printf("%-40s %10s\n", "----------------------------------------",
- "-----------");
-
- foreach my $event_name (keys %unhandled) {
- printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
- }
-}
-
-sub trace_unhandled
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain) = @_;
-
- $unhandled{$event_name}++;
-}
diff --git a/tools/perf/scripts/perl/wakeup-latency.pl b/tools/perf/scripts/perl/wakeup-latency.pl
deleted file mode 100644
index 53444ff4ec7f..000000000000
--- a/tools/perf/scripts/perl/wakeup-latency.pl
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/usr/bin/perl -w
-# SPDX-License-Identifier: GPL-2.0-only
-# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
-
-# Display avg/min/max wakeup latency
-
-# The common_* event handler fields are the most useful fields common to
-# all events. They don't necessarily correspond to the 'common_*' fields
-# in the status files. Those fields not available as handler params can
-# be retrieved via script functions of the form get_common_*().
-
-use 5.010000;
-use strict;
-use warnings;
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Util;
-
-my %last_wakeup;
-
-my $max_wakeup_latency;
-my $min_wakeup_latency;
-my $total_wakeup_latency = 0;
-my $total_wakeups = 0;
-
-sub sched::sched_switch
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $prev_comm, $prev_pid, $prev_prio, $prev_state, $next_comm, $next_pid,
- $next_prio) = @_;
-
- my $wakeup_ts = $last_wakeup{$common_cpu}{ts};
- if ($wakeup_ts) {
- my $switch_ts = nsecs($common_secs, $common_nsecs);
- my $wakeup_latency = $switch_ts - $wakeup_ts;
- if ($wakeup_latency > $max_wakeup_latency) {
- $max_wakeup_latency = $wakeup_latency;
- }
- if ($wakeup_latency < $min_wakeup_latency) {
- $min_wakeup_latency = $wakeup_latency;
- }
- $total_wakeup_latency += $wakeup_latency;
- $total_wakeups++;
- }
- $last_wakeup{$common_cpu}{ts} = 0;
-}
-
-sub sched::sched_wakeup
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain,
- $comm, $pid, $prio, $success, $target_cpu) = @_;
-
- $last_wakeup{$target_cpu}{ts} = nsecs($common_secs, $common_nsecs);
-}
-
-sub trace_begin
-{
- $min_wakeup_latency = 1000000000;
- $max_wakeup_latency = 0;
-}
-
-sub trace_end
-{
- printf("wakeup_latency stats:\n\n");
- print "total_wakeups: $total_wakeups\n";
- if ($total_wakeups) {
- printf("avg_wakeup_latency (ns): %u\n",
- avg($total_wakeup_latency, $total_wakeups));
- } else {
- printf("avg_wakeup_latency (ns): N/A\n");
- }
- printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency);
- printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency);
-
- print_unhandled();
-}
-
-my %unhandled;
-
-sub print_unhandled
-{
- if ((scalar keys %unhandled) == 0) {
- return;
- }
-
- print "\nunhandled events:\n\n";
-
- printf("%-40s %10s\n", "event", "count");
- printf("%-40s %10s\n", "----------------------------------------",
- "-----------");
-
- foreach my $event_name (keys %unhandled) {
- printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
- }
-}
-
-sub trace_unhandled
-{
- my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
- $common_pid, $common_comm, $common_callchain) = @_;
-
- $unhandled{$event_name}++;
-}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 6587dc326d1b..31b064928cfc 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -74,7 +74,7 @@ make_no_jevents := NO_JEVENTS=1
make_jevents_all := JEVENTS_ARCH=all
make_no_bpf_skel := BUILD_BPF_SKEL=0
make_gen_vmlinux_h := GEN_VMLINUX_H=1
-make_libperl := LIBPERL=1
+
make_no_libpython := NO_LIBPYTHON=1
make_no_scripts := NO_LIBPYTHON=1
make_no_slang := NO_SLANG=1
@@ -149,7 +149,7 @@ run += make_no_jevents
run += make_jevents_all
run += make_no_bpf_skel
run += make_gen_vmlinux_h
-run += make_libperl
+
run += make_no_libpython
run += make_no_scripts
run += make_no_slang
diff --git a/tools/perf/tests/shell/script_perl.sh b/tools/perf/tests/shell/script_perl.sh
deleted file mode 100755
index b6d65b6fbda1..000000000000
--- a/tools/perf/tests/shell/script_perl.sh
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/bin/bash
-# perf script perl tests
-# SPDX-License-Identifier: GPL-2.0
-
-set -e
-
-# set PERF_EXEC_PATH to find scripts in the source directory
-perfdir=$(dirname "$0")/../..
-if [ -e "$perfdir/scripts/perl/Perf-Trace-Util" ]; then
- export PERF_EXEC_PATH=$perfdir
-fi
-
-
-perfdata=$(mktemp /tmp/__perf_test_script_perl.perf.data.XXXXX)
-generated_script=$(mktemp /tmp/__perf_test_script.XXXXX.pl)
-
-cleanup() {
- rm -f "${perfdata}"
- rm -f "${generated_script}"
- trap - EXIT TERM INT
-}
-
-trap_cleanup() {
- echo "Unexpected signal in ${FUNCNAME[1]}"
- cleanup
- exit 1
-}
-trap trap_cleanup TERM INT
-trap cleanup EXIT
-
-check_perl_support() {
- if perf check feature -q libperl; then
- return 0
- fi
- echo "perf script perl test [Skipped: no libperl support]"
- return 2
-}
-
-test_script() {
- local event_name=$1
- local expected_output=$2
- local record_opts=$3
-
- echo "Testing event: $event_name"
-
- # Try to record. If this fails, it might be permissions or lack of support.
- # We return 2 to indicate "skip this event" rather than "fail test".
- if ! perf record -o "${perfdata}" -e "$event_name" $record_opts -- perf test -w thloop > /dev/null 2>&1; then
- echo "perf script perl test [Skipped: failed to record $event_name]"
- return 2
- fi
-
- echo "Generating perl script..."
- if ! perf script -i "${perfdata}" -g "${generated_script}"; then
- echo "perf script perl test [Failed: script generation for $event_name]"
- return 1
- fi
-
- if [ ! -f "${generated_script}" ]; then
- echo "perf script perl test [Failed: script not generated for $event_name]"
- return 1
- fi
-
- echo "Executing perl script..."
- output=$(perf script -i "${perfdata}" -s "${generated_script}" 2>&1)
-
- if echo "$output" | grep -q "$expected_output"; then
- echo "perf script perl test [Success: $event_name triggered $expected_output]"
- return 0
- else
- echo "perf script perl test [Failed: $event_name did not trigger $expected_output]"
- echo "Output was:"
- echo "$output" | head -n 20
- return 1
- fi
-}
-
-check_perl_support || exit 2
-
-# Try tracepoint first
-test_script "sched:sched_switch" "sched::sched_switch" "-c 1" && res=0 || res=$?
-
-if [ $res -eq 0 ]; then
- exit 0
-elif [ $res -eq 1 ]; then
- exit 1
-fi
-
-# If tracepoint skipped (res=2), try task-clock
-# For generic events like task-clock, the generated script uses process_event()
-# which dumps data using Data::Dumper. We check for "$VAR1" which is standard Dumper output.
-test_script "task-clock" "\$VAR1" "-c 100" && res=0 || res=$?
-
-if [ $res -eq 0 ]; then
- exit 0
-elif [ $res -eq 1 ]; then
- exit 1
-fi
-
-# If both skipped
-echo "perf script perl test [Skipped: Could not record tracepoint or task-clock]"
-exit 2
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index 1e8c2c2f952d..db5559311a1f 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -126,8 +126,10 @@ static int check_ev_match(int dir_fd, const char *scriptname, struct perf_sessio
len = strcspn(p, " \t");
if (!len)
break;
+ if ((size_t)len >= sizeof(evname))
+ len = sizeof(evname) - 1;
- snprintf(evname, len + 1, "%s", p);
+ snprintf(evname, sizeof(evname), "%s", p);
match = 0;
evlist__for_each_entry(session->evlist, pos) {
@@ -200,14 +202,13 @@ static int find_scripts(char **scripts_array, char **scripts_path_array, int num
if (!strcmp(lang_dirent->d_name, ".") || !strcmp(lang_dirent->d_name, ".."))
continue;
-#ifndef HAVE_LIBPERL_SUPPORT
- if (strstr(lang_dirent->d_name, "perl"))
- continue;
-#endif
+
#ifndef HAVE_LIBPYTHON_SUPPORT
if (strstr(lang_dirent->d_name, "python"))
continue;
#endif
+ if (strstr(lang_dirent->d_name, "perl"))
+ continue;
lang_dir_fd = openat(scripts_dir_fd, lang_dirent->d_name, O_DIRECTORY);
if (lang_dir_fd == -1)
@@ -218,6 +219,8 @@ static int find_scripts(char **scripts_array, char **scripts_path_array, int num
continue;
}
while ((script_dirent = readdir(lang_dir)) != NULL) {
+ int script_len;
+
if (script_dirent->d_type == DT_DIR)
continue;
if (script_dirent->d_type == DT_UNKNOWN &&
@@ -233,9 +236,11 @@ static int find_scripts(char **scripts_array, char **scripts_path_array, int num
lang_dirent->d_name,
script_dirent->d_name);
temp = strchr(script_dirent->d_name, '.');
- snprintf(scripts_array[i],
- (temp - script_dirent->d_name) + 1,
- "%s", script_dirent->d_name);
+ script_len = temp ? (temp - script_dirent->d_name) : (int)strlen(script_dirent->d_name);
+
+ if (script_len >= SCRIPT_NAMELEN)
+ script_len = SCRIPT_NAMELEN - 1;
+ snprintf(scripts_array[i], script_len + 1, "%s", script_dirent->d_name);
if (check_ev_match(lang_dir_fd, scripts_array[i], session))
continue;
diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build
index 24f087b0cd11..ce14ef44b200 100644
--- a/tools/perf/util/scripting-engines/Build
+++ b/tools/perf/util/scripting-engines/Build
@@ -1,9 +1,7 @@
-ifeq ($(CONFIG_LIBTRACEEVENT),y)
- perf-util-$(CONFIG_LIBPERL) += trace-event-perl.o
-endif
+
perf-util-$(CONFIG_LIBPYTHON) += trace-event-python.o
-CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum -Wno-thread-safety-analysis
+
# -Wno-declaration-after-statement: The python headers have mixed code with declarations (decls after asserts, for instance)
CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-deprecated-declarations -Wno-switch-enum -Wno-declaration-after-statement
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
deleted file mode 100644
index e261a57b87d4..000000000000
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ /dev/null
@@ -1,773 +0,0 @@
-/*
- * trace-event-perl. Feed perf script events to an embedded Perl interpreter.
- *
- * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <linux/bitmap.h>
-#include <linux/time64.h>
-#include <event-parse.h>
-
-#include <stdbool.h>
-/* perl needs the following define, right after including stdbool.h */
-#define HAS_BOOL
-#include <EXTERN.h>
-#include <perl.h>
-
-#include "../callchain.h"
-#include "../dso.h"
-#include "../machine.h"
-#include "../map.h"
-#include "../symbol.h"
-#include "../thread.h"
-#include "../event.h"
-#include "../trace-event.h"
-#include "../evsel.h"
-#include "../debug.h"
-
-void boot_Perf__Trace__Context(pTHX_ CV *cv);
-void boot_DynaLoader(pTHX_ CV *cv);
-typedef PerlInterpreter * INTERP;
-
-void xs_init(pTHX);
-
-void xs_init(pTHX)
-{
- const char *file = __FILE__;
- dXSUB_SYS;
-
- newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
- file);
- newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
-}
-
-INTERP my_perl;
-
-#define TRACE_EVENT_TYPE_MAX \
- ((1 << (sizeof(unsigned short) * 8)) - 1)
-
-extern struct scripting_context *scripting_context;
-
-static char *cur_field_name;
-static int zero_flag_atom;
-
-static void define_symbolic_value(const char *ev_name,
- const char *field_name,
- const char *field_value,
- const char *field_str)
-{
- unsigned long long value;
- dSP;
-
- value = eval_flag(field_value);
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
-
- XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
- XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
- XPUSHs(sv_2mortal(newSVuv(value)));
- XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
-
- PUTBACK;
- if (get_cv("main::define_symbolic_value", 0))
- call_pv("main::define_symbolic_value", G_SCALAR);
- SPAGAIN;
- PUTBACK;
- FREETMPS;
- LEAVE;
-}
-
-static void define_symbolic_values(struct tep_print_flag_sym *field,
- const char *ev_name,
- const char *field_name)
-{
- define_symbolic_value(ev_name, field_name, field->value, field->str);
- if (field->next)
- define_symbolic_values(field->next, ev_name, field_name);
-}
-
-static void define_symbolic_field(const char *ev_name,
- const char *field_name)
-{
- dSP;
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
-
- XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
- XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
-
- PUTBACK;
- if (get_cv("main::define_symbolic_field", 0))
- call_pv("main::define_symbolic_field", G_SCALAR);
- SPAGAIN;
- PUTBACK;
- FREETMPS;
- LEAVE;
-}
-
-static void define_flag_value(const char *ev_name,
- const char *field_name,
- const char *field_value,
- const char *field_str)
-{
- unsigned long long value;
- dSP;
-
- value = eval_flag(field_value);
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
-
- XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
- XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
- XPUSHs(sv_2mortal(newSVuv(value)));
- XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
-
- PUTBACK;
- if (get_cv("main::define_flag_value", 0))
- call_pv("main::define_flag_value", G_SCALAR);
- SPAGAIN;
- PUTBACK;
- FREETMPS;
- LEAVE;
-}
-
-static void define_flag_values(struct tep_print_flag_sym *field,
- const char *ev_name,
- const char *field_name)
-{
- define_flag_value(ev_name, field_name, field->value, field->str);
- if (field->next)
- define_flag_values(field->next, ev_name, field_name);
-}
-
-static void define_flag_field(const char *ev_name,
- const char *field_name,
- const char *delim)
-{
- dSP;
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
-
- XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
- XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
- XPUSHs(sv_2mortal(newSVpv(delim, 0)));
-
- PUTBACK;
- if (get_cv("main::define_flag_field", 0))
- call_pv("main::define_flag_field", G_SCALAR);
- SPAGAIN;
- PUTBACK;
- FREETMPS;
- LEAVE;
-}
-
-static void define_event_symbols(struct tep_event *event,
- const char *ev_name,
- struct tep_print_arg *args)
-{
- if (args == NULL)
- return;
-
- switch (args->type) {
- case TEP_PRINT_NULL:
- break;
- case TEP_PRINT_ATOM:
- define_flag_value(ev_name, cur_field_name, "0",
- args->atom.atom);
- zero_flag_atom = 0;
- break;
- case TEP_PRINT_FIELD:
- free(cur_field_name);
- cur_field_name = strdup(args->field.name);
- break;
- case TEP_PRINT_FLAGS:
- define_event_symbols(event, ev_name, args->flags.field);
- define_flag_field(ev_name, cur_field_name, args->flags.delim);
- define_flag_values(args->flags.flags, ev_name, cur_field_name);
- break;
- case TEP_PRINT_SYMBOL:
- define_event_symbols(event, ev_name, args->symbol.field);
- define_symbolic_field(ev_name, cur_field_name);
- define_symbolic_values(args->symbol.symbols, ev_name,
- cur_field_name);
- break;
- case TEP_PRINT_HEX:
- case TEP_PRINT_HEX_STR:
- define_event_symbols(event, ev_name, args->hex.field);
- define_event_symbols(event, ev_name, args->hex.size);
- break;
- case TEP_PRINT_INT_ARRAY:
- define_event_symbols(event, ev_name, args->int_array.field);
- define_event_symbols(event, ev_name, args->int_array.count);
- define_event_symbols(event, ev_name, args->int_array.el_size);
- break;
- case TEP_PRINT_BSTRING:
- case TEP_PRINT_DYNAMIC_ARRAY:
- case TEP_PRINT_DYNAMIC_ARRAY_LEN:
- case TEP_PRINT_STRING:
- case TEP_PRINT_BITMASK:
- break;
- case TEP_PRINT_TYPE:
- define_event_symbols(event, ev_name, args->typecast.item);
- break;
- case TEP_PRINT_OP:
- if (strcmp(args->op.op, ":") == 0)
- zero_flag_atom = 1;
- define_event_symbols(event, ev_name, args->op.left);
- define_event_symbols(event, ev_name, args->op.right);
- break;
- case TEP_PRINT_FUNC:
- default:
- pr_err("Unsupported print arg type\n");
- /* we should warn... */
- return;
- }
-
- if (args->next)
- define_event_symbols(event, ev_name, args->next);
-}
-
-static SV *perl_process_callchain(struct perf_sample *sample,
- struct evsel *evsel,
- struct addr_location *al)
-{
- struct callchain_cursor *cursor;
- AV *list;
-
- list = newAV();
- if (!list)
- goto exit;
-
- if (!symbol_conf.use_callchain || !sample->callchain)
- goto exit;
-
- cursor = get_tls_callchain_cursor();
-
- if (thread__resolve_callchain(al->thread, cursor, evsel,
- sample, NULL, NULL, scripting_max_stack) != 0) {
- pr_err("Failed to resolve callchain. Skipping\n");
- goto exit;
- }
- callchain_cursor_commit(cursor);
-
-
- while (1) {
- HV *elem;
- struct callchain_cursor_node *node;
- node = callchain_cursor_current(cursor);
- if (!node)
- break;
-
- elem = newHV();
- if (!elem)
- goto exit;
-
- if (!hv_stores(elem, "ip", newSVuv(node->ip))) {
- hv_undef(elem);
- goto exit;
- }
-
- if (node->ms.sym) {
- HV *sym = newHV();
- if (!sym) {
- hv_undef(elem);
- goto exit;
- }
- if (!hv_stores(sym, "start", newSVuv(node->ms.sym->start)) ||
- !hv_stores(sym, "end", newSVuv(node->ms.sym->end)) ||
- !hv_stores(sym, "binding", newSVuv(node->ms.sym->binding)) ||
- !hv_stores(sym, "name", newSVpvn(node->ms.sym->name,
- node->ms.sym->namelen)) ||
- !hv_stores(elem, "sym", newRV_noinc((SV*)sym))) {
- hv_undef(sym);
- hv_undef(elem);
- goto exit;
- }
- }
-
- if (node->ms.map) {
- struct map *map = node->ms.map;
- struct dso *dso = map ? map__dso(map) : NULL;
- const char *dsoname = "[unknown]";
-
- if (dso) {
- if (symbol_conf.show_kernel_path && dso__long_name(dso))
- dsoname = dso__long_name(dso);
- else
- dsoname = dso__name(dso);
- }
- if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) {
- hv_undef(elem);
- goto exit;
- }
- }
-
- callchain_cursor_advance(cursor);
- av_push(list, newRV_noinc((SV*)elem));
- }
-
-exit:
- return newRV_noinc((SV*)list);
-}
-
-static void perl_process_tracepoint(struct perf_sample *sample,
- struct evsel *evsel,
- struct addr_location *al)
-{
- struct thread *thread = al->thread;
- struct tep_event *event;
- struct tep_format_field *field;
- static char handler[256];
- unsigned long long val;
- unsigned long s, ns;
- int pid;
- int cpu = sample->cpu;
- void *data = sample->raw_data;
- unsigned long long nsecs = sample->time;
- const char *comm = thread__comm_str(thread);
- DECLARE_BITMAP(events_defined, TRACE_EVENT_TYPE_MAX);
-
- bitmap_zero(events_defined, TRACE_EVENT_TYPE_MAX);
- dSP;
-
- if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
- return;
-
- event = evsel__tp_format(evsel);
- if (!event) {
- pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config);
- return;
- }
-
- pid = raw_field_value(event, "common_pid", data);
-
- sprintf(handler, "%s::%s", event->system, event->name);
-
- if (!__test_and_set_bit(event->id, events_defined))
- define_event_symbols(event, handler, event->print_fmt.args);
-
- s = nsecs / NSEC_PER_SEC;
- ns = nsecs - s * NSEC_PER_SEC;
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
-
- XPUSHs(sv_2mortal(newSVpv(handler, 0)));
- XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
- XPUSHs(sv_2mortal(newSVuv(cpu)));
- XPUSHs(sv_2mortal(newSVuv(s)));
- XPUSHs(sv_2mortal(newSVuv(ns)));
- XPUSHs(sv_2mortal(newSViv(pid)));
- XPUSHs(sv_2mortal(newSVpv(comm, 0)));
- XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));
-
- /* common fields other than pid can be accessed via xsub fns */
-
- for (field = event->format.fields; field; field = field->next) {
- if (field->flags & TEP_FIELD_IS_STRING) {
- int offset;
- if (field->flags & TEP_FIELD_IS_DYNAMIC) {
- offset = *(int *)(data + field->offset);
- offset &= 0xffff;
- if (tep_field_is_relative(field->flags))
- offset += field->offset + field->size;
- } else
- offset = field->offset;
- XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
- } else { /* FIELD_IS_NUMERIC */
- val = read_size(event, data + field->offset,
- field->size);
- if (field->flags & TEP_FIELD_IS_SIGNED) {
- XPUSHs(sv_2mortal(newSViv(val)));
- } else {
- XPUSHs(sv_2mortal(newSVuv(val)));
- }
- }
- }
-
- PUTBACK;
-
- if (get_cv(handler, 0))
- call_pv(handler, G_SCALAR);
- else if (get_cv("main::trace_unhandled", 0)) {
- XPUSHs(sv_2mortal(newSVpv(handler, 0)));
- XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
- XPUSHs(sv_2mortal(newSVuv(cpu)));
- XPUSHs(sv_2mortal(newSVuv(nsecs)));
- XPUSHs(sv_2mortal(newSViv(pid)));
- XPUSHs(sv_2mortal(newSVpv(comm, 0)));
- XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));
- call_pv("main::trace_unhandled", G_SCALAR);
- }
- SPAGAIN;
- PUTBACK;
- FREETMPS;
- LEAVE;
-}
-
-static void perl_process_event_generic(union perf_event *event,
- struct perf_sample *sample,
- struct evsel *evsel)
-{
- dSP;
-
- if (!get_cv("process_event", 0))
- return;
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
- XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size)));
- XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->core.attr, sizeof(evsel->core.attr))));
- XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample))));
- XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size)));
- PUTBACK;
- call_pv("process_event", G_SCALAR);
- SPAGAIN;
- PUTBACK;
- FREETMPS;
- LEAVE;
-}
-
-static void perl_process_event(union perf_event *event,
- struct perf_sample *sample,
- struct evsel *evsel,
- struct addr_location *al,
- struct addr_location *addr_al)
-{
- scripting_context__update(scripting_context, event, sample, evsel, al, addr_al);
- perl_process_tracepoint(sample, evsel, al);
- perl_process_event_generic(event, sample, evsel);
-}
-
-static void run_start_sub(void)
-{
- dSP; /* access to Perl stack */
- PUSHMARK(SP);
-
- if (get_cv("main::trace_begin", 0))
- call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
-}
-
-/*
- * Start trace script
- */
-static int perl_start_script(const char *script, int argc, const char **argv,
- struct perf_session *session)
-{
- const char **command_line;
- int i, err = 0;
-
- scripting_context->session = session;
-
- command_line = malloc((argc + 2) * sizeof(const char *));
- if (!command_line)
- return -ENOMEM;
-
- command_line[0] = "";
- command_line[1] = script;
- for (i = 2; i < argc + 2; i++)
- command_line[i] = argv[i - 2];
-
- my_perl = perl_alloc();
- perl_construct(my_perl);
-
- if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
- (char **)NULL)) {
- err = -1;
- goto error;
- }
-
- if (perl_run(my_perl)) {
- err = -1;
- goto error;
- }
-
- if (SvTRUE(ERRSV)) {
- err = -1;
- goto error;
- }
-
- run_start_sub();
-
- free(command_line);
- return 0;
-error:
- perl_free(my_perl);
- free(command_line);
-
- return err;
-}
-
-static int perl_flush_script(void)
-{
- return 0;
-}
-
-/*
- * Stop trace script
- */
-static int perl_stop_script(void)
-{
- dSP; /* access to Perl stack */
- PUSHMARK(SP);
-
- if (get_cv("main::trace_end", 0))
- call_pv("main::trace_end", G_DISCARD | G_NOARGS);
-
- perl_destruct(my_perl);
- perl_free(my_perl);
-
- return 0;
-}
-
-static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
-{
- int i, not_first, count, nr_events;
- struct tep_event **all_events;
- struct tep_event *event = NULL;
- struct tep_format_field *f;
- char fname[PATH_MAX];
- FILE *ofp;
-
- sprintf(fname, "%s.pl", outfile);
- ofp = fopen(fname, "w");
- if (ofp == NULL) {
- fprintf(stderr, "couldn't open %s\n", fname);
- return -1;
- }
-
- fprintf(ofp, "# perf script event handlers, "
- "generated by perf script -g perl\n");
-
- fprintf(ofp, "# Licensed under the terms of the GNU GPL"
- " License version 2\n\n");
-
- fprintf(ofp, "# The common_* event handler fields are the most useful "
- "fields common to\n");
-
- fprintf(ofp, "# all events. They don't necessarily correspond to "
- "the 'common_*' fields\n");
-
- fprintf(ofp, "# in the format files. Those fields not available as "
- "handler params can\n");
-
- fprintf(ofp, "# be retrieved using Perl functions of the form "
- "common_*($context).\n");
-
- fprintf(ofp, "# See Context.pm for the list of available "
- "functions.\n\n");
-
- fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
- "Perf-Trace-Util/lib\";\n");
-
- fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
- fprintf(ofp, "use Perf::Trace::Core;\n");
- fprintf(ofp, "use Perf::Trace::Context;\n");
- fprintf(ofp, "use Perf::Trace::Util;\n\n");
-
- fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
- fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n");
-
-
- fprintf(ofp, "\n\
-sub print_backtrace\n\
-{\n\
- my $callchain = shift;\n\
- for my $node (@$callchain)\n\
- {\n\
- if(exists $node->{sym})\n\
- {\n\
- printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\
- }\n\
- else\n\
- {\n\
- printf( \"\\t[\\%%x]\\n\", $node{ip});\n\
- }\n\
- }\n\
-}\n\n\
-");
-
- nr_events = tep_get_events_count(pevent);
- all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
-
- for (i = 0; all_events && i < nr_events; i++) {
- event = all_events[i];
- fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
- fprintf(ofp, "\tmy (");
-
- fprintf(ofp, "$event_name, ");
- fprintf(ofp, "$context, ");
- fprintf(ofp, "$common_cpu, ");
- fprintf(ofp, "$common_secs, ");
- fprintf(ofp, "$common_nsecs,\n");
- fprintf(ofp, "\t $common_pid, ");
- fprintf(ofp, "$common_comm, ");
- fprintf(ofp, "$common_callchain,\n\t ");
-
- not_first = 0;
- count = 0;
-
- for (f = event->format.fields; f; f = f->next) {
- if (not_first++)
- fprintf(ofp, ", ");
- if (++count % 5 == 0)
- fprintf(ofp, "\n\t ");
-
- fprintf(ofp, "$%s", f->name);
- }
- fprintf(ofp, ") = @_;\n\n");
-
- fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
- "$common_secs, $common_nsecs,\n\t "
- "$common_pid, $common_comm, $common_callchain);\n\n");
-
- fprintf(ofp, "\tprintf(\"");
-
- not_first = 0;
- count = 0;
-
- for (f = event->format.fields; f; f = f->next) {
- if (not_first++)
- fprintf(ofp, ", ");
- if (count && count % 4 == 0) {
- fprintf(ofp, "\".\n\t \"");
- }
- count++;
-
- fprintf(ofp, "%s=", f->name);
- if (f->flags & TEP_FIELD_IS_STRING ||
- f->flags & TEP_FIELD_IS_FLAG ||
- f->flags & TEP_FIELD_IS_SYMBOLIC)
- fprintf(ofp, "%%s");
- else if (f->flags & TEP_FIELD_IS_SIGNED)
- fprintf(ofp, "%%d");
- else
- fprintf(ofp, "%%u");
- }
-
- fprintf(ofp, "\\n\",\n\t ");
-
- not_first = 0;
- count = 0;
-
- for (f = event->format.fields; f; f = f->next) {
- if (not_first++)
- fprintf(ofp, ", ");
-
- if (++count % 5 == 0)
- fprintf(ofp, "\n\t ");
-
- if (f->flags & TEP_FIELD_IS_FLAG) {
- if ((count - 1) % 5 != 0) {
- fprintf(ofp, "\n\t ");
- count = 4;
- }
- fprintf(ofp, "flag_str(\"");
- fprintf(ofp, "%s::%s\", ", event->system,
- event->name);
- fprintf(ofp, "\"%s\", $%s)", f->name,
- f->name);
- } else if (f->flags & TEP_FIELD_IS_SYMBOLIC) {
- if ((count - 1) % 5 != 0) {
- fprintf(ofp, "\n\t ");
- count = 4;
- }
- fprintf(ofp, "symbol_str(\"");
- fprintf(ofp, "%s::%s\", ", event->system,
- event->name);
- fprintf(ofp, "\"%s\", $%s)", f->name,
- f->name);
- } else
- fprintf(ofp, "$%s", f->name);
- }
-
- fprintf(ofp, ");\n\n");
-
- fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
-
- fprintf(ofp, "}\n\n");
- }
-
- fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
- "$common_cpu, $common_secs, $common_nsecs,\n\t "
- "$common_pid, $common_comm, $common_callchain) = @_;\n\n");
-
- fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
- "$common_secs, $common_nsecs,\n\t $common_pid, "
- "$common_comm, $common_callchain);\n");
- fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
- fprintf(ofp, "}\n\n");
-
- fprintf(ofp, "sub print_header\n{\n"
- "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
- "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
- "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n");
-
- fprintf(ofp,
- "\n# Packed byte string args of process_event():\n"
- "#\n"
- "# $event:\tunion perf_event\tutil/event.h\n"
- "# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n"
- "# $sample:\tstruct perf_sample\tutil/event.h\n"
- "# $raw_data:\tperf_sample->raw_data\tutil/event.h\n"
- "\n"
- "sub process_event\n"
- "{\n"
- "\tmy ($event, $attr, $sample, $raw_data) = @_;\n"
- "\n"
- "\tmy @event\t= unpack(\"LSS\", $event);\n"
- "\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n"
- "\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n"
- "\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n"
- "\n"
- "\tuse Data::Dumper;\n"
- "\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n"
- "}\n");
-
- fclose(ofp);
-
- fprintf(stderr, "generated Perl script: %s\n", fname);
-
- return 0;
-}
-
-struct scripting_ops perl_scripting_ops = {
- .name = "Perl",
- .dirname = "perl",
- .start_script = perl_start_script,
- .flush_script = perl_flush_script,
- .stop_script = perl_stop_script,
- .process_event = perl_process_event,
- .generate_script = perl_generate_script,
-};
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index fa850e44cb46..a82472419611 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -206,72 +206,7 @@ void setup_python_scripting(void)
}
#endif
-#ifdef HAVE_LIBTRACEEVENT
-static void print_perl_unsupported_msg(void)
-{
- fprintf(stderr, "Perl scripting not supported."
- " Install libperl and rebuild perf to enable it.\n"
- "For example:\n # apt-get install libperl-dev (ubuntu)"
- "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
- "\n etc.\n");
-}
-
-static int perl_start_script_unsupported(const char *script __maybe_unused,
- int argc __maybe_unused,
- const char **argv __maybe_unused,
- struct perf_session *session __maybe_unused)
-{
- print_perl_unsupported_msg();
-
- return -1;
-}
-
-static int perl_generate_script_unsupported(struct tep_handle *pevent
- __maybe_unused,
- const char *outfile __maybe_unused)
-{
- print_perl_unsupported_msg();
-
- return -1;
-}
-
-struct scripting_ops perl_scripting_unsupported_ops = {
- .name = "Perl",
- .dirname = "perl",
- .start_script = perl_start_script_unsupported,
- .flush_script = flush_script_unsupported,
- .stop_script = stop_script_unsupported,
- .process_event = process_event_unsupported,
- .generate_script = perl_generate_script_unsupported,
-};
-
-static void register_perl_scripting(struct scripting_ops *scripting_ops)
-{
- if (scripting_context == NULL)
- scripting_context = malloc(sizeof(*scripting_context));
-
- if (scripting_context == NULL ||
- script_spec_register("Perl", scripting_ops) ||
- script_spec_register("pl", scripting_ops)) {
- pr_err("Error registering Perl script extension: disabling it\n");
- zfree(&scripting_context);
- }
-}
-
-#ifndef HAVE_LIBPERL_SUPPORT
-void setup_perl_scripting(void)
-{
- register_perl_scripting(&perl_scripting_unsupported_ops);
-}
-#else
-extern struct scripting_ops perl_scripting_ops;
-void setup_perl_scripting(void)
-{
- register_perl_scripting(&perl_scripting_ops);
-}
-#endif
-#endif
static const struct {
u32 flags;
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 914d9b69ed62..7bdf44403e3a 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -116,7 +116,7 @@ extern unsigned int scripting_max_stack;
struct scripting_ops *script_spec__lookup(const char *spec);
int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec));
-void setup_perl_scripting(void);
+
void setup_python_scripting(void);
struct scripting_context {
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 56/59] perf script: Refactor to support standalone scripts and remove legacy features
From: Ian Rogers @ 2026-04-25 22:45 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
- Remove -g / --gen-script option as it is no longer needed.
- Hide -s / --script option to imply running standalone scripts
directly.
- Update find_script to search in 'python' instead of
'scripts/python'.
- Add support for launching standalone scripts using fork and execvp,
skipping the event processing loop.
- Update list_available_scripts to look for .py files directly in
'python' directory.
- Remove all references to scripting_ops and clean up unused functions
and variables.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2:
- Fixed strncat buffer overflow: Updated the strncat call in
find_script() to correctly use the remaining capacity of the
destination buffer instead of sizeof(path) - 1 . The declaration of
len was moved to the top of the function to conform to C style
guidelines.
- Fixed execvp path searching: If find_script() finds a local file in
the current directory without a slash, it now prepends ./ to it.
This ensures that execvp() executed by the child process knows to
look in the current directory rather than searching the system
$PATH .
- Fixed premature loop termination in docstring parsing: Removed a
check in read_script_info() that caused the loop to terminate early
if any fallback description was found (like an SPDX
identifier). This restores the intended behavior of searching the
entire header for a better "description:" tag.
- Updated subcommands and usage: Removed "record" and "report" from
the usage text and stopped passing them as valid subcommands to
parse_options_subcommand() .
- Fixed lost command-line options: Reconstructed the arguments passed
to the standalone script to include -i and the input file path,
ensuring that the user's choice of input file is not lost.
- Added error message on execvp failure: Added a pr_err call in the
child process to print a descriptive error message if execvp()
fails to launch the script.
- Fixed uninitialized status in waitpid : Initialized status to 0 and
verified that waitpid() successfully returned the child's PID
before evaluating its exit status. Also removed unnecessary braces
and fixed indentation in that block.
---
tools/perf/builtin-script.c | 767 +++++++++---------------
tools/perf/util/Build | 1 -
tools/perf/util/scripting-engines/Build | 1 -
tools/perf/util/trace-event-parse.c | 65 --
tools/perf/util/trace-event-scripting.c | 333 ----------
tools/perf/util/trace-event.h | 75 +--
6 files changed, 294 insertions(+), 948 deletions(-)
delete mode 100644 tools/perf/util/scripting-engines/Build
delete mode 100644 tools/perf/util/trace-event-scripting.c
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c0949556d1bb..9b672edac2ca 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -18,6 +18,7 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <sys/utsname.h>
#include <unistd.h>
@@ -77,7 +78,6 @@
#endif
static char const *script_name;
-static char const *generate_script_lang;
static bool reltime;
static bool deltatime;
static u64 initial_time;
@@ -95,6 +95,7 @@ static int max_blocks;
static struct dlfilter *dlfilter;
static int dlargc;
static char **dlargv;
+static unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
enum perf_output_field {
PERF_OUTPUT_COMM = 1ULL << 0,
@@ -1730,6 +1731,143 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample,
return printed;
}
+#define SAMPLE_FLAGS_BUF_SIZE 64
+#define SAMPLE_FLAGS_STR_ALIGNED_SIZE 21
+
+static int sample_flags_to_name(u32 flags, char *str, size_t size)
+{
+ static const struct {
+ u32 flags;
+ const char *name;
+ } sample_flags[] = {
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "jcc"},
+ {PERF_IP_FLAG_BRANCH, "jmp"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, "int"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, "iret"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "syscall"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "sysret"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "async"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_INTERRUPT,
+ "hw int"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "tx abrt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "tr strt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vmentry"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vmexit"},
+ {0, NULL}
+ };
+ static const struct {
+ u32 flags;
+ const char *name;
+ } branch_events[] = {
+ {PERF_IP_FLAG_BRANCH_MISS, "miss"},
+ {PERF_IP_FLAG_NOT_TAKEN, "not_taken"},
+ {0, NULL}
+ };
+ int i;
+ const char *prefix;
+ int pos = 0, ret, ev_idx = 0;
+ u32 xf = flags & PERF_ADDITIONAL_STATE_MASK;
+ u32 types, events;
+ char xs[16] = { 0 };
+
+ /* Clear additional state bits */
+ flags &= ~PERF_ADDITIONAL_STATE_MASK;
+
+ if (flags & PERF_IP_FLAG_TRACE_BEGIN)
+ prefix = "tr strt ";
+ else if (flags & PERF_IP_FLAG_TRACE_END)
+ prefix = "tr end ";
+ else
+ prefix = "";
+
+ ret = snprintf(str + pos, size - pos, "%s", prefix);
+ if (ret < 0)
+ return ret;
+ pos += ret;
+
+ flags &= ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END);
+
+ types = flags & ~PERF_IP_FLAG_BRANCH_EVENT_MASK;
+ for (i = 0; sample_flags[i].name; i++) {
+ if (sample_flags[i].flags != types)
+ continue;
+
+ ret = snprintf(str + pos, size - pos, "%s", sample_flags[i].name);
+ if (ret < 0)
+ return ret;
+ pos += ret;
+ break;
+ }
+
+ events = flags & PERF_IP_FLAG_BRANCH_EVENT_MASK;
+ for (i = 0; branch_events[i].name; i++) {
+ if (!(branch_events[i].flags & events))
+ continue;
+
+ ret = snprintf(str + pos, size - pos, !ev_idx ? "/%s" : ",%s",
+ branch_events[i].name);
+ if (ret < 0)
+ return ret;
+ pos += ret;
+ ev_idx++;
+ }
+
+ /* Add an end character '/' for events */
+ if (ev_idx) {
+ ret = snprintf(str + pos, size - pos, "/");
+ if (ret < 0)
+ return ret;
+ pos += ret;
+ }
+
+ if (!xf)
+ return pos;
+
+ snprintf(xs, sizeof(xs), "(%s%s%s)",
+ flags & PERF_IP_FLAG_IN_TX ? "x" : "",
+ flags & PERF_IP_FLAG_INTR_DISABLE ? "D" : "",
+ flags & PERF_IP_FLAG_INTR_TOGGLE ? "t" : "");
+
+ /* Right align the string if its length is less than the limit */
+ if ((pos + strlen(xs)) < SAMPLE_FLAGS_STR_ALIGNED_SIZE)
+ ret = snprintf(str + pos, size - pos, "%*s",
+ (int)(SAMPLE_FLAGS_STR_ALIGNED_SIZE - ret), xs);
+ else
+ ret = snprintf(str + pos, size - pos, " %s", xs);
+ if (ret < 0)
+ return ret;
+
+ return pos + ret;
+}
+
+static int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz)
+{
+ const char *chars = PERF_IP_FLAG_CHARS;
+ const size_t n = strlen(PERF_IP_FLAG_CHARS);
+ size_t i, pos = 0;
+ int ret;
+
+ ret = sample_flags_to_name(flags, str, sz);
+ if (ret > 0)
+ return ret;
+
+ for (i = 0; i < n; i++, flags >>= 1) {
+ if ((flags & 1) && pos < sz)
+ str[pos++] = chars[i];
+ }
+ for (; i < 32; i++, flags >>= 1) {
+ if ((flags & 1) && pos < sz)
+ str[pos++] = '?';
+ }
+ if (pos < sz)
+ str[pos] = 0;
+
+ return pos;
+}
+
static int perf_sample__fprintf_flags(u32 flags, FILE *fp)
{
char str[SAMPLE_FLAGS_BUF_SIZE];
@@ -2571,8 +2709,6 @@ static void process_event(struct perf_script *script,
fflush(fp);
}
-static struct scripting_ops *scripting_ops;
-
static void __process_stat(struct evsel *counter, u64 tstamp)
{
int nthreads = perf_thread_map__nr(counter->core.threads);
@@ -2607,35 +2743,14 @@ static void __process_stat(struct evsel *counter, u64 tstamp)
static void process_stat(struct evsel *counter, u64 tstamp)
{
- if (scripting_ops && scripting_ops->process_stat)
- scripting_ops->process_stat(&stat_config, counter, tstamp);
- else
- __process_stat(counter, tstamp);
+ __process_stat(counter, tstamp);
}
-static void process_stat_interval(u64 tstamp)
+static void process_stat_interval(u64 tstamp __maybe_unused)
{
- if (scripting_ops && scripting_ops->process_stat_interval)
- scripting_ops->process_stat_interval(tstamp);
}
-static void setup_scripting(void)
-{
- setup_python_scripting();
-}
-
-static int flush_scripting(void)
-{
- return scripting_ops ? scripting_ops->flush_script() : 0;
-}
-
-static int cleanup_scripting(void)
-{
- pr_debug("\nperf script stopped\n");
-
- return scripting_ops ? scripting_ops->stop_script() : 0;
-}
static bool filter_cpu(struct perf_sample *sample)
{
@@ -2708,19 +2823,7 @@ static int process_sample_event(const struct perf_tool *tool,
goto out_put;
}
- if (scripting_ops) {
- struct addr_location *addr_al_ptr = NULL;
-
- if ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) &&
- sample_addr_correlates_sym(&evsel->core.attr)) {
- if (!addr_al.thread)
- thread__resolve(al.thread, &addr_al, sample);
- addr_al_ptr = &addr_al;
- }
- scripting_ops->process_event(event, sample, evsel, &al, addr_al_ptr);
- } else {
- process_event(scr, sample, evsel, &al, &addr_al, machine);
- }
+ process_event(scr, sample, evsel, &al, &addr_al, machine);
out_put:
addr_location__exit(&addr_al);
@@ -3029,8 +3132,7 @@ static int process_switch_event(const struct perf_tool *tool,
if (perf_event__process_switch(tool, event, sample, machine) < 0)
return -1;
- if (scripting_ops && scripting_ops->process_switch && !filter_cpu(sample))
- scripting_ops->process_switch(event, sample, machine);
+
if (!script->show_switch_events)
return 0;
@@ -3039,17 +3141,7 @@ static int process_switch_event(const struct perf_tool *tool,
sample->tid);
}
-static int process_auxtrace_error(const struct perf_tool *tool,
- struct perf_session *session,
- union perf_event *event)
-{
- if (scripting_ops && scripting_ops->process_auxtrace_error) {
- scripting_ops->process_auxtrace_error(session, event);
- return 0;
- }
- return perf_event__process_auxtrace_error(tool, session, event);
-}
static int
process_lost_event(const struct perf_tool *tool,
@@ -3063,12 +3155,11 @@ process_lost_event(const struct perf_tool *tool,
static int
process_throttle_event(const struct perf_tool *tool __maybe_unused,
- union perf_event *event,
- struct perf_sample *sample,
- struct machine *machine)
+ union perf_event *event __maybe_unused,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
{
- if (scripting_ops && scripting_ops->process_throttle)
- scripting_ops->process_throttle(event, sample, machine);
+
return 0;
}
@@ -3211,10 +3302,9 @@ static int __cmd_script(struct perf_script *script)
script->tool.mmap = process_mmap_event;
script->tool.mmap2 = process_mmap2_event;
}
- if (script->show_switch_events || (scripting_ops && scripting_ops->process_switch))
+ if (script->show_switch_events)
script->tool.context_switch = process_switch_event;
- if (scripting_ops && scripting_ops->process_auxtrace_error)
- script->tool.auxtrace_error = process_auxtrace_error;
+ script->tool.auxtrace_error = perf_event__process_auxtrace_error;
if (script->show_namespace_events)
script->tool.namespaces = process_namespaces_event;
if (script->show_cgroup_events)
@@ -3251,96 +3341,55 @@ static int __cmd_script(struct perf_script *script)
return ret;
}
-static int list_available_languages_cb(struct scripting_ops *ops, const char *spec)
-{
- fprintf(stderr, " %-42s [%s]\n", spec, ops->name);
- return 0;
-}
-static void list_available_languages(void)
-{
- fprintf(stderr, "\n");
- fprintf(stderr, "Scripting language extensions (used in "
- "perf script -s [spec:]script.[spec]):\n\n");
- script_spec__for_each(&list_available_languages_cb);
- fprintf(stderr, "\n");
-}
/* Find script file relative to current directory or exec path */
static char *find_script(const char *script)
{
char path[PATH_MAX];
+ char *exec_path;
+ size_t len;
- if (!scripting_ops) {
- const char *ext = strrchr(script, '.');
+ if (access(script, R_OK) == 0) {
+ if (!strchr(script, '/')) {
+ snprintf(path, sizeof(path), "./%s", script);
+ script = path;
+ }
+ goto found;
+ }
- if (!ext)
- return NULL;
+ exec_path = get_argv_exec_path();
+ if (!exec_path)
+ return NULL;
- scripting_ops = script_spec__lookup(++ext);
- if (!scripting_ops)
- return NULL;
- }
+ snprintf(path, sizeof(path), "%s/python/%s", exec_path, script);
+ free(exec_path);
+ script = path;
- if (access(script, R_OK)) {
- char *exec_path = get_argv_exec_path();
+ if (access(path, R_OK) == 0)
+ goto found;
- if (!exec_path)
- return NULL;
- snprintf(path, sizeof(path), "%s/scripts/%s/%s",
- exec_path, scripting_ops->dirname, script);
- free(exec_path);
- script = path;
- if (access(script, R_OK))
- return NULL;
- }
+ /* Try with .py suffix. */
+ len = strlen(path);
+
+ strncat(path, ".py", sizeof(path) - len - 1);
+
+ if (access(script, R_OK) == 0)
+ goto found;
+
+ /* Failure to find script. */
+ return NULL;
+
+found:
return strdup(script);
}
static int parse_scriptname(const struct option *opt __maybe_unused,
const char *str, int unset __maybe_unused)
{
- char spec[PATH_MAX];
- const char *script, *ext;
- int len;
-
- if (strcmp(str, "lang") == 0) {
- list_available_languages();
- exit(0);
- }
-
- script = strchr(str, ':');
- if (script) {
- len = script - str;
- if (len >= PATH_MAX) {
- fprintf(stderr, "invalid language specifier");
- return -1;
- }
- strncpy(spec, str, len);
- spec[len] = '\0';
- scripting_ops = script_spec__lookup(spec);
- if (!scripting_ops) {
- fprintf(stderr, "invalid language specifier");
- return -1;
- }
- script++;
- } else {
- script = str;
- ext = strrchr(script, '.');
- if (!ext) {
- fprintf(stderr, "invalid script extension");
- return -1;
- }
- scripting_ops = script_spec__lookup(++ext);
- if (!scripting_ops) {
- fprintf(stderr, "invalid script extension");
- return -1;
- }
- }
-
- script_name = find_script(script);
+ script_name = find_script(str);
if (!script_name)
- script_name = strdup(script);
+ script_name = strdup(str);
return 0;
}
@@ -3551,16 +3600,18 @@ static struct script_desc *script_desc__new(const char *name)
return s;
}
-static void script_desc__delete(struct script_desc *s)
-{
- zfree(&s->name);
- zfree(&s->half_liner);
- zfree(&s->args);
- free(s);
-}
+
static void script_desc__add(struct script_desc *s)
{
+ struct script_desc *pos;
+
+ list_for_each_entry(pos, &script_descs, node) {
+ if (strcasecmp(s->name, pos->name) < 0) {
+ list_add_tail(&s->node, &pos->node);
+ return;
+ }
+ }
list_add_tail(&s->node, &script_descs);
}
@@ -3608,15 +3659,57 @@ static int read_script_info(struct script_desc *desc, const char *filename)
{
char line[BUFSIZ], *p;
FILE *fp;
+ bool in_docstring = false;
+ bool found_description = false;
fp = fopen(filename, "r");
if (!fp)
return -1;
while (fgets(line, sizeof(line), fp)) {
+ static const char * const triple_quote_str[] = {
+ "\"\"\"",
+ "'''",
+ "r\"\"\"",
+ };
p = skip_spaces(line);
if (strlen(p) == 0)
continue;
+
+ if (in_docstring) {
+ if (strlen(p) && p[strlen(p) - 1] == '\n')
+ p[strlen(p) - 1] = '\0';
+ desc->half_liner = strdup(skip_spaces(p));
+ in_docstring = false;
+ found_description = true;
+ break;
+ }
+
+
+ for (size_t i = 0; i < ARRAY_SIZE(triple_quote_str); i++) {
+ const char *quote = triple_quote_str[i];
+
+ if (!strstarts(p, quote))
+ continue;
+
+ p += strlen(quote);
+ p = skip_spaces(p);
+ if (strlen(p) > 0) {
+ if (p[strlen(p) - 1] == '\n')
+ p[strlen(p) - 1] = '\0';
+ p = skip_spaces(p);
+ if (str_ends_with(p, quote))
+ p[strlen(p) - strlen(quote)] = '\0';
+ desc->half_liner = strdup(skip_spaces(p));
+ found_description = true;
+ break;
+ }
+ in_docstring = true;
+ break;
+ }
+ if (in_docstring)
+ continue;
+
if (*p != '#')
continue;
p++;
@@ -3630,13 +3723,15 @@ static int read_script_info(struct script_desc *desc, const char *filename)
if (!strncmp(p, "description:", strlen("description:"))) {
p += strlen("description:");
desc->half_liner = strdup(skip_spaces(p));
- continue;
+ found_description = true;
+ break;
}
- if (!strncmp(p, "args:", strlen("args:"))) {
- p += strlen("args:");
- desc->args = strdup(skip_spaces(p));
- continue;
+ if (!found_description && strlen(p) > 0 &&
+ strncmp(p, "SPDX-License-Identifier", 23)) {
+ desc->half_liner = strdup(p);
+ found_description = true;
+ // Don't break, maybe we find a better "description:" later!
}
}
@@ -3667,9 +3762,9 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
const char *s __maybe_unused,
int unset __maybe_unused)
{
- struct dirent *script_dirent, *lang_dirent;
- char *buf, *scripts_path, *script_path, *lang_path, *first_half;
- DIR *scripts_dir, *lang_dir;
+ struct dirent *script_dirent;
+ char *buf, *scripts_path, *script_path, *first_half;
+ DIR *scripts_dir;
struct script_desc *desc;
char *script_root;
@@ -3680,10 +3775,9 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
}
scripts_path = buf;
script_path = buf + MAXPATHLEN;
- lang_path = buf + 2 * MAXPATHLEN;
first_half = buf + 3 * MAXPATHLEN;
- snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
+ snprintf(scripts_path, MAXPATHLEN, "%s/python", get_argv_exec_path());
scripts_dir = opendir(scripts_path);
if (!scripts_dir) {
@@ -3695,26 +3789,24 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
exit(-1);
}
- for_each_lang(scripts_path, scripts_dir, lang_dirent) {
- scnprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
- lang_dirent->d_name);
- lang_dir = opendir(lang_path);
- if (!lang_dir)
- continue;
+ while ((script_dirent = readdir(scripts_dir)) != NULL) {
+ if (script_dirent->d_type != DT_DIR &&
+ (script_dirent->d_type != DT_UNKNOWN ||
+ !is_directory(scripts_path, script_dirent))) {
- for_each_script(lang_path, lang_dir, script_dirent) {
- script_root = get_script_root(script_dirent, REPORT_SUFFIX);
+ script_root = get_script_root(script_dirent, ".py");
if (script_root) {
desc = script_desc__findnew(script_root);
scnprintf(script_path, MAXPATHLEN, "%s/%s",
- lang_path, script_dirent->d_name);
+ scripts_path, script_dirent->d_name);
read_script_info(desc, script_path);
free(script_root);
}
}
}
+ closedir(scripts_dir);
- fprintf(stdout, "List of available trace scripts:\n");
+ fprintf(stdout, "List of available scripts:\n");
list_for_each_entry(desc, &script_descs, node) {
sprintf(first_half, "%s %s", desc->name,
desc->args ? desc->args : "");
@@ -3754,93 +3846,7 @@ static void free_dlarg(void)
free(dlargv);
}
-static char *get_script_path(const char *script_root, const char *suffix)
-{
- struct dirent *script_dirent, *lang_dirent;
- char scripts_path[MAXPATHLEN];
- char script_path[MAXPATHLEN];
- DIR *scripts_dir, *lang_dir;
- char lang_path[MAXPATHLEN];
- char *__script_root;
-
- snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
-
- scripts_dir = opendir(scripts_path);
- if (!scripts_dir)
- return NULL;
-
- for_each_lang(scripts_path, scripts_dir, lang_dirent) {
- scnprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
- lang_dirent->d_name);
- lang_dir = opendir(lang_path);
- if (!lang_dir)
- continue;
-
- for_each_script(lang_path, lang_dir, script_dirent) {
- __script_root = get_script_root(script_dirent, suffix);
- if (__script_root && !strcmp(script_root, __script_root)) {
- free(__script_root);
- closedir(scripts_dir);
- scnprintf(script_path, MAXPATHLEN, "%s/%s",
- lang_path, script_dirent->d_name);
- closedir(lang_dir);
- return strdup(script_path);
- }
- free(__script_root);
- }
- closedir(lang_dir);
- }
- closedir(scripts_dir);
-
- return NULL;
-}
-
-static bool is_top_script(const char *script_path)
-{
- return ends_with(script_path, "top") != NULL;
-}
-
-static int has_required_arg(char *script_path)
-{
- struct script_desc *desc;
- int n_args = 0;
- char *p;
-
- desc = script_desc__new(NULL);
-
- if (read_script_info(desc, script_path))
- goto out;
-
- if (!desc->args)
- goto out;
-
- for (p = desc->args; *p; p++)
- if (*p == '<')
- n_args++;
-out:
- script_desc__delete(desc);
-
- return n_args;
-}
-
-static int have_cmd(int argc, const char **argv)
-{
- char **__argv = calloc(argc, sizeof(const char *));
- if (!__argv) {
- pr_err("malloc failed\n");
- return -1;
- }
-
- memcpy(__argv, argv, sizeof(const char *) * argc);
- argc = parse_options(argc, (const char **)__argv, record_options,
- NULL, PARSE_OPT_STOP_AT_NON_OPTION);
- free(__argv);
-
- system_wide = (argc == 0);
-
- return 0;
-}
static void script__setup_sample_type(struct perf_script *script)
{
@@ -4026,17 +4032,13 @@ int cmd_script(int argc, const char **argv)
bool show_full_info = false;
bool header = false;
bool header_only = false;
- bool script_started = false;
bool unsorted_dump = false;
bool merge_deferred_callchains = true;
- char *rec_script_path = NULL;
- char *rep_script_path = NULL;
struct perf_session *session;
struct itrace_synth_opts itrace_synth_opts = {
.set = false,
.default_no_sample = true,
};
- char *script_path = NULL;
const char *dlfilter_file = NULL;
const char **__argv;
int i, j, err = 0;
@@ -4057,11 +4059,10 @@ int cmd_script(int argc, const char **argv)
list_available_scripts),
OPT_CALLBACK_NOOPT(0, "list-dlfilters", NULL, NULL, "list available dlfilters",
list_available_dlfilters),
- OPT_CALLBACK('s', "script", NULL, "name",
- "script file name (lang:script name, script name, or *)",
- parse_scriptname),
- OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
- "generate perf-script.xx script in specified language"),
+ { .type = OPTION_CALLBACK, .short_name = 's', .long_name = "script",
+ .value = NULL, .argh = "name",
+ .help = "script file name (lang:script name, script name, or *)",
+ .callback = parse_scriptname, .flags = PARSE_OPT_HIDDEN },
OPT_STRING(0, "dlfilter", &dlfilter_file, "file", "filter .so file name"),
OPT_CALLBACK(0, "dlarg", NULL, "argument", "filter argument",
add_dlarg),
@@ -4185,22 +4186,17 @@ int cmd_script(int argc, const char **argv)
OPTS_EVSWITCH(&script.evswitch),
OPT_END()
};
- const char * const script_subcommands[] = { "record", "report", NULL };
const char *script_usage[] = {
"perf script [<options>]",
- "perf script [<options>] record <script> [<record-options>] <command>",
- "perf script [<options>] report <script> [script-args]",
- "perf script [<options>] <script> [<record-options>] <command>",
- "perf script [<options>] <top-script> [script-args]",
+ "perf script [<options>] <script> [script-args]",
NULL
};
struct perf_env *env;
perf_set_singlethreaded();
- setup_scripting();
- argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage,
+ argc = parse_options_subcommand(argc, argv, options, NULL, script_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (symbol_conf.guestmount ||
@@ -4223,21 +4219,7 @@ int cmd_script(int argc, const char **argv)
if (symbol__validate_sym_arguments())
return -1;
- if (argc > 1 && strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
- rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
- if (!rec_script_path)
- return cmd_record(argc, argv);
- }
- if (argc > 1 && strlen(argv[0]) > 2 && strstarts("report", argv[0])) {
- rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
- if (!rep_script_path) {
- fprintf(stderr,
- "Please specify a valid report script"
- "(see 'perf script -l' for listing)\n");
- return -1;
- }
- }
if (reltime && deltatime) {
fprintf(stderr,
@@ -4253,149 +4235,54 @@ int cmd_script(int argc, const char **argv)
/* make sure PERF_EXEC_PATH is set for scripts */
set_argv_exec_path(get_argv_exec_path());
- if (argc && !script_name && !rec_script_path && !rep_script_path) {
- int live_pipe[2];
- int rep_args;
- pid_t pid;
-
- rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
- rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
-
- if (!rec_script_path && !rep_script_path) {
- script_name = find_script(argv[0]);
- if (script_name) {
- argc -= 1;
- argv += 1;
- goto script_found;
- }
- usage_with_options_msg(script_usage, options,
- "Couldn't find script `%s'\n\n See perf"
- " script -l for available scripts.\n", argv[0]);
- }
-
- if (is_top_script(argv[0])) {
- rep_args = argc - 1;
- } else {
- int rec_args;
-
- rep_args = has_required_arg(rep_script_path);
- rec_args = (argc - 1) - rep_args;
- if (rec_args < 0) {
- usage_with_options_msg(script_usage, options,
- "`%s' script requires options."
- "\n\n See perf script -l for available "
- "scripts and options.\n", argv[0]);
- }
+ if (argc && !script_name) {
+ script_name = find_script(argv[0]);
+ if (script_name) {
+ argc -= 1;
+ argv += 1;
+ goto script_found;
}
+ usage_with_options_msg(script_usage, options,
+ "Couldn't find script `%s'\n\n"
+ " See perf script -l for available scripts.\n", argv[0]);
+ }
+script_found:
- if (pipe(live_pipe) < 0) {
- perror("failed to create pipe");
- return -1;
- }
- pid = fork();
+ if (script_name) {
+ pid_t pid = fork();
if (pid < 0) {
- perror("failed to fork");
- return -1;
+ pr_err("failed to fork\n");
+ return -errno;
}
-
- if (!pid) {
+ if (pid == 0) { /* child */
+ __argv = calloc(argc + 4, sizeof(const char *));
j = 0;
-
- dup2(live_pipe[1], 1);
- close(live_pipe[0]);
-
- if (is_top_script(argv[0])) {
- system_wide = true;
- } else if (!system_wide) {
- if (have_cmd(argc - rep_args, &argv[rep_args]) != 0) {
- err = -1;
- goto out;
- }
- }
-
- __argv = calloc(argc + 6, sizeof(const char *));
if (!__argv) {
- pr_err("malloc failed\n");
- err = -ENOMEM;
- goto out;
+ exit(-ENOMEM);
}
-
- __argv[j++] = "/bin/sh";
- __argv[j++] = rec_script_path;
- if (system_wide)
- __argv[j++] = "-a";
- __argv[j++] = "-q";
- __argv[j++] = "-o";
- __argv[j++] = "-";
- for (i = rep_args + 1; i < argc; i++)
+ __argv[j++] = script_name;
+ if (input_name) {
+ __argv[j++] = "-i";
+ __argv[j++] = input_name;
+ }
+ for (i = 0; i < argc; i++)
__argv[j++] = argv[i];
__argv[j++] = NULL;
- execvp("/bin/sh", (char **)__argv);
- free(__argv);
- exit(-1);
- }
-
- dup2(live_pipe[0], 0);
- close(live_pipe[1]);
-
- __argv = calloc(argc + 4, sizeof(const char *));
- if (!__argv) {
- pr_err("malloc failed\n");
- err = -ENOMEM;
- goto out;
- }
-
- j = 0;
- __argv[j++] = "/bin/sh";
- __argv[j++] = rep_script_path;
- for (i = 1; i < rep_args + 1; i++)
- __argv[j++] = argv[i];
- __argv[j++] = "-i";
- __argv[j++] = "-";
- __argv[j++] = NULL;
-
- execvp("/bin/sh", (char **)__argv);
- free(__argv);
- exit(-1);
- }
-script_found:
- if (rec_script_path)
- script_path = rec_script_path;
- if (rep_script_path)
- script_path = rep_script_path;
-
- if (script_path) {
- j = 0;
-
- if (!rec_script_path)
- system_wide = false;
- else if (!system_wide) {
- if (have_cmd(argc - 1, &argv[1]) != 0) {
- err = -1;
- goto out;
+ execvp(script_name, (char **)__argv);
+ pr_err("failed to execute script '%s': %s\n", script_name, strerror(errno));
+ exit(-errno);
+ } else { /* parent */
+ int status = 0;
+
+ if (waitpid(pid, &status, 0) == pid) {
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else
+ return -1;
}
}
-
- __argv = calloc(argc + 2, sizeof(const char *));
- if (!__argv) {
- pr_err("malloc failed\n");
- err = -ENOMEM;
- goto out;
- }
-
- __argv[j++] = "/bin/sh";
- __argv[j++] = script_path;
- if (system_wide)
- __argv[j++] = "-a";
- for (i = 2; i < argc; i++)
- __argv[j++] = argv[i];
- __argv[j++] = NULL;
-
- execvp("/bin/sh", (char **)__argv);
- free(__argv);
- exit(-1);
}
if (dlfilter_file) {
@@ -4487,77 +4374,12 @@ int cmd_script(int argc, const char **argv)
goto out_delete;
}
#endif
- if (generate_script_lang) {
- struct stat perf_stat;
- int input;
- char *filename = strdup("perf-script");
-
- if (output_set_by_user()) {
- fprintf(stderr,
- "custom fields not supported for generated scripts");
- err = -EINVAL;
- goto out_delete;
- }
-
- input = open(data.path, O_RDONLY); /* input_name */
- if (input < 0) {
- err = -errno;
- perror("failed to open file");
- goto out_delete;
- }
-
- err = fstat(input, &perf_stat);
- if (err < 0) {
- perror("failed to stat file");
- goto out_delete;
- }
-
- if (!perf_stat.st_size) {
- fprintf(stderr, "zero-sized file, nothing to do!\n");
- goto out_delete;
- }
-
- scripting_ops = script_spec__lookup(generate_script_lang);
- if (!scripting_ops && ends_with(generate_script_lang, ".py")) {
- scripting_ops = script_spec__lookup("python");
- free(filename);
- filename = strdup(generate_script_lang);
- filename[strlen(filename) - 3] = '\0';
- } else if (!scripting_ops && ends_with(generate_script_lang, ".pl")) {
- scripting_ops = script_spec__lookup("perl");
- free(filename);
- filename = strdup(generate_script_lang);
- filename[strlen(filename) - 3] = '\0';
- }
- if (!scripting_ops) {
- fprintf(stderr, "invalid language specifier '%s'\n", generate_script_lang);
- err = -ENOENT;
- goto out_delete;
- }
- if (!filename) {
- err = -ENOMEM;
- goto out_delete;
- }
-#ifdef HAVE_LIBTRACEEVENT
- err = scripting_ops->generate_script(session->tevent.pevent, filename);
-#else
- err = scripting_ops->generate_script(NULL, filename);
-#endif
- free(filename);
- goto out_delete;
- }
err = dlfilter__start(dlfilter, session);
if (err)
goto out_delete;
- if (script_name) {
- err = scripting_ops->start_script(script_name, argc, argv, session);
- if (err)
- goto out_delete;
- pr_debug("perf script started with script %s\n\n", script_name);
- script_started = true;
- }
+
err = perf_session__check_output_opt(session);
@@ -4587,7 +4409,6 @@ int cmd_script(int argc, const char **argv)
err = __cmd_script(&script);
- flush_scripting();
if (verbose > 2 || debug_kmaps)
perf_session__dump_kmaps(session);
@@ -4603,10 +4424,8 @@ int cmd_script(int argc, const char **argv)
perf_session__delete(session);
perf_script__exit(&script);
- if (script_started)
- cleanup_scripting();
+
dlfilter__cleanup(dlfilter);
free_dlarg();
-out:
return err;
}
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index fd55d02dd433..9719f8cedc22 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -94,7 +94,6 @@ perf-util-y += tool_pmu.o
perf-util-y += tp_pmu.o
perf-util-y += svghelper.o
perf-util-y += trace-event-info.o
-perf-util-y += trace-event-scripting.o
perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event.o
perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-parse.o
perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-read.o
diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build
deleted file mode 100644
index 54920e7e1d5d..000000000000
--- a/tools/perf/util/scripting-engines/Build
+++ /dev/null
@@ -1 +0,0 @@
-# No embedded scripting engines
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 9c015fc2bcfb..374cf82fd86e 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -14,71 +14,6 @@
#include <linux/kernel.h>
#include <event-parse.h>
-static int get_common_field(struct scripting_context *context,
- int *offset, int *size, const char *type)
-{
- struct tep_handle *pevent = context->pevent;
- struct tep_event *event;
- struct tep_format_field *field;
-
- if (!*size) {
-
- event = tep_get_first_event(pevent);
- if (!event)
- return 0;
-
- field = tep_find_common_field(event, type);
- if (!field)
- return 0;
- *offset = field->offset;
- *size = field->size;
- }
-
- return tep_read_number(pevent, context->event_data + *offset, *size);
-}
-
-int common_lock_depth(struct scripting_context *context)
-{
- static int offset;
- static int size;
- int ret;
-
- ret = get_common_field(context, &size, &offset,
- "common_lock_depth");
- if (ret < 0)
- return -1;
-
- return ret;
-}
-
-int common_flags(struct scripting_context *context)
-{
- static int offset;
- static int size;
- int ret;
-
- ret = get_common_field(context, &size, &offset,
- "common_flags");
- if (ret < 0)
- return -1;
-
- return ret;
-}
-
-int common_pc(struct scripting_context *context)
-{
- static int offset;
- static int size;
- int ret;
-
- ret = get_common_field(context, &size, &offset,
- "common_preempt_count");
- if (ret < 0)
- return -1;
-
- return ret;
-}
-
unsigned long long
raw_field_value(struct tep_event *event, const char *name, void *data)
{
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
deleted file mode 100644
index 0a0a50d9e1e1..000000000000
--- a/tools/perf/util/trace-event-scripting.c
+++ /dev/null
@@ -1,333 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * trace-event-scripting. Scripting engine common and initialization code.
- *
- * Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.com>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#ifdef HAVE_LIBTRACEEVENT
-#include <event-parse.h>
-#endif
-
-#include "debug.h"
-#include "event.h"
-#include "trace-event.h"
-#include "evsel.h"
-#include <linux/perf_event.h>
-#include <linux/zalloc.h>
-#include "util/sample.h"
-
-unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
-
-struct scripting_context *scripting_context;
-
-struct script_spec {
- struct list_head node;
- struct scripting_ops *ops;
- char spec[];
-};
-
-static LIST_HEAD(script_specs);
-
-static struct script_spec *script_spec__new(const char *spec,
- struct scripting_ops *ops)
-{
- struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
-
- if (s != NULL) {
- strcpy(s->spec, spec);
- s->ops = ops;
- }
-
- return s;
-}
-
-static void script_spec__add(struct script_spec *s)
-{
- list_add_tail(&s->node, &script_specs);
-}
-
-static struct script_spec *script_spec__find(const char *spec)
-{
- struct script_spec *s;
-
- list_for_each_entry(s, &script_specs, node)
- if (strcasecmp(s->spec, spec) == 0)
- return s;
- return NULL;
-}
-
-static int script_spec_register(const char *spec, struct scripting_ops *ops)
-{
- struct script_spec *s;
-
- s = script_spec__find(spec);
- if (s)
- return -1;
-
- s = script_spec__new(spec, ops);
- if (!s)
- return -1;
-
- script_spec__add(s);
- return 0;
-}
-
-struct scripting_ops *script_spec__lookup(const char *spec)
-{
- struct script_spec *s = script_spec__find(spec);
-
- if (!s)
- return NULL;
-
- return s->ops;
-}
-
-int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec))
-{
- struct script_spec *s;
- int ret = 0;
-
- list_for_each_entry(s, &script_specs, node) {
- ret = cb(s->ops, s->spec);
- if (ret)
- break;
- }
- return ret;
-}
-
-void scripting_context__update(struct scripting_context *c,
- union perf_event *event,
- struct perf_sample *sample,
- struct evsel *evsel,
- struct addr_location *al,
- struct addr_location *addr_al)
-{
-#ifdef HAVE_LIBTRACEEVENT
- const struct tep_event *tp_format = evsel__tp_format(evsel);
-
- c->pevent = tp_format ? tp_format->tep : NULL;
-#else
- c->pevent = NULL;
-#endif
- c->event_data = sample->raw_data;
- c->event = event;
- c->sample = sample;
- c->evsel = evsel;
- c->al = al;
- c->addr_al = addr_al;
-}
-
-static int flush_script_unsupported(void)
-{
- return 0;
-}
-
-static int stop_script_unsupported(void)
-{
- return 0;
-}
-
-static void process_event_unsupported(union perf_event *event __maybe_unused,
- struct perf_sample *sample __maybe_unused,
- struct evsel *evsel __maybe_unused,
- struct addr_location *al __maybe_unused,
- struct addr_location *addr_al __maybe_unused)
-{
-} static void print_python_unsupported_msg(void)
-{
- fprintf(stderr, "Python scripting not supported."
- " Install libpython and rebuild perf to enable it.\n"
- "For example:\n # apt-get install python-dev (ubuntu)"
- "\n # yum install python-devel (Fedora)"
- "\n etc.\n");
-}
-
-static int python_start_script_unsupported(const char *script __maybe_unused,
- int argc __maybe_unused,
- const char **argv __maybe_unused,
- struct perf_session *session __maybe_unused)
-{
- print_python_unsupported_msg();
-
- return -1;
-}
-
-static int python_generate_script_unsupported(struct tep_handle *pevent
- __maybe_unused,
- const char *outfile
- __maybe_unused)
-{
- print_python_unsupported_msg();
-
- return -1;
-}
-
-struct scripting_ops python_scripting_unsupported_ops = {
- .name = "Python",
- .dirname = "python",
- .start_script = python_start_script_unsupported,
- .flush_script = flush_script_unsupported,
- .stop_script = stop_script_unsupported,
- .process_event = process_event_unsupported,
- .generate_script = python_generate_script_unsupported,
-};
-
-static void register_python_scripting(struct scripting_ops *scripting_ops)
-{
- if (scripting_context == NULL)
- scripting_context = malloc(sizeof(*scripting_context));
-
- if (scripting_context == NULL ||
- script_spec_register("Python", scripting_ops) ||
- script_spec_register("py", scripting_ops)) {
- pr_err("Error registering Python script extension: disabling it\n");
- zfree(&scripting_context);
- }
-}
-
-void setup_python_scripting(void)
-{
- register_python_scripting(&python_scripting_unsupported_ops);
-}
-
-
-static const struct {
- u32 flags;
- const char *name;
-} sample_flags[] = {
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "jcc"},
- {PERF_IP_FLAG_BRANCH, "jmp"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, "int"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, "iret"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "syscall"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "sysret"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "async"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_INTERRUPT,
- "hw int"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "tx abrt"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "tr strt"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vmentry"},
- {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vmexit"},
- {0, NULL}
-};
-
-static const struct {
- u32 flags;
- const char *name;
-} branch_events[] = {
- {PERF_IP_FLAG_BRANCH_MISS, "miss"},
- {PERF_IP_FLAG_NOT_TAKEN, "not_taken"},
- {0, NULL}
-};
-
-static int sample_flags_to_name(u32 flags, char *str, size_t size)
-{
- int i;
- const char *prefix;
- int pos = 0, ret, ev_idx = 0;
- u32 xf = flags & PERF_ADDITIONAL_STATE_MASK;
- u32 types, events;
- char xs[16] = { 0 };
-
- /* Clear additional state bits */
- flags &= ~PERF_ADDITIONAL_STATE_MASK;
-
- if (flags & PERF_IP_FLAG_TRACE_BEGIN)
- prefix = "tr strt ";
- else if (flags & PERF_IP_FLAG_TRACE_END)
- prefix = "tr end ";
- else
- prefix = "";
-
- ret = snprintf(str + pos, size - pos, "%s", prefix);
- if (ret < 0)
- return ret;
- pos += ret;
-
- flags &= ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END);
-
- types = flags & ~PERF_IP_FLAG_BRANCH_EVENT_MASK;
- for (i = 0; sample_flags[i].name; i++) {
- if (sample_flags[i].flags != types)
- continue;
-
- ret = snprintf(str + pos, size - pos, "%s", sample_flags[i].name);
- if (ret < 0)
- return ret;
- pos += ret;
- break;
- }
-
- events = flags & PERF_IP_FLAG_BRANCH_EVENT_MASK;
- for (i = 0; branch_events[i].name; i++) {
- if (!(branch_events[i].flags & events))
- continue;
-
- ret = snprintf(str + pos, size - pos, !ev_idx ? "/%s" : ",%s",
- branch_events[i].name);
- if (ret < 0)
- return ret;
- pos += ret;
- ev_idx++;
- }
-
- /* Add an end character '/' for events */
- if (ev_idx) {
- ret = snprintf(str + pos, size - pos, "/");
- if (ret < 0)
- return ret;
- pos += ret;
- }
-
- if (!xf)
- return pos;
-
- snprintf(xs, sizeof(xs), "(%s%s%s)",
- flags & PERF_IP_FLAG_IN_TX ? "x" : "",
- flags & PERF_IP_FLAG_INTR_DISABLE ? "D" : "",
- flags & PERF_IP_FLAG_INTR_TOGGLE ? "t" : "");
-
- /* Right align the string if its length is less than the limit */
- if ((pos + strlen(xs)) < SAMPLE_FLAGS_STR_ALIGNED_SIZE)
- ret = snprintf(str + pos, size - pos, "%*s",
- (int)(SAMPLE_FLAGS_STR_ALIGNED_SIZE - ret), xs);
- else
- ret = snprintf(str + pos, size - pos, " %s", xs);
- if (ret < 0)
- return ret;
-
- return pos + ret;
-}
-
-int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz)
-{
- const char *chars = PERF_IP_FLAG_CHARS;
- const size_t n = strlen(PERF_IP_FLAG_CHARS);
- size_t i, pos = 0;
- int ret;
-
- ret = sample_flags_to_name(flags, str, sz);
- if (ret > 0)
- return ret;
-
- for (i = 0; i < n; i++, flags >>= 1) {
- if ((flags & 1) && pos < sz)
- str[pos++] = chars[i];
- }
- for (; i < 32; i++, flags >>= 1) {
- if ((flags & 1) && pos < sz)
- str[pos++] = '?';
- }
- if (pos < sz)
- str[pos] = 0;
-
- return pos;
-}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 7bdf44403e3a..19f22ac1faf3 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -7,15 +7,9 @@
#include <sys/types.h>
#include <linux/types.h>
-struct evlist;
struct machine;
-struct perf_sample;
-union perf_event;
-struct perf_tool;
-struct thread;
-struct tep_plugin_list;
-struct evsel;
struct tep_format_field;
+struct tep_plugin_list;
struct trace_event {
struct tep_handle *pevent;
@@ -79,73 +73,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
int fd, bool temp);
int tracing_data_put(struct tracing_data *tdata);
-
-struct addr_location;
-
-struct perf_session;
-struct perf_stat_config;
-
-struct scripting_ops {
- const char *name;
- const char *dirname; /* For script path .../scripts/<dirname>/... */
- int (*start_script)(const char *script, int argc, const char **argv,
- struct perf_session *session);
- int (*flush_script) (void);
- int (*stop_script) (void);
- void (*process_event) (union perf_event *event,
- struct perf_sample *sample,
- struct evsel *evsel,
- struct addr_location *al,
- struct addr_location *addr_al);
- void (*process_switch)(union perf_event *event,
- struct perf_sample *sample,
- struct machine *machine);
- void (*process_auxtrace_error)(struct perf_session *session,
- union perf_event *event);
- void (*process_stat)(struct perf_stat_config *config,
- struct evsel *evsel, u64 tstamp);
- void (*process_stat_interval)(u64 tstamp);
- void (*process_throttle)(union perf_event *event,
- struct perf_sample *sample,
- struct machine *machine);
- int (*generate_script) (struct tep_handle *pevent, const char *outfile);
-};
-
-extern unsigned int scripting_max_stack;
-
-struct scripting_ops *script_spec__lookup(const char *spec);
-int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec));
-
-
-void setup_python_scripting(void);
-
-struct scripting_context {
- struct tep_handle *pevent;
- void *event_data;
- union perf_event *event;
- struct perf_sample *sample;
- struct evsel *evsel;
- struct addr_location *al;
- struct addr_location *addr_al;
- struct perf_session *session;
-};
-
-void scripting_context__update(struct scripting_context *scripting_context,
- union perf_event *event,
- struct perf_sample *sample,
- struct evsel *evsel,
- struct addr_location *al,
- struct addr_location *addr_al);
-
-int common_pc(struct scripting_context *context);
-int common_flags(struct scripting_context *context);
-int common_lock_depth(struct scripting_context *context);
-
-#define SAMPLE_FLAGS_BUF_SIZE 64
-#define SAMPLE_FLAGS_STR_ALIGNED_SIZE 21
-
-int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz);
-
#if defined(LIBTRACEEVENT_VERSION) && LIBTRACEEVENT_VERSION >= MAKE_LIBTRACEEVENT_VERSION(1, 5, 0)
#include <event-parse.h>
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 57/59] perf Documentation: Update for standalone Python scripts and remove obsolete data
From: Ian Rogers @ 2026-04-25 22:45 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
- Remove documentation for -g and -s options in perf-script.txt.
- Remove links to perf-script-perl in perf-script.txt.
- Rewrite perf-script-python.txt to describe the new standalone script
usage with perf module.
- Remove obsolete perf-script-perl.txt.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v6:
- Updated `perf-script-python.txt` to use indented code blocks to fix
man page formatting, and documented `find_thread` and `elf_machine`.
---
tools/perf/Documentation/perf-script-perl.txt | 216 ------
.../perf/Documentation/perf-script-python.txt | 713 +++---------------
tools/perf/Documentation/perf-script.txt | 70 +-
3 files changed, 96 insertions(+), 903 deletions(-)
delete mode 100644 tools/perf/Documentation/perf-script-perl.txt
diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
deleted file mode 100644
index 5b479f5e62ff..000000000000
--- a/tools/perf/Documentation/perf-script-perl.txt
+++ /dev/null
@@ -1,216 +0,0 @@
-perf-script-perl(1)
-===================
-
-NAME
-----
-perf-script-perl - Process trace data with a Perl script
-
-SYNOPSIS
---------
-[verse]
-'perf script' [-s [Perl]:script[.pl] ]
-
-DESCRIPTION
------------
-
-This perf script option is used to process perf script data using perf's
-built-in Perl interpreter. It reads and processes the input file and
-displays the results of the trace analysis implemented in the given
-Perl script, if any.
-
-STARTER SCRIPTS
----------------
-
-You can avoid reading the rest of this document by running 'perf script
--g perl' in the same directory as an existing perf.data trace file.
-That will generate a starter script containing a handler for each of
-the event types in the trace file; it simply prints every available
-field for each event in the trace file.
-
-You can also look at the existing scripts in
-~/libexec/perf-core/scripts/perl for typical examples showing how to
-do basic things like aggregate event data, print results, etc. Also,
-the check-perf-script.pl script, while not interesting for its results,
-attempts to exercise all of the main scripting features.
-
-EVENT HANDLERS
---------------
-
-When perf script is invoked using a trace script, a user-defined
-'handler function' is called for each event in the trace. If there's
-no handler function defined for a given event type, the event is
-ignored (or passed to a 'trace_unhandled' function, see below) and the
-next event is processed.
-
-Most of the event's field values are passed as arguments to the
-handler function; some of the less common ones aren't - those are
-available as calls back into the perf executable (see below).
-
-As an example, the following perf record command can be used to record
-all sched_wakeup events in the system:
-
- # perf record -a -e sched:sched_wakeup
-
-Traces meant to be processed using a script should be recorded with
-the above option: -a to enable system-wide collection.
-
-The format file for the sched_wakeup event defines the following fields
-(see /sys/kernel/tracing/events/sched/sched_wakeup/format):
-
-----
- format:
- field:unsigned short common_type;
- field:unsigned char common_flags;
- field:unsigned char common_preempt_count;
- field:int common_pid;
-
- field:char comm[TASK_COMM_LEN];
- field:pid_t pid;
- field:int prio;
- field:int success;
- field:int target_cpu;
-----
-
-The handler function for this event would be defined as:
-
-----
-sub sched::sched_wakeup
-{
- my ($event_name, $context, $common_cpu, $common_secs,
- $common_nsecs, $common_pid, $common_comm,
- $comm, $pid, $prio, $success, $target_cpu) = @_;
-}
-----
-
-The handler function takes the form subsystem::event_name.
-
-The $common_* arguments in the handler's argument list are the set of
-arguments passed to all event handlers; some of the fields correspond
-to the common_* fields in the format file, but some are synthesized,
-and some of the common_* fields aren't common enough to to be passed
-to every event as arguments but are available as library functions.
-
-Here's a brief description of each of the invariant event args:
-
- $event_name the name of the event as text
- $context an opaque 'cookie' used in calls back into perf
- $common_cpu the cpu the event occurred on
- $common_secs the secs portion of the event timestamp
- $common_nsecs the nsecs portion of the event timestamp
- $common_pid the pid of the current task
- $common_comm the name of the current process
-
-All of the remaining fields in the event's format file have
-counterparts as handler function arguments of the same name, as can be
-seen in the example above.
-
-The above provides the basics needed to directly access every field of
-every event in a trace, which covers 90% of what you need to know to
-write a useful trace script. The sections below cover the rest.
-
-SCRIPT LAYOUT
--------------
-
-Every perf script Perl script should start by setting up a Perl module
-search path and 'use'ing a few support modules (see module
-descriptions below):
-
-----
- use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
- use lib "./Perf-Trace-Util/lib";
- use Perf::Trace::Core;
- use Perf::Trace::Context;
- use Perf::Trace::Util;
-----
-
-The rest of the script can contain handler functions and support
-functions in any order.
-
-Aside from the event handler functions discussed above, every script
-can implement a set of optional functions:
-
-*trace_begin*, if defined, is called before any event is processed and
-gives scripts a chance to do setup tasks:
-
-----
- sub trace_begin
- {
- }
-----
-
-*trace_end*, if defined, is called after all events have been
- processed and gives scripts a chance to do end-of-script tasks, such
- as display results:
-
-----
-sub trace_end
-{
-}
-----
-
-*trace_unhandled*, if defined, is called after for any event that
- doesn't have a handler explicitly defined for it. The standard set
- of common arguments are passed into it:
-
-----
-sub trace_unhandled
-{
- my ($event_name, $context, $common_cpu, $common_secs,
- $common_nsecs, $common_pid, $common_comm) = @_;
-}
-----
-
-The remaining sections provide descriptions of each of the available
-built-in perf script Perl modules and their associated functions.
-
-AVAILABLE MODULES AND FUNCTIONS
--------------------------------
-
-The following sections describe the functions and variables available
-via the various Perf::Trace::* Perl modules. To use the functions and
-variables from the given module, add the corresponding 'use
-Perf::Trace::XXX' line to your perf script script.
-
-Perf::Trace::Core Module
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-These functions provide some essential functions to user scripts.
-
-The *flag_str* and *symbol_str* functions provide human-readable
-strings for flag and symbolic fields. These correspond to the strings
-and values parsed from the 'print fmt' fields of the event format
-files:
-
- flag_str($event_name, $field_name, $field_value) - returns the string representation corresponding to $field_value for the flag field $field_name of event $event_name
- symbol_str($event_name, $field_name, $field_value) - returns the string representation corresponding to $field_value for the symbolic field $field_name of event $event_name
-
-Perf::Trace::Context Module
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Some of the 'common' fields in the event format file aren't all that
-common, but need to be made accessible to user scripts nonetheless.
-
-Perf::Trace::Context defines a set of functions that can be used to
-access this data in the context of the current event. Each of these
-functions expects a $context variable, which is the same as the
-$context variable passed into every event handler as the second
-argument.
-
- common_pc($context) - returns common_preempt count for the current event
- common_flags($context) - returns common_flags for the current event
- common_lock_depth($context) - returns common_lock_depth for the current event
-
-Perf::Trace::Util Module
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Various utility functions for use with perf script:
-
- nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
- nsecs_secs($nsecs) - returns whole secs portion given nsecs
- nsecs_nsecs($nsecs) - returns nsecs remainder given nsecs
- nsecs_str($nsecs) - returns printable string in the form secs.nsecs
- avg($total, $n) - returns average given a sum and a total number of values
-
-SEE ALSO
---------
-linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index 27a1cac6fe76..6bcf98e4e6c6 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -3,676 +3,143 @@ perf-script-python(1)
NAME
----
-perf-script-python - Process trace data with a Python script
+perf-script-python - Process trace data with a Python script using perf module
SYNOPSIS
--------
[verse]
-'perf script' [-s [Python]:script[.py] ]
+'perf script' <script>.py
DESCRIPTION
-----------
-This perf script option is used to process perf script data using perf's
-built-in Python interpreter. It reads and processes the input file and
-displays the results of the trace analysis implemented in the given
-Python script, if any.
+This document describes how to use the `perf` Python module to process
+trace data recorded by `perf record`.
+
+With the removal of embedded Python interpreter from `perf`, scripts
+are now run as standalone Python programs that import the `perf`
+module to access trace data.
A QUICK EXAMPLE
---------------
-This section shows the process, start to finish, of creating a working
-Python script that aggregates and extracts useful information from a
-raw perf script stream. You can avoid reading the rest of this
-document if an example is enough for you; the rest of the document
-provides more details on each step and lists the library functions
-available to script writers.
-
-This example actually details the steps that were used to create the
-'syscall-counts' script you see when you list the available perf script
-scripts via 'perf script -l'. As such, this script also shows how to
-integrate your script into the list of general-purpose 'perf script'
-scripts listed by that command.
-
-The syscall-counts script is a simple script, but demonstrates all the
-basic ideas necessary to create a useful script. Here's an example
-of its output (syscall names are not yet supported, they will appear
-as numbers):
-
-----
-syscall events:
-
-event count
----------------------------------------- -----------
-sys_write 455067
-sys_getdents 4072
-sys_close 3037
-sys_swapoff 1769
-sys_read 923
-sys_sched_setparam 826
-sys_open 331
-sys_newfstat 326
-sys_mmap 217
-sys_munmap 216
-sys_futex 141
-sys_select 102
-sys_poll 84
-sys_setitimer 12
-sys_writev 8
-15 8
-sys_lseek 7
-sys_rt_sigprocmask 6
-sys_wait4 3
-sys_ioctl 3
-sys_set_robust_list 1
-sys_exit 1
-56 1
-sys_access 1
-----
-
-Basically our task is to keep a per-syscall tally that gets updated
-every time a system call occurs in the system. Our script will do
-that, but first we need to record the data that will be processed by
-that script. Theoretically, there are a couple of ways we could do
-that:
-
-- we could enable every event under the tracing/events/syscalls
- directory, but this is over 600 syscalls, well beyond the number
- allowable by perf. These individual syscall events will however be
- useful if we want to later use the guidance we get from the
- general-purpose scripts to drill down and get more detail about
- individual syscalls of interest.
-
-- we can enable the sys_enter and/or sys_exit syscalls found under
- tracing/events/raw_syscalls. These are called for all syscalls; the
- 'id' field can be used to distinguish between individual syscall
- numbers.
-
-For this script, we only need to know that a syscall was entered; we
-don't care how it exited, so we'll use 'perf record' to record only
-the sys_enter events:
-
-----
-# perf record -a -e raw_syscalls:sys_enter
-
-^C[ perf record: Woken up 1 times to write data ]
-[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
-----
-
-The options basically say to collect data for every syscall event
-system-wide and multiplex the per-cpu output into a single stream.
-That single stream will be recorded in a file in the current directory
-called perf.data.
-
-Once we have a perf.data file containing our data, we can use the -g
-'perf script' option to generate a Python script that will contain a
-callback handler for each event type found in the perf.data trace
-stream (for more details, see the STARTER SCRIPTS section).
-
-----
-# perf script -g python
-generated Python script: perf-script.py
-
-The output file created also in the current directory is named
-perf-script.py. Here's the file in its entirety:
-
-# perf script event handlers, generated by perf script -g python
-# Licensed under the terms of the GNU GPL License version 2
-
-# The common_* event handler fields are the most useful fields common to
-# all events. They don't necessarily correspond to the 'common_*' fields
-# in the format files. Those fields not available as handler params can
-# be retrieved using Python functions of the form common_*(context).
-# See the perf-script-python Documentation for the list of available functions.
-
-import os
-import sys
-
-sys.path.append(os.environ['PERF_EXEC_PATH'] + \
- '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
-from perf_trace_context import *
-from Core import *
-
-def trace_begin():
- print "in trace_begin"
-
-def trace_end():
- print "in trace_end"
-
-def raw_syscalls__sys_enter(event_name, context, common_cpu,
- common_secs, common_nsecs, common_pid, common_comm,
- id, args):
- print_header(event_name, common_cpu, common_secs, common_nsecs,
- common_pid, common_comm)
-
- print "id=%d, args=%s\n" % \
- (id, args),
-
-def trace_unhandled(event_name, context, event_fields_dict):
- print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
-
-def print_header(event_name, cpu, secs, nsecs, pid, comm):
- print "%-20s %5u %05u.%09u %8u %-20s " % \
- (event_name, cpu, secs, nsecs, pid, comm),
-----
-
-At the top is a comment block followed by some import statements and a
-path append which every perf script script should include.
-
-Following that are a couple generated functions, trace_begin() and
-trace_end(), which are called at the beginning and the end of the
-script respectively (for more details, see the SCRIPT_LAYOUT section
-below).
-
-Following those are the 'event handler' functions generated one for
-every event in the 'perf record' output. The handler functions take
-the form subsystem\__event_name, and contain named parameters, one for
-each field in the event; in this case, there's only one event,
-raw_syscalls__sys_enter(). (see the EVENT HANDLERS section below for
-more info on event handlers).
-
-The final couple of functions are, like the begin and end functions,
-generated for every script. The first, trace_unhandled(), is called
-every time the script finds an event in the perf.data file that
-doesn't correspond to any event handler in the script. This could
-mean either that the record step recorded event types that it wasn't
-really interested in, or the script was run against a trace file that
-doesn't correspond to the script.
-
-The script generated by -g option simply prints a line for each
-event found in the trace stream i.e. it basically just dumps the event
-and its parameter values to stdout. The print_header() function is
-simply a utility function used for that purpose. Let's rename the
-script and run it to see the default output:
-
-----
-# mv perf-script.py syscall-counts.py
-# perf script -s syscall-counts.py
-
-raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args=
-raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args=
-raw_syscalls__sys_enter 1 00840.847620860 7506 perf id=1, args=
-raw_syscalls__sys_enter 1 00840.847710478 6533 npviewer.bin id=78, args=
-raw_syscalls__sys_enter 1 00840.847719204 6533 npviewer.bin id=142, args=
-raw_syscalls__sys_enter 1 00840.847755445 6533 npviewer.bin id=3, args=
-raw_syscalls__sys_enter 1 00840.847775601 6533 npviewer.bin id=3, args=
-raw_syscalls__sys_enter 1 00840.847781820 6533 npviewer.bin id=3, args=
-.
-.
-.
-----
-
-Of course, for this script, we're not interested in printing every
-trace event, but rather aggregating it in a useful way. So we'll get
-rid of everything to do with printing as well as the trace_begin() and
-trace_unhandled() functions, which we won't be using. That leaves us
-with this minimalistic skeleton:
-
-----
-import os
-import sys
-
-sys.path.append(os.environ['PERF_EXEC_PATH'] + \
- '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
-from perf_trace_context import *
-from Core import *
-
-def trace_end():
- print "in trace_end"
-
-def raw_syscalls__sys_enter(event_name, context, common_cpu,
- common_secs, common_nsecs, common_pid, common_comm,
- id, args):
-----
-
-In trace_end(), we'll simply print the results, but first we need to
-generate some results to print. To do that we need to have our
-sys_enter() handler do the necessary tallying until all events have
-been counted. A hash table indexed by syscall id is a good way to
-store that information; every time the sys_enter() handler is called,
-we simply increment a count associated with that hash entry indexed by
-that syscall id:
-
-----
- syscalls = autodict()
-
- try:
- syscalls[id] += 1
- except TypeError:
- syscalls[id] = 1
-----
-
-The syscalls 'autodict' object is a special kind of Python dictionary
-(implemented in Core.py) that implements Perl's 'autovivifying' hashes
-in Python i.e. with autovivifying hashes, you can assign nested hash
-values without having to go to the trouble of creating intermediate
-levels if they don't exist e.g syscalls[comm][pid][id] = 1 will create
-the intermediate hash levels and finally assign the value 1 to the
-hash entry for 'id' (because the value being assigned isn't a hash
-object itself, the initial value is assigned in the TypeError
-exception. Well, there may be a better way to do this in Python but
-that's what works for now).
-
-Putting that code into the raw_syscalls__sys_enter() handler, we
-effectively end up with a single-level dictionary keyed on syscall id
-and having the counts we've tallied as values.
-
-The print_syscall_totals() function iterates over the entries in the
-dictionary and displays a line for each entry containing the syscall
-name (the dictionary keys contain the syscall ids, which are passed to
-the Util function syscall_name(), which translates the raw syscall
-numbers to the corresponding syscall name strings). The output is
-displayed after all the events in the trace have been processed, by
-calling the print_syscall_totals() function from the trace_end()
-handler called at the end of script processing.
-
-The final script producing the output shown above is shown in its
-entirety below (syscall_name() helper is not yet available, you can
-only deal with id's for now):
-
-----
-import os
-import sys
-
-sys.path.append(os.environ['PERF_EXEC_PATH'] + \
- '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
-from perf_trace_context import *
-from Core import *
-from Util import *
-
-syscalls = autodict()
-
-def trace_end():
- print_syscall_totals()
-
-def raw_syscalls__sys_enter(event_name, context, common_cpu,
- common_secs, common_nsecs, common_pid, common_comm,
- id, args):
- try:
- syscalls[id] += 1
- except TypeError:
- syscalls[id] = 1
-
-def print_syscall_totals():
- if for_comm is not None:
- print "\nsyscall events for %s:\n\n" % (for_comm),
- else:
- print "\nsyscall events:\n\n",
-
- print "%-40s %10s\n" % ("event", "count"),
- print "%-40s %10s\n" % ("----------------------------------------", \
- "-----------"),
-
- for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
- reverse = True):
- print "%-40s %10d\n" % (syscall_name(id), val),
-----
-
-The script can be run just as before:
-
- # perf script -s syscall-counts.py
-
-So those are the essential steps in writing and running a script. The
-process can be generalized to any tracepoint or set of tracepoints
-you're interested in - basically find the tracepoint(s) you're
-interested in by looking at the list of available events shown by
-'perf list' and/or look in /sys/kernel/tracing/events/ for
-detailed event and field info, record the corresponding trace data
-using 'perf record', passing it the list of interesting events,
-generate a skeleton script using 'perf script -g python' and modify the
-code to aggregate and display it for your particular needs.
-
-After you've done that you may end up with a general-purpose script
-that you want to keep around and have available for future use. By
-writing a couple of very simple shell scripts and putting them in the
-right place, you can have your script listed alongside the other
-scripts listed by the 'perf script -l' command e.g.:
-
-----
-# perf script -l
-List of available trace scripts:
- wakeup-latency system-wide min/max/avg wakeup latency
- rw-by-file <comm> r/w activity for a program, by file
- rw-by-pid system-wide r/w activity
-----
-
-A nice side effect of doing this is that you also then capture the
-probably lengthy 'perf record' command needed to record the events for
-the script.
-
-To have the script appear as a 'built-in' script, you write two simple
-scripts, one for recording and one for 'reporting'.
-
-The 'record' script is a shell script with the same base name as your
-script, but with -record appended. The shell script should be put
-into the perf/scripts/python/bin directory in the kernel source tree.
-In that script, you write the 'perf record' command-line needed for
-your script:
-
-----
-# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
-
-#!/bin/bash
-perf record -a -e raw_syscalls:sys_enter
-----
-
-The 'report' script is also a shell script with the same base name as
-your script, but with -report appended. It should also be located in
-the perf/scripts/python/bin directory. In that script, you write the
-'perf script -s' command-line needed for running your script:
+This section shows how to create a simple Python script that reads a
+`perf.data` file and prints event information.
-----
-# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
+Create a file named `print_events.py` with the following content:
-#!/bin/bash
-# description: system-wide syscall counts
-perf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py
-----
+ #!/usr/bin/env python3
+ import perf
-Note that the location of the Python script given in the shell script
-is in the libexec/perf-core/scripts/python directory - this is where
-the script will be copied by 'make install' when you install perf.
-For the installation to install your script there, your script needs
-to be located in the perf/scripts/python directory in the kernel
-source tree:
+ def process_event(sample):
+ print(f"Event: {sample.evsel} on CPU {sample.sample_cpu} at {sample.sample_time}")
-----
-# ls -al kernel-source/tools/perf/scripts/python
-total 32
-drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
-drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
-drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
--rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
-drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util
--rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
-----
+ # Open the session with perf.data file
+ session = perf.session(perf.data("perf.data"), sample=process_event)
-Once you've done that (don't forget to do a new 'make install',
-otherwise your script won't show up at run-time), 'perf script -l'
-should show a new entry for your script:
+ # Process all events
+ session.process_events()
-----
-# perf script -l
-List of available trace scripts:
- wakeup-latency system-wide min/max/avg wakeup latency
- rw-by-file <comm> r/w activity for a program, by file
- rw-by-pid system-wide r/w activity
- syscall-counts system-wide syscall counts
-----
+Make the script executable:
+ $ chmod +x print_events.py
-You can now perform the record step via 'perf script record':
+Record some data:
+ $ perf record -a sleep 1
- # perf script record syscall-counts
+Run the script:
+ $ perf script print_events.py
-and display the output using 'perf script report':
+Or run it directly with Python, ensuring `perf.so` is in your `PYTHONPATH`:
+ $ PYTHONPATH=/path/to/perf/python python3 print_events.py
- # perf script report syscall-counts
-
-STARTER SCRIPTS
+THE PERF MODULE
---------------
-You can quickly get started writing a script for a particular set of
-trace data by generating a skeleton script using 'perf script -g
-python' in the same directory as an existing perf.data trace file.
-That will generate a starter script containing a handler for each of
-the event types in the trace file; it simply prints every available
-field for each event in the trace file.
-
-You can also look at the existing scripts in
-~/libexec/perf-core/scripts/python for typical examples showing how to
-do basic things like aggregate event data, print results, etc. Also,
-the check-perf-script.py script, while not interesting for its results,
-attempts to exercise all of the main scripting features.
-
-EVENT HANDLERS
---------------
-
-When perf script is invoked using a trace script, a user-defined
-'handler function' is called for each event in the trace. If there's
-no handler function defined for a given event type, the event is
-ignored (or passed to a 'trace_unhandled' function, see below) and the
-next event is processed.
-
-Most of the event's field values are passed as arguments to the
-handler function; some of the less common ones aren't - those are
-available as calls back into the perf executable (see below).
-
-As an example, the following perf record command can be used to record
-all sched_wakeup events in the system:
-
- # perf record -a -e sched:sched_wakeup
-
-Traces meant to be processed using a script should be recorded with
-the above option: -a to enable system-wide collection.
-
-The format file for the sched_wakeup event defines the following fields
-(see /sys/kernel/tracing/events/sched/sched_wakeup/format):
-
-----
- format:
- field:unsigned short common_type;
- field:unsigned char common_flags;
- field:unsigned char common_preempt_count;
- field:int common_pid;
-
- field:char comm[TASK_COMM_LEN];
- field:pid_t pid;
- field:int prio;
- field:int success;
- field:int target_cpu;
-----
-
-The handler function for this event would be defined as:
-
-----
-def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
- common_nsecs, common_pid, common_comm,
- comm, pid, prio, success, target_cpu):
- pass
-----
-
-The handler function takes the form subsystem__event_name.
-
-The common_* arguments in the handler's argument list are the set of
-arguments passed to all event handlers; some of the fields correspond
-to the common_* fields in the format file, but some are synthesized,
-and some of the common_* fields aren't common enough to to be passed
-to every event as arguments but are available as library functions.
-
-Here's a brief description of each of the invariant event args:
-
- event_name the name of the event as text
- context an opaque 'cookie' used in calls back into perf
- common_cpu the cpu the event occurred on
- common_secs the secs portion of the event timestamp
- common_nsecs the nsecs portion of the event timestamp
- common_pid the pid of the current task
- common_comm the name of the current process
-
-All of the remaining fields in the event's format file have
-counterparts as handler function arguments of the same name, as can be
-seen in the example above.
-
-The above provides the basics needed to directly access every field of
-every event in a trace, which covers 90% of what you need to know to
-write a useful trace script. The sections below cover the rest.
-
-SCRIPT LAYOUT
--------------
-
-Every perf script Python script should start by setting up a Python
-module search path and 'import'ing a few support modules (see module
-descriptions below):
-
-----
- import os
- import sys
-
- sys.path.append(os.environ['PERF_EXEC_PATH'] + \
- '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
- from perf_trace_context import *
- from Core import *
-----
-
-The rest of the script can contain handler functions and support
-functions in any order.
-
-Aside from the event handler functions discussed above, every script
-can implement a set of optional functions:
-
-*trace_begin*, if defined, is called before any event is processed and
-gives scripts a chance to do setup tasks:
-
-----
-def trace_begin():
- pass
-----
-
-*trace_end*, if defined, is called after all events have been
- processed and gives scripts a chance to do end-of-script tasks, such
- as display results:
-
-----
-def trace_end():
- pass
-----
-
-*trace_unhandled*, if defined, is called after for any event that
- doesn't have a handler explicitly defined for it. The standard set
- of common arguments are passed into it:
-
-----
-def trace_unhandled(event_name, context, event_fields_dict):
- pass
-----
-
-*process_event*, if defined, is called for any non-tracepoint event
-
-----
-def process_event(param_dict):
- pass
-----
-
-*context_switch*, if defined, is called for any context switch
-
-----
-def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_preempt, *x):
- pass
-----
-
-*auxtrace_error*, if defined, is called for any AUX area tracing error
-
-----
-def auxtrace_error(typ, code, cpu, pid, tid, ip, ts, msg, cpumode, *x):
- pass
-----
-
-The remaining sections provide descriptions of each of the available
-built-in perf script Python modules and their associated functions.
-
-AVAILABLE MODULES AND FUNCTIONS
--------------------------------
-
-The following sections describe the functions and variables available
-via the various perf script Python modules. To use the functions and
-variables from the given module, add the corresponding 'from XXXX
-import' line to your perf script script.
-
-Core.py Module
-~~~~~~~~~~~~~~
+The `perf` module provides several classes and functions to interact
+with trace data.
-These functions provide some essential functions to user scripts.
+### Module Functions
-The *flag_str* and *symbol_str* functions provide human-readable
-strings for flag and symbolic fields. These correspond to the strings
-and values parsed from the 'print fmt' fields of the event format
-files:
+- `config_get(name)`: Get a perf config value.
+- `metrics()`: Returns a list of metrics represented as string values in dictionaries.
+- `tracepoint(subsystem, name)`: Get tracepoint config.
+- `parse_events(string)`: Parse a string of events and return an `evlist`.
+- `parse_metrics(string, pmu=None)`: Parse a string of metrics or metric groups and return an `evlist`.
+- `pmus()`: Returns a sequence of PMUs.
+- `syscall_name(num, *, elf_machine=None)`: Turns a syscall number to a string.
+- `syscall_id(name, *, elf_machine=None)`: Turns a syscall name to a number.
- flag_str(event_name, field_name, field_value) - returns the string representation corresponding to field_value for the flag field field_name of event event_name
- symbol_str(event_name, field_name, field_value) - returns the string representation corresponding to field_value for the symbolic field field_name of event event_name
+### `perf.pmu`
-The *autodict* function returns a special kind of Python
-dictionary that implements Perl's 'autovivifying' hashes in Python
-i.e. with autovivifying hashes, you can assign nested hash values
-without having to go to the trouble of creating intermediate levels if
-they don't exist.
+Represents a Performance Monitoring Unit.
- autodict() - returns an autovivifying dictionary instance
+- `events()`: Returns a sequence of events encoded as dictionaries.
+- `name()`: Name of the PMU including suffixes.
+### `perf.evlist`
-perf_trace_context Module
-~~~~~~~~~~~~~~~~~~~~~~~~~
+Represents a list of event selectors.
-Some of the 'common' fields in the event format file aren't all that
-common, but need to be made accessible to user scripts nonetheless.
+- `all_cpus()`: CPU map union of all evsel CPU maps.
+- `metrics()`: List of metric names within the evlist.
+- `compute_metric(name, cpu, thread)`: Compute metric for given name, cpu and thread.
+- `mmap()`: mmap the file descriptor table.
+- `open()`: open the file descriptors.
+- `close()`: close the file descriptors.
+- `poll()`: poll the file descriptor table.
+- `get_pollfd()`: get the poll file descriptor table.
+- `add(evsel)`: adds an event selector to the list.
+- `read_on_cpu(cpu)`: reads an event.
+- `config()`: Apply default record options to the evlist.
+- `disable()`: Disable the evsels in the evlist.
+- `enable()`: Enable the evsels in the evlist.
-perf_trace_context defines a set of functions that can be used to
-access this data in the context of the current event. Each of these
-functions expects a context variable, which is the same as the
-context variable passed into every tracepoint event handler as the second
-argument. For non-tracepoint events, the context variable is also present
-as perf_trace_context.perf_script_context .
+### `perf.evsel`
- common_pc(context) - returns common_preempt count for the current event
- common_flags(context) - returns common_flags for the current event
- common_lock_depth(context) - returns common_lock_depth for the current event
- perf_sample_insn(context) - returns the machine code instruction
- perf_set_itrace_options(context, itrace_options) - set --itrace options if they have not been set already
- perf_sample_srcline(context) - returns source_file_name, line_number
- perf_sample_srccode(context) - returns source_file_name, line_number, source_line
- perf_config_get(config_name) - returns the value of the named config item, or None if unset
+Represents an event selector.
-Util.py Module
-~~~~~~~~~~~~~~
+- `open()`: open the event selector file descriptor table.
+- `cpus()`: CPUs the event is to be used with.
+- `threads()`: threads the event is to be used with.
+- `read(cpu, thread)`: read counters. Returns a count object with `val`, `ena`, and `run` attributes.
-Various utility functions for use with perf script:
+### `perf.session`
- nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
- nsecs_secs(nsecs) - returns whole secs portion given nsecs
- nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs
- nsecs_str(nsecs) - returns printable string in the form secs.nsecs
- avg(total, n) - returns average given a sum and a total number of values
+Manages a trace session.
-SUPPORTED FIELDS
-----------------
+- `__init__(data, sample=None)`: Creates a new session. `data` is a `perf.data` object. `sample` is a callback function called for each sample event.
+- `process_events()`: Reads the trace data and calls the sample callback for each event.
+- `find_thread(tid)`: Returns the thread associated with a TID.
-Currently supported fields:
+### `perf.data`
-ev_name, comm, id, stream_id, pid, tid, cpu, ip, time, period, phys_addr,
-addr, symbol, symoff, dso, time_enabled, time_running, values, callchain,
-brstack, brstacksym, datasrc, datasrc_decode, iregs, uregs,
-weight, transaction, raw_buf, attr, cpumode.
+Represents a trace file.
-Fields that may also be present:
+- `__init__(filename, mode=perf.DATA_MODE_READ)`: Opens a trace file.
- flags - sample flags
- flags_disp - sample flags display
- insn_cnt - instruction count for determining instructions-per-cycle (IPC)
- cyc_cnt - cycle count for determining IPC
- addr_correlates_sym - addr can correlate to a symbol
- addr_dso - addr dso
- addr_symbol - addr symbol
- addr_symoff - addr symbol offset
+### Sample Object
-Some fields have sub items:
+Passed to the callback function in `perf.session`.
-brstack:
- from, to, from_dsoname, to_dsoname, mispred,
- predicted, in_tx, abort, cycles.
+- `evsel`: The event selector (name of the event).
+- `sample_cpu`: The CPU on which the event occurred.
+- `sample_time`: The timestamp of the event.
+- `sample_pid`: The PID of the process.
+- `sample_tid`: The TID of the thread.
+- `raw_buf`: Raw buffer containing event specific data.
-brstacksym:
- items: from, to, pred, in_tx, abort (converted string)
+COUNTER AND METRIC APIS
+-----------------------
-For example,
-We can use this code to print brstack "from", "to", "cycles".
+The following APIs are used in `tools/perf/python/ilist.py` for
+interactive listing and reading of counters and metrics:
-if 'brstack' in dict:
- for entry in dict['brstack']:
- print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"])
+- `perf.pmus()`: Used to get all available PMUs.
+- `pmu.events()`: Used to get all events for a specific PMU.
+- `perf.metrics()`: Used to get all available metrics.
+- `perf.parse_metrics(metric_name, pmu)`: Used to parse a metric and get an `evlist`.
+- `evlist.compute_metric(metric_name, cpu, thread)`: Used to compute a metric value for a specific CPU and thread.
+- `evsel.read(cpu, thread)`: Used to read raw counter values.
SEE ALSO
--------
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 200ea25891d8..93ed1ea704c9 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -9,10 +9,7 @@ SYNOPSIS
--------
[verse]
'perf script' [<options>]
-'perf script' [<options>] record <script> [<record-options>] <command>
-'perf script' [<options>] report <script> [script-args]
-'perf script' [<options>] <script> <required-script-args> [<record-options>] <command>
-'perf script' [<options>] <top-script> [script-args]
+'perf script' [<options>] <script> [script-args]
DESCRIPTION
-----------
@@ -23,52 +20,9 @@ There are several variants of perf script:
'perf script' to see a detailed trace of the workload that was
recorded.
- You can also run a set of pre-canned scripts that aggregate and
- summarize the raw trace data in various ways (the list of scripts is
- available via 'perf script -l'). The following variants allow you to
- record and run those scripts:
-
- 'perf script record <script> <command>' to record the events required
- for 'perf script report'. <script> is the name displayed in the
- output of 'perf script --list' i.e. the actual script name minus any
- language extension. If <command> is not specified, the events are
- recorded using the -a (system-wide) 'perf record' option.
-
- 'perf script report <script> [args]' to run and display the results
- of <script>. <script> is the name displayed in the output of 'perf
- script --list' i.e. the actual script name minus any language
- extension. The perf.data output from a previous run of 'perf script
- record <script>' is used and should be present for this command to
- succeed. [args] refers to the (mainly optional) args expected by
- the script.
-
- 'perf script <script> <required-script-args> <command>' to both
- record the events required for <script> and to run the <script>
- using 'live-mode' i.e. without writing anything to disk. <script>
- is the name displayed in the output of 'perf script --list' i.e. the
- actual script name minus any language extension. If <command> is
- not specified, the events are recorded using the -a (system-wide)
- 'perf record' option. If <script> has any required args, they
- should be specified before <command>. This mode doesn't allow for
- optional script args to be specified; if optional script args are
- desired, they can be specified using separate 'perf script record'
- and 'perf script report' commands, with the stdout of the record step
- piped to the stdin of the report script, using the '-o -' and '-i -'
- options of the corresponding commands.
-
- 'perf script <top-script>' to both record the events required for
- <top-script> and to run the <top-script> using 'live-mode'
- i.e. without writing anything to disk. <top-script> is the name
- displayed in the output of 'perf script --list' i.e. the actual
- script name minus any language extension; a <top-script> is defined
- as any script name ending with the string 'top'.
-
- [<record-options>] can be passed to the record steps of 'perf script
- record' and 'live-mode' variants; this isn't possible however for
- <top-script> 'live-mode' or 'perf script report' variants.
-
- See the 'SEE ALSO' section for links to language-specific
- information on how to write and run your own trace scripts.
+ You can also run standalone scripts that aggregate and summarize the
+ raw trace data in various ways (the list of scripts is available via
+ 'perf script -l').
OPTIONS
-------
@@ -90,18 +44,7 @@ OPTIONS
--list=::
Display a list of available trace scripts.
--s ['lang']::
---script=::
- Process trace data with the given script ([lang]:script[.ext]).
- If the string 'lang' is specified in place of a script name, a
- list of supported languages will be displayed instead.
--g::
---gen-script=::
- Generate a starter script. If a language is given then the
- script is named perf-script.[ext] according to the
- language. If a file path is given then python is used for
- files ending '.py' and perl used for files ending '.pl'.
--dlfilter=<file>::
Filter sample events using the given shared object file.
@@ -543,6 +486,5 @@ include::guest-files.txt[]
SEE ALSO
--------
-linkperf:perf-record[1], linkperf:perf-script-perl[1],
-linkperf:perf-script-python[1], linkperf:perf-intel-pt[1],
-linkperf:perf-dlfilter[1]
+linkperf:perf-record[1], linkperf:perf-script-python[1],
+linkperf:perf-intel-pt[1], linkperf:perf-dlfilter[1]
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 59/59] perf sched stats: Fix segmentation faults in diff mode
From: Ian Rogers @ 2026-04-25 22:45 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
Address several segmentation fault vectors in `perf sched stats diff`:
1. When processing invalid or empty data files, the CPU domain maps may
be NULL. Added NULL checks for `cd_map1` and `cd_map2` in
`show_schedstat_data()` to fail gracefully.
2. When files contain a different number of CPUs or domains, the parallel
list iteration in `show_schedstat_data()` could wrap around the list
heads and dereference invalid memory. Added `list_is_last` checks
to safely terminate iteration at the end of each list.
3. When summarizing CPU statistics in `get_all_cpu_stats()`, parallel list
iteration over domains could similarly wrap around if a CPU has more
domains than the first CPU. Added `list_is_last` check to prevent this.
4. Added bounds checks for `cs1->cpu` and `cs2->cpu` against `nr1` and
`nr2` (passed from `env->nr_cpus_avail`) to prevent out-of-bounds
reads from `cd_map1` and `cd_map2` when processing data from machines
with different CPU configurations.
5. Added NULL checks for `cd_info1` and `cd_info2` in `show_schedstat_data()`
to prevent crashes when a CPU has samples in the data file but no
corresponding domain info in the header (which leaves the map entry NULL).
6. Added NULL checks for `dinfo1` and `dinfo2` in `show_schedstat_data()`
to prevent crashes when a domain is present in the list but has no
corresponding info in the CPU domain map (which leaves the entry NULL).
7. Zero-initialized the `perf_data` array in `perf_sched__schedstat_diff()`
to prevent stack garbage from causing `perf_data_file__fd()` to attempt
to use a NULL `fptr` when `use_stdio` happened to be non-zero.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-sched.c | 85 +++++++++++++++++++++++++++++++-------
1 file changed, 69 insertions(+), 16 deletions(-)
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index d3fa9c70790f..f6c7d100729a 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -4212,12 +4212,20 @@ static int get_all_cpu_stats(struct list_head *head)
cnt++;
summarize_schedstat_cpu(summary_head, cptr, cnt, is_last);
- tdptr = list_first_entry(&summary_head->domain_head, struct schedstat_domain,
- domain_list);
+ if (!list_empty(&summary_head->domain_head))
+ tdptr = list_first_entry(&summary_head->domain_head, struct schedstat_domain,
+ domain_list);
+ else
+ tdptr = NULL;
list_for_each_entry(dptr, &cptr->domain_head, domain_list) {
- summarize_schedstat_domain(tdptr, dptr, cnt, is_last);
- tdptr = list_next_entry(tdptr, domain_list);
+ if (tdptr) {
+ summarize_schedstat_domain(tdptr, dptr, cnt, is_last);
+ if (list_is_last(&tdptr->domain_list, &summary_head->domain_head))
+ tdptr = NULL;
+ else
+ tdptr = list_next_entry(tdptr, domain_list);
+ }
}
}
@@ -4225,8 +4233,8 @@ static int get_all_cpu_stats(struct list_head *head)
return ret;
}
-static int show_schedstat_data(struct list_head *head1, struct cpu_domain_map **cd_map1,
- struct list_head *head2, struct cpu_domain_map **cd_map2,
+static int show_schedstat_data(struct list_head *head1, struct cpu_domain_map **cd_map1, int nr1,
+ struct list_head *head2, struct cpu_domain_map **cd_map2, int nr2,
bool summary_only)
{
struct schedstat_cpu *cptr1 = list_first_entry(head1, struct schedstat_cpu, cpu_list);
@@ -4238,6 +4246,15 @@ static int show_schedstat_data(struct list_head *head1, struct cpu_domain_map **
bool is_summary = true;
int ret = 0;
+ if (!cd_map1) {
+ pr_err("Error: CPU domain map 1 is missing.\n");
+ return -1;
+ }
+ if (head2 && !cd_map2) {
+ pr_err("Error: CPU domain map 2 is missing.\n");
+ return -1;
+ }
+
printf("Description\n");
print_separator2(SEP_LEN, "", 0);
printf("%-30s-> %s\n", "DESC", "Description of the field");
@@ -4269,12 +4286,31 @@ static int show_schedstat_data(struct list_head *head1, struct cpu_domain_map **
struct cpu_domain_map *cd_info1 = NULL, *cd_info2 = NULL;
cs1 = cptr1->cpu_data;
+ if (cs1->cpu >= (u32)nr1) {
+ pr_err("Error: CPU %d exceeds domain map size %d\n", cs1->cpu, nr1);
+ return -1;
+ }
cd_info1 = cd_map1[cs1->cpu];
+ if (!cd_info1) {
+ pr_err("Error: CPU %d domain info is missing in map 1.\n", cs1->cpu);
+ return -1;
+ }
if (cptr2) {
cs2 = cptr2->cpu_data;
+ if (cs2->cpu >= (u32)nr2) {
+ pr_err("Error: CPU %d exceeds domain map size %d\n", cs2->cpu, nr2);
+ return -1;
+ }
cd_info2 = cd_map2[cs2->cpu];
- dptr2 = list_first_entry(&cptr2->domain_head, struct schedstat_domain,
- domain_list);
+ if (!cd_info2) {
+ pr_err("Error: CPU %d domain info is missing in map 2.\n", cs2->cpu);
+ return -1;
+ }
+ if (!list_empty(&cptr2->domain_head))
+ dptr2 = list_first_entry(&cptr2->domain_head, struct schedstat_domain,
+ domain_list);
+ else
+ dptr2 = NULL;
}
if (cs2 && cs1->cpu != cs2->cpu) {
@@ -4303,9 +4339,17 @@ static int show_schedstat_data(struct list_head *head1, struct cpu_domain_map **
ds1 = dptr1->domain_data;
dinfo1 = cd_info1->domains[ds1->domain];
+ if (!dinfo1) {
+ pr_err("Error: Domain %d info is missing for CPU %d in map 1.\n", ds1->domain, cs1->cpu);
+ return -1;
+ }
if (dptr2) {
ds2 = dptr2->domain_data;
dinfo2 = cd_info2->domains[ds2->domain];
+ if (!dinfo2) {
+ pr_err("Error: Domain %d info is missing for CPU %d in map 2.\n", ds2->domain, cs2->cpu);
+ return -1;
+ }
}
if (dinfo2 && dinfo1->domain != dinfo2->domain) {
@@ -4334,14 +4378,22 @@ static int show_schedstat_data(struct list_head *head1, struct cpu_domain_map **
print_domain_stats(ds1, ds2, jiffies1, jiffies2);
print_separator2(SEP_LEN, "", 0);
- if (dptr2)
- dptr2 = list_next_entry(dptr2, domain_list);
+ if (dptr2) {
+ if (list_is_last(&dptr2->domain_list, &cptr2->domain_head))
+ dptr2 = NULL;
+ else
+ dptr2 = list_next_entry(dptr2, domain_list);
+ }
}
if (summary_only)
break;
- if (cptr2)
- cptr2 = list_next_entry(cptr2, cpu_list);
+ if (cptr2) {
+ if (list_is_last(&cptr2->cpu_list, head2))
+ cptr2 = NULL;
+ else
+ cptr2 = list_next_entry(cptr2, cpu_list);
+ }
is_summary = false;
}
@@ -4523,7 +4575,7 @@ static int perf_sched__schedstat_report(struct perf_sched *sched)
}
cd_map = session->header.env.cpu_domain;
- err = show_schedstat_data(&cpu_head, cd_map, NULL, NULL, false);
+ err = show_schedstat_data(&cpu_head, cd_map, session->header.env.nr_cpus_avail, NULL, NULL, 0, false);
}
out:
@@ -4538,7 +4590,7 @@ static int perf_sched__schedstat_diff(struct perf_sched *sched,
struct cpu_domain_map **cd_map0 = NULL, **cd_map1 = NULL;
struct list_head cpu_head_ses0, cpu_head_ses1;
struct perf_session *session[2];
- struct perf_data data[2];
+ struct perf_data data[2] = {0};
int ret = 0, err = 0;
static const char *defaults[] = {
"perf.data.old",
@@ -4610,7 +4662,8 @@ static int perf_sched__schedstat_diff(struct perf_sched *sched,
goto out_delete_ses0;
}
- show_schedstat_data(&cpu_head_ses0, cd_map0, &cpu_head_ses1, cd_map1, true);
+ show_schedstat_data(&cpu_head_ses0, cd_map0, session[0]->header.env.nr_cpus_avail,
+ &cpu_head_ses1, cd_map1, session[1]->header.env.nr_cpus_avail, true);
out_delete_ses1:
free_schedstat(&cpu_head_ses1);
@@ -4720,7 +4773,7 @@ static int perf_sched__schedstat_live(struct perf_sched *sched,
goto out;
}
- show_schedstat_data(&cpu_head, cd_map, NULL, NULL, false);
+ show_schedstat_data(&cpu_head, cd_map, nr, NULL, NULL, 0, false);
free_cpu_domain_info(cd_map, sv, nr);
out:
free_schedstat(&cpu_head);
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 50/59] perf rwtop: Port rwtop to use python module
From: Ian Rogers @ 2026-04-25 22:44 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
Port the legacy Perl script rwtop.pl to a python script using the perf
module in tools/perf/python.
The new script uses a class-based architecture and leverages the
perf.session API for event processing.
It periodically displays system-wide r/w call activity, broken down by
PID, refreshed every interval.
Complications:
- Implemented periodic display based on event timestamps
(sample.sample_time) instead of relying on SIGALRM, making it robust
for file-based processing.
- Used ANSI escape codes (\x1b[H\x1b[2J) to clear the terminal.
- Fixed unused imports and indentation issues identified by pylint.
- pylint warns about the module name not being snake_case, but it is
kept for consistency with the original script name.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2:
- Added Live Session Support: Updated main() to start a LiveSession
when the input file does not exist (or is the default "perf.data"
and doesn't exist). It traces read and write entry/exit
tracepoints.
- Fixed Live Mode Comm Resolution: Fixed a bug in process_event()
where it would attempt to use self.session to resolve the command
name when running in live mode (where self.session is None ). It
now falls back to f"PID({pid})" when in live mode or if resolution
fails.
- Fixed Substring Matching: Replaced loose substring checks like if
"sys_enter_read" in event_name: with exact matches against
"evsel(syscalls:sys_enter_read)" and
"evsel(raw_syscalls:sys_enter_read)" using str(sample.evsel) . This
prevents unrelated syscalls with similar names (like readv or
readahead ) from being incorrectly aggregated. Similar fixes were
applied for exit events and write events.
- Inlined Handlers and Tracked Errors: Inlined the _handle_sys_*
helper methods into process_event() . Now, if a sample lacks
expected fields, it is added to the self.unhandled tracker instead
of being silently ignored.
- Fixed Write Byte Counting: Updated the write exit handler to use
sample.ret to count actual bytes written on success, and tracked
requested bytes separately in the enter handler, matching the read
behavior.
- Added Error Tables to Output: Added tables to display failed reads
and writes by PID in print_totals() , which were previously tracked
but never displayed.
- Fixed Offline Output (Ghosting): Removed the hardcoded ANSI
clear-screen escape codes in print_totals() , as they corrupted
output when processing offline trace files at CPU speed or when
piping the output.
- Code Cleanup: Fixed a bug where fd was printed instead of pid in
the read counts table, and broke long lines to satisfy pylint.
---
tools/perf/python/rwtop.py | 219 +++++++++++++++++++++++++++++++++++++
1 file changed, 219 insertions(+)
create mode 100755 tools/perf/python/rwtop.py
diff --git a/tools/perf/python/rwtop.py b/tools/perf/python/rwtop.py
new file mode 100755
index 000000000000..895ebab9af10
--- /dev/null
+++ b/tools/perf/python/rwtop.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+"""Periodically displays system-wide r/w call activity, broken down by pid."""
+
+import argparse
+from collections import defaultdict
+import os
+import sys
+from typing import Optional, Dict, Any
+import perf
+from perf_live import LiveSession
+
+class RwTop:
+ """Periodically displays system-wide r/w call activity."""
+ def __init__(self, interval: int = 3, nlines: int = 20) -> None:
+ self.interval_ns = interval * 1000000000
+ self.nlines = nlines
+ self.reads: Dict[int, Dict[str, Any]] = defaultdict(
+ lambda: {
+ "bytes_requested": 0,
+ "bytes_read": 0,
+ "total_reads": 0,
+ "comm": "",
+ "errors": defaultdict(int),
+ }
+ )
+ self.writes: Dict[int, Dict[str, Any]] = defaultdict(
+ lambda: {
+ "bytes_requested": 0,
+ "bytes_written": 0,
+ "total_writes": 0,
+ "comm": "",
+ "errors": defaultdict(int),
+ }
+ )
+ self.unhandled: Dict[str, int] = defaultdict(int)
+ self.session: Optional[perf.session] = None
+ self.last_print_time: int = 0
+
+ def process_event(self, sample: perf.sample_event) -> None: # pylint: disable=too-many-branches
+ """Process events."""
+ event_name = str(sample.evsel)
+ pid = sample.sample_pid
+ sample_time = sample.sample_time
+
+ if self.last_print_time == 0:
+ self.last_print_time = sample_time
+
+ # Check if interval has passed
+ if sample_time - self.last_print_time >= self.interval_ns:
+ self.print_totals()
+ self.last_print_time = sample_time
+
+ try:
+ comm = f"PID({pid})" if not self.session else self.session.find_thread(pid).comm()
+ except Exception: # pylint: disable=broad-except
+ comm = f"PID({pid})"
+
+ if event_name in ("evsel(syscalls:sys_enter_read)", "evsel(raw_syscalls:sys_enter_read)"):
+ try:
+ count = sample.count
+ self.reads[pid]["bytes_requested"] += count
+ self.reads[pid]["total_reads"] += 1
+ self.reads[pid]["comm"] = comm
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ elif event_name in ("evsel(syscalls:sys_exit_read)", "evsel(raw_syscalls:sys_exit_read)"):
+ try:
+ ret = sample.ret
+ if ret > 0:
+ self.reads[pid]["bytes_read"] += ret
+ else:
+ self.reads[pid]["errors"][ret] += 1
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ elif event_name in ("evsel(syscalls:sys_enter_write)",
+ "evsel(raw_syscalls:sys_enter_write)"):
+ try:
+ count = sample.count
+ self.writes[pid]["bytes_requested"] += count
+ self.writes[pid]["total_writes"] += 1
+ self.writes[pid]["comm"] = comm
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ elif event_name in ("evsel(syscalls:sys_exit_write)", "evsel(raw_syscalls:sys_exit_write)"):
+ try:
+ ret = sample.ret
+ if ret > 0:
+ self.writes[pid]["bytes_written"] += ret
+ else:
+ self.writes[pid]["errors"][ret] += 1
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ else:
+ self.unhandled[event_name] += 1
+
+ def print_totals(self) -> None:
+ """Print summary tables."""
+ print("read counts by pid:\n")
+ print(
+ f"{'pid':>6s} {'comm':<20s} {'# reads':>10s} "
+ f"{'bytes_req':>10s} {'bytes_read':>10s}"
+ )
+ print(f"{'-'*6} {'-'*20} {'-'*10} {'-'*10} {'-'*10}")
+
+ count = 0
+ for pid, data in sorted(self.reads.items(),
+ key=lambda kv: kv[1]["bytes_read"], reverse=True):
+ print(
+ f"{pid:6d} {data['comm']:<20s} {data['total_reads']:10d} "
+ f"{data['bytes_requested']:10d} {data['bytes_read']:10d}"
+ )
+ count += 1
+ if count >= self.nlines:
+ break
+
+ print("\nfailed reads by pid:\n")
+ print(f"{'pid':>6s} {'comm':<20s} {'error #':>6s} {'# errors':>10s}")
+ print(f"{'-'*6} {'-'*20} {'-'*6} {'-'*10}")
+
+ errcounts = []
+ for pid, data in self.reads.items():
+ for error, cnt in data["errors"].items():
+ errcounts.append((pid, data["comm"], error, cnt))
+
+ sorted_errcounts = sorted(errcounts, key=lambda x: x[3], reverse=True)
+ for pid, comm, error, cnt in sorted_errcounts[:self.nlines]:
+ print(f"{pid:6d} {comm:<20s} {error:6d} {cnt:10d}")
+
+ print("\nwrite counts by pid:\n")
+ print(
+ f"{'pid':>6s} {'comm':<20s} {'# writes':>10s} "
+ f"{'bytes_req':>10s} {'bytes_written':>13s}"
+ )
+ print(f"{'-'*6} {'-'*20} {'-'*10} {'-'*10} {'-'*13}")
+
+ count = 0
+ for pid, data in sorted(self.writes.items(),
+ key=lambda kv: kv[1]["bytes_written"], reverse=True):
+ print(
+ f"{pid:6d} {data['comm']:<20s} {data['total_writes']:10d} "
+ f"{data['bytes_requested']:10d} {data['bytes_written']:13d}"
+ )
+ count += 1
+ if count >= self.nlines:
+ break
+
+ print("\nfailed writes by pid:\n")
+ print(f"{'pid':>6s} {'comm':<20s} {'error #':>6s} {'# errors':>10s}")
+ print(f"{'-'*6} {'-'*20} {'-'*6} {'-'*10}")
+
+ errcounts = []
+ for pid, data in self.writes.items():
+ for error, cnt in data["errors"].items():
+ errcounts.append((pid, data["comm"], error, cnt))
+
+ sorted_errcounts = sorted(errcounts, key=lambda x: x[3], reverse=True)
+ for pid, comm, error, cnt in sorted_errcounts[:self.nlines]:
+ print(f"{pid:6d} {comm:<20s} {error:6d} {cnt:10d}")
+
+ # Reset counts
+ self.reads.clear()
+ self.writes.clear()
+
+ def run(self, input_file: str) -> None:
+ """Run the session."""
+ self.session = perf.session(perf.data(input_file), sample=self.process_event)
+ self.session.process_events()
+
+ # Print final totals if there are any left
+ if self.reads or self.writes:
+ self.print_totals()
+
+ if self.unhandled:
+ print("\nunhandled events:\n")
+ print(f"{'event':<40s} {'count':>10s}")
+ print(f"{'-'*40} {'-'*10}")
+ for event_name, count in self.unhandled.items():
+ print(f"{event_name:<40s} {count:10d}")
+
+def main() -> None:
+ """Main function."""
+ parser = argparse.ArgumentParser(description="Trace r/w activity by PID")
+ parser.add_argument(
+ "interval", type=int, nargs="?", default=3, help="Refresh interval in seconds"
+ )
+ parser.add_argument("-i", "--input", default="perf.data", help="Input file")
+ args = parser.parse_args()
+
+ analyzer = RwTop(args.interval)
+ try:
+ if not os.path.exists(args.input) and args.input == "perf.data":
+ # Live mode
+ events = (
+ "syscalls:sys_enter_read,syscalls:sys_exit_read,"
+ "syscalls:sys_enter_write,syscalls:sys_exit_write"
+ )
+ try:
+ live_session = LiveSession(events, sample_callback=analyzer.process_event)
+ except OSError:
+ events = (
+ "raw_syscalls:sys_enter_read,raw_syscalls:sys_exit_read,"
+ "raw_syscalls:sys_enter_write,raw_syscalls:sys_exit_write"
+ )
+ live_session = LiveSession(events, sample_callback=analyzer.process_event)
+ print("Live mode started. Press Ctrl+C to stop.", file=sys.stderr)
+ live_session.run()
+ else:
+ analyzer.run(args.input)
+ except IOError as e:
+ print(e, file=sys.stderr)
+ sys.exit(1)
+ except KeyboardInterrupt:
+ print("\nStopping live mode...", file=sys.stderr)
+ if analyzer.reads or analyzer.writes:
+ analyzer.print_totals()
+
+if __name__ == "__main__":
+ main()
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 55/59] perf Makefile: Update Python script installation path
From: Ian Rogers @ 2026-04-25 22:44 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
Remove libpython feature test that is now a python-module feature
test. Update references from libpython to python-module accordingly.
Remove references to legacy 'scripts/python' directory and install
scripts directly to 'python' directory under libexec. This aligns with
the removal of embedded interpreter and move to standalone
scripts.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/build/Makefile.feature | 4 ++--
tools/build/feature/Makefile | 4 ++--
tools/build/feature/test-all.c | 6 +++---
tools/build/feature/test-libpython.c | 10 ----------
tools/build/feature/test-python-module.c | 12 ++++++++++++
tools/perf/Makefile.config | 13 ++++++-------
tools/perf/Makefile.perf | 10 ++++------
tools/perf/tests/make | 5 +----
8 files changed, 30 insertions(+), 34 deletions(-)
delete mode 100644 tools/build/feature/test-libpython.c
create mode 100644 tools/build/feature/test-python-module.c
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 96d4382144c4..cbe41ba7bae5 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -79,7 +79,7 @@ FEATURE_TESTS_BASIC := \
libelf-zstd \
libnuma \
numa_num_possible_cpus \
- libpython \
+ python-module \
libslang \
libtraceevent \
libcpupower \
@@ -140,7 +140,7 @@ FEATURE_DISPLAY ?= \
libelf \
libnuma \
numa_num_possible_cpus \
- libpython \
+ python-module \
libcapstone \
llvm-perf \
zlib \
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index 60e3df8142a5..5530f9e03fcf 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -30,7 +30,7 @@ FILES= \
test-libdebuginfod.bin \
test-libnuma.bin \
test-numa_num_possible_cpus.bin \
- test-libpython.bin \
+ test-python-module.bin \
test-libslang.bin \
test-libtraceevent.bin \
test-libcpupower.bin \
@@ -252,7 +252,7 @@ $(OUTPUT)test-gtk2-infobar.bin:
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
-$(OUTPUT)test-libpython.bin:
+$(OUTPUT)test-python-module.bin:
$(BUILD) $(FLAGS_PYTHON_EMBED)
$(OUTPUT)test-libbfd.bin:
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 1488bf6e6078..4400e3d24f81 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -10,8 +10,8 @@
* Quirk: Python headers cannot be in arbitrary places, so keep this testcase at
* the top:
*/
-#define main main_test_libpython
-# include "test-libpython.c"
+#define main main_test_python_module
+# include "test-python-module.c"
#undef main
#define main main_test_hello
@@ -148,7 +148,7 @@
int main(int argc, char *argv[])
{
- main_test_libpython();
+ main_test_python_module();
main_test_hello();
main_test_libelf();
main_test_gettid();
diff --git a/tools/build/feature/test-libpython.c b/tools/build/feature/test-libpython.c
deleted file mode 100644
index 371c9113e49d..000000000000
--- a/tools/build/feature/test-libpython.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <Python.h>
-
-int main(void)
-{
- Py_Initialize();
-
- return 0;
-}
-#undef _GNU_SOURCE
diff --git a/tools/build/feature/test-python-module.c b/tools/build/feature/test-python-module.c
new file mode 100644
index 000000000000..d670dba014b0
--- /dev/null
+++ b/tools/build/feature/test-python-module.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <Python.h>
+
+int main(void)
+{
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ };
+ PyObject *module = PyModule_Create(&moduledef);
+
+ return module ? 0 : -1;
+}
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index ecddd91229c8..e2cef452964f 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -317,7 +317,7 @@ PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
# Python 3.8 changed the output of `python-config --ldflags` to not include the
# '-lpythonX.Y' flag unless '--embed' is also passed. The feature check for
-# libpython fails if that flag is not included in LDFLAGS
+# python-module fails if that flag is not included in LDFLAGS
ifeq ($(shell $(PYTHON_CONFIG_SQ) --ldflags --embed 2>&1 1>/dev/null; echo $$?), 0)
PYTHON_CONFIG_LDFLAGS := --ldflags --embed
else
@@ -340,8 +340,8 @@ ifdef PYTHON_CONFIG
endif
endif
-FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
-FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
+FEATURE_CHECK_CFLAGS-python-module := $(PYTHON_EMBED_CCOPTS)
+FEATURE_CHECK_LDFLAGS-python-module := $(PYTHON_EMBED_LDOPTS)
FEATURE_CHECK_LDFLAGS-libaio = -lrt
@@ -830,13 +830,12 @@ endif
disable-python = $(eval $(disable-python_code))
define disable-python_code
- CFLAGS += -DNO_LIBPYTHON
$(warning $1)
- NO_LIBPYTHON := 1
+ NO_PYTHON_MODULE := 1
endef
PYTHON_EXTENSION_SUFFIX := '.so'
-ifdef NO_LIBPYTHON
+ifdef NO_PYTHON_MODULE
$(call disable-python,Python support disabled by user)
else
@@ -849,7 +848,7 @@ else
$(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev)
else
- ifneq ($(feature-libpython), 1)
+ ifneq ($(feature-python-module), 1)
$(call disable-python,No 'Python.h' was found: disables Python support - please install python-devel/python-dev)
else
PYTHON_SETUPTOOLS_INSTALLED := $(shell $(PYTHON) -c 'import setuptools;' 2> /dev/null && echo "yes" || echo "no")
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 2020532bab9c..e50b1e8cf85d 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -17,9 +17,7 @@ include ../scripts/utilities.mak
#
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
#
-
-#
-# Define NO_LIBPYTHON to disable python script extension.
+# Define NO_PYTHON_MODULE to disable python script extension.
#
# Define PYTHON to point to the python binary if the default
# `python' is not correct; for example: PYTHON=python2
@@ -1099,10 +1097,10 @@ endif
$(call QUIET_INSTALL, perf-iostat) \
$(INSTALL) $(OUTPUT)perf-iostat -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
-ifndef NO_LIBPYTHON
+ifndef NO_PYTHON_MODULE
$(call QUIET_INSTALL, python-scripts) \
- $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
- $(INSTALL) python/*.py -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python'; \
+ $(INSTALL) python/*.py -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python'
endif
$(call QUIET_INSTALL, dlfilters) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/dlfilters'; \
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 31b064928cfc..f2c5f1c254a7 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -75,8 +75,6 @@ make_jevents_all := JEVENTS_ARCH=all
make_no_bpf_skel := BUILD_BPF_SKEL=0
make_gen_vmlinux_h := GEN_VMLINUX_H=1
-make_no_libpython := NO_LIBPYTHON=1
-make_no_scripts := NO_LIBPYTHON=1
make_no_slang := NO_SLANG=1
make_no_gtk2 := NO_GTK2=1
make_no_ui := NO_SLANG=1 NO_GTK2=1
@@ -118,7 +116,7 @@ make_install_prefix_slash := install prefix=/tmp/krava/
make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 NO_LIBELF=1
# all the NO_* variable combined
-make_minimal := NO_LIBPYTHON=1 NO_GTK2=1
+make_minimal := NO_GTK2=1
make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_BACKTRACE=1
make_minimal += NO_LIBNUMA=1 NO_LIBBIONIC=1 NO_LIBDW=1
make_minimal += NO_LIBBPF=1
@@ -150,7 +148,6 @@ run += make_jevents_all
run += make_no_bpf_skel
run += make_gen_vmlinux_h
-run += make_no_libpython
run += make_no_scripts
run += make_no_slang
run += make_no_gtk2
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 58/59] perf python: Improve perf script -l descriptions
From: Ian Rogers @ 2026-04-25 22:45 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
Improve the description when running "perf script -l":
```
$ perf script -l
List of available scripts:
...
counting Example for counting perf events.
...
exported-sql-viewer exported-sql-viewer.py: view data from sql database.
...
tracepoint Example showing how to enable a tracepoint and access its fields.
twatch Example to show how to enable a tracepoint and access its fields.
...
```
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/python/counting.py | 1 +
tools/perf/python/exported-sql-viewer.py | 2 +-
tools/perf/python/tracepoint.py | 1 +
tools/perf/python/twatch.py | 1 +
4 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/perf/python/counting.py b/tools/perf/python/counting.py
index 02121d2bb11d..9adbbeccdacd 100755
--- a/tools/perf/python/counting.py
+++ b/tools/perf/python/counting.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
+"""Example for counting perf events."""
# -*- python -*-
# -*- coding: utf-8 -*-
diff --git a/tools/perf/python/exported-sql-viewer.py b/tools/perf/python/exported-sql-viewer.py
index f3ac96ada1f5..6d526a2502ca 100755
--- a/tools/perf/python/exported-sql-viewer.py
+++ b/tools/perf/python/exported-sql-viewer.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# SPDX-License-Identifier: GPL-2.0
-# exported-sql-viewer.py: view data from sql database
+"""exported-sql-viewer.py: view data from sql database."""
# Copyright (c) 2014-2018, Intel Corporation.
# To use this script you will need to have exported data using either the
diff --git a/tools/perf/python/tracepoint.py b/tools/perf/python/tracepoint.py
index 15b0c8268996..d3bc22628ef7 100755
--- a/tools/perf/python/tracepoint.py
+++ b/tools/perf/python/tracepoint.py
@@ -1,5 +1,6 @@
#! /usr/bin/env python
# SPDX-License-Identifier: GPL-2.0
+"""Example showing how to enable a tracepoint and access its fields."""
# -*- python -*-
# -*- coding: utf-8 -*-
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index 04f3db29b9bc..e50cc2feb58a 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -1,5 +1,6 @@
#! /usr/bin/env python
# SPDX-License-Identifier: GPL-2.0-only
+"""Example to show how to enable a tracepoint and access its fields."""
# -*- python -*-
# -*- coding: utf-8 -*-
# twatch - Experimental use of the perf python interface
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 52/59] perf test: Migrate Intel PT virtual LBR test to use Python API
From: Ian Rogers @ 2026-04-25 22:44 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
The Intel PT virtual LBR test used an ad-hoc Python script written on
the fly to parse branch stacks. This change migrates it to use the
newly added `brstack` iterator API in the `perf` Python module.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v7:
- Fixed permanent iterator exhaustion on brstack by converting it
to a list.
---
.../perf/tests/shell/lib/perf_brstack_max.py | 43 +++++++++++++++++++
tools/perf/tests/shell/test_intel_pt.sh | 35 +++++----------
2 files changed, 53 insertions(+), 25 deletions(-)
create mode 100644 tools/perf/tests/shell/lib/perf_brstack_max.py
diff --git a/tools/perf/tests/shell/lib/perf_brstack_max.py b/tools/perf/tests/shell/lib/perf_brstack_max.py
new file mode 100644
index 000000000000..bd1cdb463f28
--- /dev/null
+++ b/tools/perf/tests/shell/lib/perf_brstack_max.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0
+# Determine the maximum size of branch stacks in a perf.data file.
+
+import argparse
+import sys
+
+import os
+
+script_dir = os.path.dirname(os.path.abspath(__file__))
+python_dir = os.path.abspath(os.path.join(script_dir, "../../../python"))
+sys.path.insert(0, python_dir)
+
+import perf
+
+def main():
+ ap = argparse.ArgumentParser()
+ ap.add_argument("-i", "--input", default="perf.data", help="Input file name")
+ args = ap.parse_args()
+
+ bmax = 0
+
+ def process_event(sample):
+ nonlocal bmax
+ try:
+ brstack = sample.brstack
+ if brstack:
+ n = len(list(brstack))
+ if n > bmax:
+ bmax = n
+ except AttributeError:
+ pass
+
+ try:
+ session = perf.session(perf.data(args.input), sample=process_event)
+ session.process_events()
+ print("max brstack", bmax)
+ except Exception as e:
+ print(f"Error processing events: {e}", file=sys.stderr)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
index 8ee761f03c38..d711ecdf5be0 100755
--- a/tools/perf/tests/shell/test_intel_pt.sh
+++ b/tools/perf/tests/shell/test_intel_pt.sh
@@ -24,7 +24,6 @@ errfile="${temp_dir}/test-err.txt"
workload="${temp_dir}/workload"
awkscript="${temp_dir}/awkscript"
jitdump_workload="${temp_dir}/jitdump_workload"
-maxbrstack="${temp_dir}/maxbrstack.py"
cleanup()
{
@@ -539,34 +538,20 @@ test_kernel_trace()
test_virtual_lbr()
{
echo "--- Test virtual LBR ---"
- # Check if python script is supported
- libpython=$(perf version --build-options | grep python | grep -cv OFF)
- if [ "${libpython}" != "1" ] ; then
- echo "SKIP: python scripting is not supported"
+ # shellcheck source=lib/setup_python.sh
+ . "$(dirname "$0")"/lib/setup_python.sh
+
+ if [ -z "$PYTHON" ] ; then
+ echo "SKIP: Python not found"
return 2
fi
- # Python script to determine the maximum size of branch stacks
- cat << "_end_of_file_" > "${maxbrstack}"
-from __future__ import print_function
-
-bmax = 0
-
-def process_event(param_dict):
- if "brstack" in param_dict:
- brstack = param_dict["brstack"]
- n = len(brstack)
- global bmax
- if n > bmax:
- bmax = n
-
-def trace_end():
- print("max brstack", bmax)
-_end_of_file_
-
# Check if virtual lbr is working
- perf_record_no_bpf -o "${perfdatafile}" --aux-sample -e '{intel_pt//,cycles}:u' uname
- times_val=$(perf script -i "${perfdatafile}" --itrace=L -s "${maxbrstack}" 2>/dev/null | grep "max brstack " | cut -d " " -f 3)
+ perf_record_no_bpf -o "${tmpfile}" --aux-sample -e '{intel_pt//,cycles}:u' perf test -w brstack
+ perf inject --itrace=L -i "${tmpfile}" -o "${perfdatafile}"
+ output=$($PYTHON "$(dirname "$0")"/lib/perf_brstack_max.py -i "${perfdatafile}")
+ echo "Debug: perf_brstack_max.py output: $output"
+ times_val=$(echo "$output" | grep "max brstack " | cut -d " " -f 3)
case "${times_val}" in
[0-9]*) ;;
*) times_val=0;;
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 51/59] perf wakeup-latency: Port wakeup-latency to use python module
From: Ian Rogers @ 2026-04-25 22:44 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
Port the legacy Perl script wakeup-latency.pl to a python script using
the perf module in tools/perf/python.
The new script uses a class-based architecture and leverages the
perf.session API for event processing.
It measures wakeup latency by tracking timestamps of
sched:sched_wakeup and sched:sched_switch events.
Complications:
- Used min() and max() built-in functions instead of if blocks to
satisfy pylint recommendations.
- pylint warns about the module name not being snake_case, but it is
kept for consistency with the original script name.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2:
- Fixed Wakeup Latency Logic: Modified the script to track wakeup
timestamps per task (using sample.pid as the key) instead of per
CPU. This ensures that context switches are correctly paired with
the specific task that was woken up, even if multiple tasks are
woken up on the same CPU or if a task is migrated to a different
CPU before running.
- Prevented Memory Growth: Added del self.last_wakeup[next_pid] after
successful latency calculation to prevent the dictionary from
growing unbounded over time.
- Added Error Tracking: Added try-except blocks around tracepoint
field access in process_event() and tracked missing fields in self.
unhandled instead of ignoring them.
---
tools/perf/python/wakeup-latency.py | 88 +++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
create mode 100755 tools/perf/python/wakeup-latency.py
diff --git a/tools/perf/python/wakeup-latency.py b/tools/perf/python/wakeup-latency.py
new file mode 100755
index 000000000000..1b0db115abcf
--- /dev/null
+++ b/tools/perf/python/wakeup-latency.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+"""Display avg/min/max wakeup latency."""
+
+import argparse
+from collections import defaultdict
+import sys
+from typing import Optional, Dict
+import perf
+
+class WakeupLatency:
+ """Tracks and displays wakeup latency statistics."""
+ def __init__(self) -> None:
+ self.last_wakeup: Dict[int, int] = defaultdict(int)
+ self.max_wakeup_latency = 0
+ self.min_wakeup_latency = 1000000000
+ self.total_wakeup_latency = 0
+ self.total_wakeups = 0
+ self.unhandled: Dict[str, int] = defaultdict(int)
+ self.session: Optional[perf.session] = None
+
+ def process_event(self, sample: perf.sample_event) -> None:
+ """Process events."""
+ event_name = str(sample.evsel)
+ sample_time = sample.sample_time
+
+ if "sched:sched_wakeup" in event_name:
+ try:
+ pid = sample.pid
+ self.last_wakeup[pid] = sample_time
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ elif "sched:sched_switch" in event_name:
+ try:
+ next_pid = sample.next_pid
+ wakeup_ts = self.last_wakeup.get(next_pid, 0)
+ if wakeup_ts:
+ latency = sample_time - wakeup_ts
+ self.max_wakeup_latency = max(self.max_wakeup_latency, latency)
+ self.min_wakeup_latency = min(self.min_wakeup_latency, latency)
+ self.total_wakeup_latency += latency
+ self.total_wakeups += 1
+ del self.last_wakeup[next_pid]
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ else:
+ self.unhandled[event_name] += 1
+
+ def print_totals(self) -> None:
+ """Print summary statistics."""
+ print("wakeup_latency stats:\n")
+ print(f"total_wakeups: {self.total_wakeups}")
+ if self.total_wakeups:
+ avg = self.total_wakeup_latency // self.total_wakeups
+ print(f"avg_wakeup_latency (ns): {avg}")
+ else:
+ print("avg_wakeup_latency (ns): N/A")
+ print(f"min_wakeup_latency (ns): {self.min_wakeup_latency}")
+ print(f"max_wakeup_latency (ns): {self.max_wakeup_latency}")
+
+ if self.unhandled:
+ print("\nunhandled events:\n")
+ print(f"{'event':<40s} {'count':>10s}")
+ print(f"{'-'*40} {'-'*10}")
+ for event_name, count in self.unhandled.items():
+ print(f"{event_name:<40s} {count:10d}")
+
+ def run(self, input_file: str) -> None:
+ """Run the session."""
+ self.session = perf.session(perf.data(input_file), sample=self.process_event)
+ self.session.process_events()
+ self.print_totals()
+
+def main() -> None:
+ """Main function."""
+ parser = argparse.ArgumentParser(description="Trace wakeup latency")
+ parser.add_argument("-i", "--input", default="perf.data", help="Input file")
+ args = parser.parse_args()
+
+ analyzer = WakeupLatency()
+ try:
+ analyzer.run(args.input)
+ except IOError as e:
+ print(e, file=sys.stderr)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH v7 49/59] perf rw-by-pid: Port rw-by-pid to use python module
From: Ian Rogers @ 2026-04-25 22:44 UTC (permalink / raw)
To: acme, adrian.hunter, james.clark, leo.yan, namhyung, tmricht
Cc: alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz, Ian Rogers
In-Reply-To: <20260425224503.170337-1-irogers@google.com>
Port the legacy Perl script rw-by-pid.pl to a python script using the
perf module in tools/perf/python.
The new script uses a class-based architecture and leverages the
perf.session API for event processing.
It tracks read and write activity by PID for all processes,
aggregating bytes requested, bytes read, total reads, and errors.
Complications:
- Refactored process_event to extract helper methods
(_handle_sys_enter_read, etc.) to reduce the number of branches and
satisfy pylint.
- Split long lines to comply with line length limits.
- pylint warns about the module name not being snake_case, but it is
kept for consistency with the original script name.
Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2:
- Fixed Substring Matching: Replaced loose substring checks like if
"sys_enter_read" in event_name: with exact matches against
syscalls:sys_enter_read and raw_syscalls:sys_enter_read using
sample.evsel.name . This prevents unrelated syscalls with similar
names (like readahead ) from being incorrectly aggregated. Similar
fixes were applied for exit events and write events.
- Inlined Handlers and Tracked Errors: Inlined the _handle_sys_*
helper methods into process_event() to make error handling
easier. Now, if a sample lacks expected fields (raising
AttributeError ), it is added to the self.unhandled tracker instead
of being silently dropped, providing better visibility to the user.
- Code Cleanup: Fixed trailing whitespace and added a pylint disable
comment for too-many-branches caused by the inlining.
v6:
- Fixed `AttributeError` by using `str(sample.evsel)` to get event name.
---
tools/perf/python/rw-by-pid.py | 158 +++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
create mode 100755 tools/perf/python/rw-by-pid.py
diff --git a/tools/perf/python/rw-by-pid.py b/tools/perf/python/rw-by-pid.py
new file mode 100755
index 000000000000..b206d2a575cd
--- /dev/null
+++ b/tools/perf/python/rw-by-pid.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+"""Display r/w activity for all processes."""
+
+import argparse
+from collections import defaultdict
+import sys
+from typing import Optional, Dict, List, Tuple, Any
+import perf
+
+class RwByPid:
+ """Tracks and displays read/write activity by PID."""
+ def __init__(self) -> None:
+ self.reads: Dict[int, Dict[str, Any]] = defaultdict(
+ lambda: {
+ "bytes_requested": 0,
+ "bytes_read": 0,
+ "total_reads": 0,
+ "comm": "",
+ "errors": defaultdict(int),
+ }
+ )
+ self.writes: Dict[int, Dict[str, Any]] = defaultdict(
+ lambda: {
+ "bytes_written": 0,
+ "total_writes": 0,
+ "comm": "",
+ "errors": defaultdict(int),
+ }
+ )
+ self.unhandled: Dict[str, int] = defaultdict(int)
+ self.session: Optional[perf.session] = None
+
+ def process_event(self, sample: perf.sample_event) -> None: # pylint: disable=too-many-branches
+ """Process events."""
+ event_name = str(sample.evsel)[6:-1]
+ pid = sample.sample_pid
+
+ assert self.session is not None
+ try:
+ comm = self.session.find_thread(pid).comm()
+ except Exception: # pylint: disable=broad-except
+ comm = "unknown"
+
+ if event_name in ("syscalls:sys_enter_read", "raw_syscalls:sys_enter_read"):
+ try:
+ count = sample.count
+ self.reads[pid]["bytes_requested"] += count
+ self.reads[pid]["total_reads"] += 1
+ self.reads[pid]["comm"] = comm
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ elif event_name in ("syscalls:sys_exit_read", "raw_syscalls:sys_exit_read"):
+ try:
+ ret = sample.ret
+ if ret > 0:
+ self.reads[pid]["bytes_read"] += ret
+ else:
+ self.reads[pid]["errors"][ret] += 1
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ elif event_name in ("syscalls:sys_enter_write", "raw_syscalls:sys_enter_write"):
+ try:
+ count = sample.count
+ self.writes[pid]["bytes_written"] += count
+ self.writes[pid]["total_writes"] += 1
+ self.writes[pid]["comm"] = comm
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ elif event_name in ("syscalls:sys_exit_write", "raw_syscalls:sys_exit_write"):
+ try:
+ ret = sample.ret
+ if ret <= 0:
+ self.writes[pid]["errors"][ret] += 1
+ except AttributeError:
+ self.unhandled[event_name] += 1
+ else:
+ self.unhandled[event_name] += 1
+
+ def print_totals(self) -> None:
+ """Print summary tables."""
+ print("read counts by pid:\n")
+ print(
+ f"{'pid':>6s} {'comm':<20s} {'# reads':>10s} "
+ f"{'bytes_requested':>15s} {'bytes_read':>10s}"
+ )
+ print(f"{'-'*6} {'-'*20} {'-'*10} {'-'*15} {'-'*10}")
+
+ for pid, data in sorted(self.reads.items(),
+ key=lambda kv: kv[1]["bytes_read"], reverse=True):
+ print(
+ f"{pid:6d} {data['comm']:<20s} {data['total_reads']:10d} "
+ f"{data['bytes_requested']:15d} {data['bytes_read']:10d}"
+ )
+
+ print("\nfailed reads by pid:\n")
+ print(f"{'pid':>6s} {'comm':<20s} {'error #':>6s} {'# errors':>10s}")
+ print(f"{'-'*6} {'-'*20} {'-'*6} {'-'*10}")
+
+ errcounts: List[Tuple[int, str, int, int]] = []
+ for pid, data in self.reads.items():
+ for error, count in data["errors"].items():
+ errcounts.append((pid, data["comm"], error, count))
+
+ for pid, comm, error, count in sorted(errcounts, key=lambda x: x[3], reverse=True):
+ print(f"{pid:6d} {comm:<20s} {error:6d} {count:10d}")
+
+ print("\nwrite counts by pid:\n")
+ print(f"{'pid':>6s} {'comm':<20s} {'# writes':>10s} {'bytes_written':>15s}")
+ print(f"{'-'*6} {'-'*20} {'-'*10} {'-'*15}")
+
+ for pid, data in sorted(self.writes.items(),
+ key=lambda kv: kv[1]["bytes_written"], reverse=True):
+ print(
+ f"{pid:6d} {data['comm']:<20s} "
+ f"{data['total_writes']:10d} {data['bytes_written']:15d}"
+ )
+
+ print("\nfailed writes by pid:\n")
+ print(f"{'pid':>6s} {'comm':<20s} {'error #':>6s} {'# errors':>10s}")
+ print(f"{'-'*6} {'-'*20} {'-'*6} {'-'*10}")
+
+ errcounts = []
+ for pid, data in self.writes.items():
+ for error, count in data["errors"].items():
+ errcounts.append((pid, data["comm"], error, count))
+
+ for pid, comm, error, count in sorted(errcounts, key=lambda x: x[3], reverse=True):
+ print(f"{pid:6d} {comm:<20s} {error:6d} {count:10d}")
+
+ if self.unhandled:
+ print("\nunhandled events:\n")
+ print(f"{'event':<40s} {'count':>10s}")
+ print(f"{'-'*40} {'-'*10}")
+ for event_name, count in self.unhandled.items():
+ print(f"{event_name:<40s} {count:10d}")
+
+ def run(self, input_file: str) -> None:
+ """Run the session."""
+ self.session = perf.session(perf.data(input_file), sample=self.process_event)
+ self.session.process_events()
+ self.print_totals()
+
+def main() -> None:
+ """Main function."""
+ parser = argparse.ArgumentParser(description="Trace r/w activity by PID")
+ parser.add_argument("-i", "--input", default="perf.data", help="Input file")
+ args = parser.parse_args()
+
+ analyzer = RwByPid()
+ try:
+ analyzer.run(args.input)
+ except IOError as e:
+ print(e, file=sys.stderr)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).