Skip to content

Commit 255f5b6

Browse files
captain5050acmel
authored andcommitted
perf parse-events: Add "cpu" term to set the CPU an event is recorded on
The -C option allows the CPUs for a list of events to be specified but its not possible to set the CPU for a single event. Add a term to allow this. The term isn't a general CPU list due to ',' already being a special character in event parsing instead multiple cpu= terms may be provided and they will be merged/unioned together. An example of mixing different types of events counted on different CPUs: ``` $ perf stat -A -C 0,4-5,8 -e "instructions/cpu=0/,l1d-misses/cpu=4,cpu=5/,inst_retired.any/cpu=8/,cycles" -a sleep 0.1 Performance counter stats for 'system wide': CPU0 6,979,225 instructions/cpu=0/ # 0.89 insn per cycle CPU4 75,138 cpu/l1d-misses/ CPU5 1,418,939 cpu/l1d-misses/ CPU8 797,553 cpu/inst_retired.any,cpu=8/ CPU0 7,845,302 cycles CPU4 6,546,859 cycles CPU5 185,915,438 cycles CPU8 2,065,668 cycles 0.112449242 seconds time elapsed ``` Committer testing: root@number:~# grep -m1 "model name" /proc/cpuinfo model name : AMD Ryzen 9 9950X3D 16-Core Processor root@number:~# perf stat -A -e "instructions/cpu=0/,instructions,l1d-misses/cpu=4,cpu=5/,cycles" -a sleep 0.1 Performance counter stats for 'system wide': CPU0 2,398,351 instructions/cpu=0/ # 0.44 insn per cycle CPU0 2,398,152 instructions # 0.44 insn per cycle CPU1 1,265,634 instructions # 0.49 insn per cycle CPU2 606,087 instructions # 0.50 insn per cycle CPU3 4,025,752 instructions # 0.52 insn per cycle CPU4 4,236,810 instructions # 0.53 insn per cycle CPU5 3,984,832 instructions # 0.66 insn per cycle CPU6 434,132 instructions # 0.44 insn per cycle CPU7 65,752 instructions # 0.41 insn per cycle CPU8 459,083 instructions # 0.48 insn per cycle CPU9 6,464,161 instructions # 1.31 insn per cycle <SNIP> root@number:~# perf stat -e "instructions/cpu=0/,instructions,l1d-misses/cpu=4,cpu=5/,cycles" -a sleep 0. Performance counter stats for 'system wide': 144,822 instructions/cpu=0/ # 0.03 insn per cycle 4,666,114 instructions # 0.93 insn per cycle 2,583 l1d-misses 4,993,633 cycles 0.000868512 seconds time elapsed root@number:~# Signed-off-by: Ian Rogers <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Tested-by: Kan Liang <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Dominique Martinet <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: James Clark <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Leo Yan <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Weilin Wang <[email protected]> Cc: Yicong Yang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 168c7b5 commit 255f5b6

File tree

6 files changed

+76
-17
lines changed

6 files changed

+76
-17
lines changed

tools/perf/Documentation/perf-list.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,15 @@ Sums up the event counts for all hardware threads in a core, e.g.:
289289

290290
perf stat -e cpu/event=0,umask=0x3,percore=1/
291291

292+
cpu:
293+
294+
Specifies the CPU to open the event upon. The value may be repeated to
295+
specify opening the event on multiple CPUs:
296+
297+
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
300+
292301

293302
EVENT GROUPS
294303
------------

tools/perf/util/evsel_config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct evsel_config_term {
4848
u32 aux_sample_size;
4949
u64 cfg_chg;
5050
char *str;
51+
int cpu;
5152
} val;
5253
bool weak;
5354
};

tools/perf/util/parse-events.c

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <errno.h>
88
#include <sys/ioctl.h>
99
#include <sys/param.h>
10+
#include "cpumap.h"
1011
#include "term.h"
1112
#include "env.h"
1213
#include "evlist.h"
@@ -180,6 +181,26 @@ static char *get_config_name(const struct parse_events_terms *head_terms)
180181
return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_NAME);
181182
}
182183

