Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf list: Give more details about raw event encodings

List all the PMUs, not just the first core one, and list real format
specifiers with value ranges.

Before:

$ perf list
...
rNNN [Raw hardware event descriptor]
cpu/t1=v1[,t2=v2,t3 ...]/modifier [Raw hardware event descriptor]
[(see 'man perf-list' on how to encode it)]
mem:<addr>[/len][:access] [Hardware breakpoint]
...

After:

$ perf list
...
rNNN [Raw event descriptor]
cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
breakpoint//modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
intel_bts//modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
kprobe/retprobe/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
power/event=0..255/modifier [Raw event descriptor]
software//modifier [Raw event descriptor]
tracepoint//modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
mem:<addr>[/len][:access] [Hardware breakpoint]
...

With '--details' provide more details on the formats encoding:

cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
cpu/event=0..255,pc,edge,offcore_rsp=0..0xffffffffffffffff,ldlat=0..0xffff,inv,
umask=0..255,frontend=0..0xffffff,cmask=0..255,config=0..0xffffffffffffffff,
config1=0..0xffffffffffffffff,config2=0..0xffffffffffffffff,config3=0..0xffffffffffffffff,
name=string,period=number,freq=number,branch_type=(u|k|hv|any|...),time,
call-graph=(fp|dwarf|lbr),stack-size=number,max-stack=number,nr=number,inherit,no-inherit,
overwrite,no-overwrite,percore,aux-output,aux-sample-size=number/modifier
breakpoint//modifier [Raw event descriptor]
breakpoint//modifier
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier
intel_bts//modifier [Raw event descriptor]
intel_bts//modifier
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,pt,notnt,branch,tsc,pwr_evt,fup_on_ptw,cyc,noretcomp,
mtc,psb_period=0..15,mtc_period=0..15/modifier
kprobe/retprobe/modifier [Raw event descriptor]
kprobe/retprobe/modifier
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier
power/event=0..255/modifier [Raw event descriptor]
power/event=0..255/modifier
software//modifier [Raw event descriptor]
software//modifier
tracepoint//modifier [Raw event descriptor]
tracepoint//modifier
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier

Committer notes:

Address this build error in various distros:

55 58.44 ubuntu:24.04 : FAIL gcc version 13.2.0 (Ubuntu 13.2.0-17ubuntu2)
util/pmu.c:1638:70: error: '_Static_assert' with no message is a C2x extension [-Werror,-Wc2x-extensions]
1638 | _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6);
| ^
| , ""
1 error generated.

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Link: https://lore.kernel.org/r/20240308001915.4060155-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
4ccf3bb7 aa1f4ad2

