Skip to content

Commit bd741d8

Browse files
captain5050namhyung
authored andcommitted
perf parse-events: Allow the cpu term to be a PMU or CPU range
On hybrid systems, events like msr/tsc/ will aggregate counts across all CPUs. Often metrics only want a value like msr/tsc/ for the cores on which the metric is being computed. Listing each CPU with terms cpu=0,cpu=1.. is laborious and would need to be encoded for all variations of a CPU model. Allow the cpumask from a PMU to be an argument to the cpu term. For example in the following the cpumask of the cstate_pkg PMU selects the CPUs to count msr/tsc/ counter upon: ``` $ cat /sys/bus/event_source/devices/cstate_pkg/cpumask 0 $ perf stat -A -e 'msr/tsc,cpu=cstate_pkg/' -a sleep 0.1 Performance counter stats for 'system wide': CPU0 252,621,253 msr/tsc,cpu=cstate_pkg/ 0.101184092 seconds time elapsed ``` As the cpu term is now also allowed to be a string, allow it to encode a range of CPUs (a list can't be supported as ',' is already a special token). The "event qualifiers" section of the `perf list` man page is updated to detail the additional behavior. The man page formatting is tidied up in this section, as it was incorrectly appearing within the "parameterized events" section. Reviewed-by: Thomas Falcon <thomas.falcon@intel.com> Signed-off-by: Ian Rogers <irogers@google.com> Link: https://lore.kernel.org/r/20250719030517.1990983-5-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
1 parent ced4c24 commit bd741d8

2 files changed

Lines changed: 54 additions & 18 deletions

File tree

tools/perf/Documentation/perf-list.txt

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -278,26 +278,33 @@ also be supplied. For example:
278278

279279
perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ...
280280

281-
EVENT QUALIFIERS:
281+
EVENT QUALIFIERS
282+
----------------
282283

283284
It is also possible to add extra qualifiers to an event:
284285

285286
percore:
286287

287-
Sums up the event counts for all hardware threads in a core, e.g.:
288-
289-
290-
perf stat -e cpu/event=0,umask=0x3,percore=1/
288+
Sums up the event counts for all hardware threads in a core, e.g.:
289+
perf stat -e cpu/event=0,umask=0x3,percore=1/
291290

292291
cpu:
293292

294-
Specifies the CPU to open the event upon. The value may be repeated to
295-
specify opening the event on multiple CPUs:
293+
Specifies a CPU or a range of CPUs to open the event upon. It may
294+
also reference a PMU to copy the CPU mask from. The value may be
295+
repeated to specify opening the event on multiple CPUs.
296296

297+
Example 1: to open the instructions event on CPUs 0 and 2, the
298+
cycles event on CPUs 1 and 2:
299+
perf stat -e instructions/cpu=0,cpu=2/,cycles/cpu=1-2/ -a sleep 1
297300

298-
perf stat -e instructions/cpu=0,cpu=2/,cycles/cpu=1,cpu=2/ -a sleep 1
299-
perf stat -e data_read/cpu=0/,data_write/cpu=1/ -a sleep 1
301+
Example 2: to open the data_read uncore event on CPU 0 and the
302+
data_write uncore event on CPU 1:
303+
perf stat -e data_read/cpu=0/,data_write/cpu=1/ -a sleep 1
300304

305+
Example 3: to open the software msr/tsc/ event only on the CPUs
306+
matching those from the cpu_core PMU:
307+
perf stat -e msr/tsc,cpu=cpu_core/ -a sleep 1
301308

302309
EVENT GROUPS
303310
------------

tools/perf/util/parse-events.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,22 @@ static struct perf_cpu_map *get_config_cpu(const struct parse_events_terms *head
187187

188188
list_for_each_entry(term, &head_terms->terms, list) {
189189
if (term->type_term == PARSE_EVENTS__TERM_TYPE_CPU) {
190-
struct perf_cpu_map *cpu = perf_cpu_map__new_int(term->val.num);
191-
192-
perf_cpu_map__merge(&cpus, cpu);
193-
perf_cpu_map__put(cpu);
190+
struct perf_cpu_map *term_cpus;
191+
192+
if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
193+
term_cpus = perf_cpu_map__new_int(term->val.num);
194+
} else {
195+
struct perf_pmu *pmu = perf_pmus__find(term->val.str);
196+
197+
if (pmu && perf_cpu_map__is_empty(pmu->cpus))
198+
term_cpus = pmu->is_core ? cpu_map__online() : NULL;
199+
else if (pmu)
200+
term_cpus = perf_cpu_map__get(pmu->cpus);
201+
else
202+
term_cpus = perf_cpu_map__new(term->val.str);
203+
}
204+
perf_cpu_map__merge(&cpus, term_cpus);
205+
perf_cpu_map__put(term_cpus);
194206
}
195207
}
196208

@@ -1048,15 +1060,32 @@ do { \
10481060
return -EINVAL;
10491061
}
10501062
break;
1051-
case PARSE_EVENTS__TERM_TYPE_CPU:
1052-
CHECK_TYPE_VAL(NUM);
1053-
if (term->val.num >= (u64)cpu__max_present_cpu().cpu) {
1063+
case PARSE_EVENTS__TERM_TYPE_CPU: {
1064+
struct perf_cpu_map *map;
1065+
1066+
if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
1067+
if (term->val.num >= (u64)cpu__max_present_cpu().cpu) {
1068+
parse_events_error__handle(err, term->err_val,
1069+
strdup("too big"),
1070+
/*help=*/NULL);
1071+
return -EINVAL;
1072+
}
1073+
break;
1074+
}
1075+
assert(term->type_val == PARSE_EVENTS__TERM_TYPE_STR);
1076+
if (perf_pmus__find(term->val.str) != NULL)
1077+
break;
1078+
1079+
map = perf_cpu_map__new(term->val.str);
1080+
if (!map) {
10541081
parse_events_error__handle(err, term->err_val,
1055-
strdup("too big"),
1056-
NULL);
1082+
strdup("not a valid PMU or CPU number"),
1083+
/*help=*/NULL);
10571084
return -EINVAL;
10581085
}
1086+
perf_cpu_map__put(map);
10591087
break;
1088+
}
10601089
case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
10611090
case PARSE_EVENTS__TERM_TYPE_USER:
10621091
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:

0 commit comments

Comments
 (0)