summaryrefslogtreecommitdiff
path: root/tools/perf/util/python.c
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2025-07-10 16:51:24 -0700
committerNamhyung Kim <namhyung@kernel.org>2025-07-11 12:36:40 -0700
commit6183afcba9c1c810656ddb36170106aaf3cf778c (patch)
tree46956e7999b29cd82c16edc9acf7b3f8d3b40076 /tools/perf/util/python.c
parent64ec9b997f3a9462901a404ad60f452f76dd2d6e (diff)
perf python: Correct pyrf_evsel__read for tool PMUs
Tool PMUs assume that stat's process_counter_values is being used to read the counters. Specifically they hold onto old values in evsel->prev_raw_counts and give the cumulative count based off of this value. Update pyrf_evsel__read to allocate counts and prev_raw_counts, use evsel__read_counter rather than perf_evsel__read so tool PMUs are read from not just perf_event_open events, make the returned pyrf_counts_values contain the delta value rather than the cumulative value. Fixes: 739621f65702 ("perf python: Add evsel read method") Signed-off-by: Ian Rogers <irogers@google.com> Link: https://lore.kernel.org/r/20250710235126.1086011-12-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'tools/perf/util/python.c')
-rw-r--r--tools/perf/util/python.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 4a3c2b4dd79f..f689560192f4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -10,6 +10,7 @@
#endif
#include <perf/mmap.h>
#include "callchain.h"
+#include "counts.h"
#include "evlist.h"
#include "evsel.h"
#include "event.h"
@@ -889,12 +890,38 @@ static PyObject *pyrf_evsel__threads(struct pyrf_evsel *pevsel)
return (PyObject *)pthread_map;
}
+/*
+ * Ensure evsel's counts and prev_raw_counts are allocated, the latter
+ * used by tool PMUs to compute the cumulative count as expected by
+ * stat's process_counter_values.
+ */
+static int evsel__ensure_counts(struct evsel *evsel)
+{
+ int nthreads, ncpus;
+
+ if (evsel->counts != NULL)
+ return 0;
+
+ nthreads = perf_thread_map__nr(evsel->core.threads);
+ ncpus = perf_cpu_map__nr(evsel->core.cpus);
+
+ evsel->counts = perf_counts__new(ncpus, nthreads);
+ if (evsel->counts == NULL)
+ return -ENOMEM;
+
+ evsel->prev_raw_counts = perf_counts__new(ncpus, nthreads);
+ if (evsel->prev_raw_counts == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
PyObject *args, PyObject *kwargs)
{
struct evsel *evsel = &pevsel->evsel;
int cpu = 0, cpu_idx, thread = 0, thread_idx;
- struct perf_counts_values counts;
+ struct perf_counts_values *old_count, *new_count;
struct pyrf_counts_values *count_values = PyObject_New(struct pyrf_counts_values,
&pyrf_counts_values__type);
@@ -915,8 +942,22 @@ static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
thread);
return NULL;
}
- perf_evsel__read(&(evsel->core), cpu_idx, thread_idx, &counts);
- count_values->values = counts;
+
+ if (evsel__ensure_counts(evsel))
+ return PyErr_NoMemory();
+
+ /* Set up pointers to the old and newly read counter values. */
+ old_count = perf_counts(evsel->prev_raw_counts, cpu_idx, thread_idx);
+ new_count = perf_counts(evsel->counts, cpu_idx, thread_idx);
+ /* Update the value in evsel->counts. */
+ evsel__read_counter(evsel, cpu_idx, thread_idx);
+ /* Copy the value and turn it into the delta from old_count. */
+ count_values->values = *new_count;
+ count_values->values.val -= old_count->val;
+ count_values->values.ena -= old_count->ena;
+ count_values->values.run -= old_count->run;
+ /* Save the new count over the old_count for the next read. */
+ *old_count = *new_count;
return (PyObject *)count_values;
}