+161 -19
+61 -1
tools/perf/util/pmu.c
··· 1603 1603 return false; 1604 1604 } 1605 1605 1606 + int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb) 1607 + { 1608 + static const char *const terms[] = { 1609 + "config=0..0xffffffffffffffff", 1610 + "config1=0..0xffffffffffffffff", 1611 + "config2=0..0xffffffffffffffff", 1612 + "config3=0..0xffffffffffffffff", 1613 + "name=string", 1614 + "period=number", 1615 + "freq=number", 1616 + "branch_type=(u|k|hv|any|...)", 1617 + "time", 1618 + "call-graph=(fp|dwarf|lbr)", 1619 + "stack-size=number", 1620 + "max-stack=number", 1621 + "nr=number", 1622 + "inherit", 1623 + "no-inherit", 1624 + "overwrite", 1625 + "no-overwrite", 1626 + "percore", 1627 + "aux-output", 1628 + "aux-sample-size=number", 1629 + }; 1630 + struct perf_pmu_format *format; 1631 + int ret; 1632 + 1633 + /* 1634 + * max-events and driver-config are missing above as are the internal 1635 + * types user, metric-id, raw, legacy cache and hardware. Assert against 1636 + * the enum parse_events__term_type so they are kept in sync. 1637 + */ 1638 + _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6, 1639 + "perf_pmu__for_each_format()'s terms must be kept in sync with enum parse_events__term_type"); 1640 + list_for_each_entry(format, &pmu->format, list) { 1641 + perf_pmu_format__load(pmu, format); 1642 + ret = cb(state, format->name, (int)format->value, format->bits); 1643 + if (ret) 1644 + return ret; 1645 + } 1646 + if (!pmu->is_core) 1647 + return 0; 1648 + 1649 + for (size_t i = 0; i < ARRAY_SIZE(terms); i++) { 1650 + int config = PERF_PMU_FORMAT_VALUE_CONFIG; 1651 + 1652 + if (i < PERF_PMU_FORMAT_VALUE_CONFIG_END) 1653 + config = i; 1654 + 1655 + ret = cb(state, terms[i], config, /*bits=*/NULL); 1656 + if (ret) 1657 + return ret; 1658 + } 1659 + return 0; 1660 + } 1661 + 1606 1662 bool is_pmu_core(const char *name) 1607 1663 { 1608 1664 return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name); ··· 1753 1697 pmu_add_cpu_aliases(pmu); 1754 1698 list_for_each_entry(event, &pmu->aliases, list) { 1755 1699 size_t buf_used; 1700 + int pmu_name_len; 1756 1701 1757 1702 info.pmu_name = event->pmu_name ?: pmu->name; 1703 + pmu_name_len = skip_duplicate_pmus 1704 + ? pmu_name_len_no_suffix(info.pmu_name, /*num=*/NULL) 1705 + : (int)strlen(info.pmu_name); 1758 1706 info.alias = NULL; 1759 1707 if (event->desc) { 1760 1708 info.name = event->name; ··· 1783 1723 info.encoding_desc = buf + buf_used; 1784 1724 parse_events_terms__to_strbuf(&event->terms, &sb); 1785 1725 buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1786 - "%s/%s/", info.pmu_name, sb.buf) + 1; 1726 + "%.*s/%s/", pmu_name_len, info.pmu_name, sb.buf) + 1; 1787 1727 info.topic = event->topic; 1788 1728 info.str = sb.buf; 1789 1729 info.deprecated = event->deprecated;
+3
tools/perf/util/pmu.h
··· 196 196 }; 197 197 198 198 typedef int (*pmu_event_callback)(void *state, struct pmu_event_info *info); 199 + typedef int (*pmu_format_callback)(void *state, const char *name, int config, 200 + const unsigned long *bits); 199 201 200 202 void pmu_add_sys_aliases(struct perf_pmu *pmu); 201 203 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, ··· 217 215 int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load); 218 216 void perf_pmu_format__set_value(void *format, int config, unsigned long *bits); 219 217 bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name); 218 + int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb); 220 219 221 220 bool is_pmu_core(const char *name); 222 221 bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu);
+94
tools/perf/util/pmus.c
··· 16 16 #include "pmus.h" 17 17 #include "pmu.h" 18 18 #include "print-events.h" 19 + #include "strbuf.h" 19 20 20 21 /* 21 22 * core_pmus: A PMU belongs to core_pmus if it's name is "cpu" or it's sysfs ··· 502 501 printf("\n"); 503 502 504 503 zfree(&aliases); 504 + } 505 + 506 + struct build_format_string_args { 507 + struct strbuf short_string; 508 + struct strbuf long_string; 509 + int num_formats; 510 + }; 511 + 512 + static int build_format_string(void *state, const char *name, int config, 513 + const unsigned long *bits) 514 + { 515 + struct build_format_string_args *args = state; 516 + unsigned int num_bits; 517 + int ret1, ret2 = 0; 518 + 519 + (void)config; 520 + args->num_formats++; 521 + if (args->num_formats > 1) { 522 + strbuf_addch(&args->long_string, ','); 523 + if (args->num_formats < 4) 524 + strbuf_addch(&args->short_string, ','); 525 + } 526 + num_bits = bits ? bitmap_weight(bits, PERF_PMU_FORMAT_BITS) : 0; 527 + if (num_bits <= 1) { 528 + ret1 = strbuf_addf(&args->long_string, "%s", name); 529 + if (args->num_formats < 4) 530 + ret2 = strbuf_addf(&args->short_string, "%s", name); 531 + } else if (num_bits > 8) { 532 + ret1 = strbuf_addf(&args->long_string, "%s=0..0x%llx", name, 533 + ULLONG_MAX >> (64 - num_bits)); 534 + if (args->num_formats < 4) { 535 + ret2 = strbuf_addf(&args->short_string, "%s=0..0x%llx", name, 536 + ULLONG_MAX >> (64 - num_bits)); 537 + } 538 + } else { 539 + ret1 = strbuf_addf(&args->long_string, "%s=0..%llu", name, 540 + ULLONG_MAX >> (64 - num_bits)); 541 + if (args->num_formats < 4) { 542 + ret2 = strbuf_addf(&args->short_string, "%s=0..%llu", name, 543 + ULLONG_MAX >> (64 - num_bits)); 544 + } 545 + } 546 + return ret1 < 0 ? ret1 : (ret2 < 0 ? ret2 : 0); 547 + } 548 + 549 + void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state) 550 + { 551 + bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state); 552 + struct perf_pmu *(*scan_fn)(struct perf_pmu *); 553 + struct perf_pmu *pmu = NULL; 554 + 555 + if (skip_duplicate_pmus) 556 + scan_fn = perf_pmus__scan_skip_duplicates; 557 + else 558 + scan_fn = perf_pmus__scan; 559 + 560 + while ((pmu = scan_fn(pmu)) != NULL) { 561 + struct build_format_string_args format_args = { 562 + .short_string = STRBUF_INIT, 563 + .long_string = STRBUF_INIT, 564 + .num_formats = 0, 565 + }; 566 + int len = pmu_name_len_no_suffix(pmu->name, /*num=*/NULL); 567 + const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)"; 568 + 569 + if (!pmu->is_core) 570 + desc = NULL; 571 + 572 + strbuf_addf(&format_args.short_string, "%.*s/", len, pmu->name); 573 + strbuf_addf(&format_args.long_string, "%.*s/", len, pmu->name); 574 + perf_pmu__for_each_format(pmu, &format_args, build_format_string); 575 + 576 + if (format_args.num_formats > 3) 577 + strbuf_addf(&format_args.short_string, ",.../modifier"); 578 + else 579 + strbuf_addf(&format_args.short_string, "/modifier"); 580 + 581 + strbuf_addf(&format_args.long_string, "/modifier"); 582 + print_cb->print_event(print_state, 583 + /*topic=*/NULL, 584 + /*pmu_name=*/NULL, 585 + format_args.short_string.buf, 586 + /*event_alias=*/NULL, 587 + /*scale_unit=*/NULL, 588 + /*deprecated=*/false, 589 + "Raw event descriptor", 590 + desc, 591 + /*long_desc=*/NULL, 592 + format_args.long_string.buf); 593 + 594 + strbuf_release(&format_args.short_string); 595 + strbuf_release(&format_args.long_string); 596 + } 505 597 } 506 598 507 599 bool perf_pmus__have_event(const char *pname, const char *name)
+1
tools/perf/util/pmus.h
··· 18 18 const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str); 19 19 20 20 void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state); 21 + void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state); 21 22 bool perf_pmus__have_event(const char *pname, const char *name); 22 23 int perf_pmus__num_core_pmus(void); 23 24 bool perf_pmus__supports_extended_type(void);
+2 -18
tools/perf/util/print-events.c
··· 39 39 "Software event", 40 40 "Tracepoint event", 41 41 "Hardware cache event", 42 - "Raw hardware event descriptor", 42 + "Raw event descriptor", 43 43 "Hardware breakpoint", 44 44 }; 45 45 ··· 416 416 */ 417 417 void print_events(const struct print_callbacks *print_cb, void *print_state) 418 418 { 419 - char *tmp; 420 - 421 419 print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE, 422 420 event_symbols_hw, PERF_COUNT_HW_MAX); 423 421 print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE, ··· 439 441 /*long_desc=*/NULL, 440 442 /*encoding_desc=*/NULL); 441 443 442 - if (asprintf(&tmp, "%s/t1=v1[,t2=v2,t3 ...]/modifier", 443 - perf_pmus__scan_core(/*pmu=*/NULL)->name) > 0) { 444 - print_cb->print_event(print_state, 445 - /*topic=*/NULL, 446 - /*pmu_name=*/NULL, 447 - tmp, 448 - /*event_alias=*/NULL, 449 - /*scale_unit=*/NULL, 450 - /*deprecated=*/false, 451 - event_type_descriptors[PERF_TYPE_RAW], 452 - "(see 'man perf-list' on how to encode it)", 453 - /*long_desc=*/NULL, 454 - /*encoding_desc=*/NULL); 455 - free(tmp); 456 - } 444 + perf_pmus__print_raw_pmu_events(print_cb, print_state); 457 445 458 446 print_cb->print_event(print_state, 459 447 /*topic=*/NULL,