Skip to content

Commit 6183afc

Browse files
captain5050namhyung
authored andcommitted
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: 739621f ("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>
1 parent 64ec9b9 commit 6183afc

File tree

1 file changed

+44
-3
lines changed

1 file changed

+44
-3
lines changed

tools/perf/util/python.c

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#endif
1111
#include <perf/mmap.h>
1212
#include "callchain.h"
13+
#include "counts.h"
1314
#include "evlist.h"
1415
#include "evsel.h"
1516
#include "event.h"
@@ -889,12 +890,38 @@ static PyObject *pyrf_evsel__threads(struct pyrf_evsel *pevsel)
889890
return (PyObject *)pthread_map;
890891
}
891892

893+
/*
894+
* Ensure evsel's counts and prev_raw_counts are allocated, the latter
895+
* used by tool PMUs to compute the cumulative count as expected by
896+
* stat's process_counter_values.
897+
*/
898+
static int evsel__ensure_counts(struct evsel *evsel)
899+
{
900+
int nthreads, ncpus;
901+
902+
if (evsel->counts != NULL)
903+
return 0;
904+
905+
nthreads = perf_thread_map__nr(evsel->core.threads);
906+
ncpus = perf_cpu_map__nr(evsel->core.cpus);
907+
908+
evsel->counts = perf_counts__new(ncpus, nthreads);
909+
if (evsel->counts == NULL)
910+
return -ENOMEM;
911+
912+
evsel->prev_raw_counts = perf_counts__new(ncpus, nthreads);
913+
if (evsel->prev_raw_counts == NULL)
914+
return -ENOMEM;
915+
916+
return 0;
917+
}
918+
892919
static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
893920
PyObject *args, PyObject *kwargs)
894921
{
895922
struct evsel *evsel = &pevsel->evsel;
896923
int cpu = 0, cpu_idx, thread = 0, thread_idx;
897-
struct perf_counts_values counts;
924+
struct perf_counts_values *old_count, *new_count;
898925
struct pyrf_counts_values *count_values = PyObject_New(struct pyrf_counts_values,
899926
&pyrf_counts_values__type);
900927

@@ -915,8 +942,22 @@ static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
915942
thread);
916943
return NULL;
917944
}
918-
perf_evsel__read(&(evsel->core), cpu_idx, thread_idx, &counts);
919-
count_values->values = counts;
945+
946+
if (evsel__ensure_counts(evsel))
947+
return PyErr_NoMemory();
948+
949+
/* Set up pointers to the old and newly read counter values. */
950+
old_count = perf_counts(evsel->prev_raw_counts, cpu_idx, thread_idx);
951+
new_count = perf_counts(evsel->counts, cpu_idx, thread_idx);
952+
/* Update the value in evsel->counts. */
953+
evsel__read_counter(evsel, cpu_idx, thread_idx);
954+
/* Copy the value and turn it into the delta from old_count. */
955+
count_values->values = *new_count;
956+
count_values->values.val -= old_count->val;
957+
count_values->values.ena -= old_count->ena;
958+
count_values->values.run -= old_count->run;
959+
/* Save the new count over the old_count for the next read. */
960+
*old_count = *new_count;
920961
return (PyObject *)count_values;
921962
}
922963

0 commit comments

Comments
 (0)