184+
static struct perf_cpu_map *get_config_cpu(const struct parse_events_terms *head_terms)
185+
{
186+
struct parse_events_term *term;
187+
struct perf_cpu_map *cpus = NULL;
188+
189+
if (!head_terms)
190+
return NULL;
191+
192+
list_for_each_entry(term, &head_terms->terms, list) {
193+
if (term->type_term == PARSE_EVENTS__TERM_TYPE_CPU) {
194+
struct perf_cpu_map *cpu = perf_cpu_map__new_int(term->val.num);
195+
196+
perf_cpu_map__merge(&cpus, cpu);
197+
perf_cpu_map__put(cpu);
198+
}
199+
}
200+
201+
return cpus;
202+
}
203+
183204
/**
184205
* fix_raw - For each raw term see if there is an event (aka alias) in pmu that
185206
* matches the raw's string value. If the string value matches an
@@ -443,11 +464,12 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
443464
bool found_supported = false;
444465
const char *config_name = get_config_name(parsed_terms);
445466
const char *metric_id = get_config_metric_id(parsed_terms);
467+
struct perf_cpu_map *cpus = get_config_cpu(parsed_terms);
468+
int ret = 0;
446469

447470
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
448471
LIST_HEAD(config_terms);
449472
struct perf_event_attr attr;
450-
int ret;
451473

452474
if (parse_events__filter_pmu(parse_state, pmu))
453475
continue;
@@ -462,7 +484,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
462484
perf_pmu__auto_merge_stats(pmu),
463485
/*alternate_hw_config=*/PERF_COUNT_HW_MAX);
464486
if (ret)
465-
return ret;
487+
goto out_err;
466488
continue;
467489
}
468490

@@ -482,21 +504,27 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
482504

483505
if (parsed_terms) {
484506
if (config_attr(&attr, parsed_terms, parse_state->error,
485-
config_term_common))
486-
return -EINVAL;
487-
488-
if (get_config_terms(parsed_terms, &config_terms))
489-
return -ENOMEM;
507+
config_term_common)) {
508+
ret = -EINVAL;
509+
goto out_err;
510+
}
511+
if (get_config_terms(parsed_terms, &config_terms)) {
512+
ret = -ENOMEM;
513+
goto out_err;
514+
}
490515
}
491516

492517
if (__add_event(list, idx, &attr, /*init_attr*/true, config_name ?: name,
493518
metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
494-
/*cpu_list=*/NULL,
495-
/*alternate_hw_config=*/PERF_COUNT_HW_MAX) == NULL)
496-
return -ENOMEM;
519+
cpus, /*alternate_hw_config=*/PERF_COUNT_HW_MAX) == NULL)
520+
ret = -ENOMEM;
497521

498522
free_config_terms(&config_terms);
523+
if (ret)
524+
goto out_err;
499525
}
526+
out_err:
527+
perf_cpu_map__put(cpus);
500528
return found_supported ? 0 : -EINVAL;
501529
}
502530

@@ -815,6 +843,7 @@ const char *parse_events__term_type_str(enum parse_events__term_type term_type)
815843
[PARSE_EVENTS__TERM_TYPE_RAW] = "raw",
816844
[PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE] = "legacy-cache",
817845
[PARSE_EVENTS__TERM_TYPE_HARDWARE] = "hardware",
846+
[PARSE_EVENTS__TERM_TYPE_CPU] = "cpu",
818847
};
819848
if ((unsigned int)term_type >= __PARSE_EVENTS__TERM_TYPE_NR)
820849
return "unknown term";
@@ -844,6 +873,7 @@ config_term_avail(enum parse_events__term_type term_type, struct parse_events_er
844873
case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
845874
case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
846875
case PARSE_EVENTS__TERM_TYPE_PERCORE:
876+
case PARSE_EVENTS__TERM_TYPE_CPU:
847877
return true;
848878
case PARSE_EVENTS__TERM_TYPE_USER:
849879
case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
@@ -991,6 +1021,15 @@ do { \
9911021
return -EINVAL;
9921022
}
9931023
break;
1024+
case PARSE_EVENTS__TERM_TYPE_CPU:
1025+
CHECK_TYPE_VAL(NUM);
1026+
if (term->val.num >= (u64)cpu__max_present_cpu().cpu) {
1027+
parse_events_error__handle(err, term->err_val,
1028+
strdup("too big"),
1029+
NULL);
1030+
return -EINVAL;
1031+
}
1032+
break;
9941033
case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
9951034
case PARSE_EVENTS__TERM_TYPE_USER:
9961035
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
@@ -1118,6 +1157,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
11181157
case PARSE_EVENTS__TERM_TYPE_RAW:
11191158
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
11201159
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
1160+
case PARSE_EVENTS__TERM_TYPE_CPU:
11211161
default:
11221162
if (err) {
11231163
parse_events_error__handle(err, term->err_term,
@@ -1252,6 +1292,7 @@ do { \
12521292
case PARSE_EVENTS__TERM_TYPE_RAW:
12531293
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
12541294
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
1295+
case PARSE_EVENTS__TERM_TYPE_CPU:
12551296
default:
12561297
break;
12571298
}
@@ -1306,6 +1347,7 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
13061347
case PARSE_EVENTS__TERM_TYPE_RAW:
13071348
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
13081349
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
1350+
case PARSE_EVENTS__TERM_TYPE_CPU:
13091351
default:
13101352
break;
13111353
}
@@ -1350,6 +1392,7 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state,
13501392
struct perf_event_attr attr;
13511393
LIST_HEAD(config_terms);
13521394
const char *name, *metric_id;
1395+
struct perf_cpu_map *cpus;
13531396
int ret;
13541397

13551398
memset(&attr, 0, sizeof(attr));
@@ -1371,10 +1414,11 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state,
13711414

13721415
name = get_config_name(head_config);
13731416
metric_id = get_config_metric_id(head_config);
1417+
cpus = get_config_cpu(head_config);
13741418
ret = __add_event(list, &parse_state->idx, &attr, /*init_attr*/true, name,
1375-
metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
1376-
/*cpu_list=*/NULL, /*alternate_hw_config=*/PERF_COUNT_HW_MAX
1377-
) == NULL ? -ENOMEM : 0;
1419+
metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
1420+
cpus, /*alternate_hw_config=*/PERF_COUNT_HW_MAX) ? 0 : -ENOMEM;
1421+
perf_cpu_map__put(cpus);
13781422
free_config_terms(&config_terms);
13791423
return ret;
13801424
}
@@ -1434,6 +1478,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
14341478
LIST_HEAD(config_terms);
14351479
struct parse_events_terms parsed_terms;
14361480
bool alias_rewrote_terms = false;
1481+
struct perf_cpu_map *term_cpu = NULL;
14371482

14381483
if (verbose > 1) {
14391484
struct strbuf sb;
@@ -1528,11 +1573,12 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
15281573
return -EINVAL;
15291574
}
15301575

1576+
term_cpu = get_config_cpu(&parsed_terms);
15311577
evsel = __add_event(list, &parse_state->idx, &attr, /*init_attr=*/true,
15321578
get_config_name(&parsed_terms),
15331579
get_config_metric_id(&parsed_terms), pmu,
1534-
&config_terms, auto_merge_stats, /*cpu_list=*/NULL,
1535-
alternate_hw_config);
1580+
&config_terms, auto_merge_stats, term_cpu, alternate_hw_config);
1581+
perf_cpu_map__put(term_cpu);
15361582
if (!evsel) {
15371583
parse_events_terms__exit(&parsed_terms);
15381584
return -ENOMEM;

tools/perf/util/parse-events.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ enum parse_events__term_type {
8080
PARSE_EVENTS__TERM_TYPE_RAW,
8181
PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE,
8282
PARSE_EVENTS__TERM_TYPE_HARDWARE,
83-
#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_HARDWARE + 1)
83+
PARSE_EVENTS__TERM_TYPE_CPU,
84+
#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_CPU + 1)
8485
};
8586

8687
struct parse_events_term {

tools/perf/util/parse-events.l

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); }
335335
aux-action { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_ACTION); }
336336
aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); }
337337
metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); }
338+
cpu { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CPU); }
338339
cpu-cycles|cycles { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
339340
stalled-cycles-frontend|idle-cycles-frontend { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
340341
stalled-cycles-backend|idle-cycles-backend { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }

tools/perf/util/pmu.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,7 @@ static int pmu_config_term(const struct perf_pmu *pmu,
14701470
break;
14711471
case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */
14721472
return -EINVAL;
1473-
case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_HARDWARE:
1473+
case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_CPU:
14741474
/* Skip non-config terms. */
14751475
break;
14761476
default:
@@ -1852,6 +1852,7 @@ int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_call
18521852
"aux-output",
18531853
"aux-action=(pause|resume|start-paused)",
18541854
"aux-sample-size=number",
1855+
"cpu=number",
18551856
};
18561857
struct perf_pmu_format *format;
18571858
int ret;

0 commit comments

Comments
 (0)