perf list: Give more details about raw event encodings
authorIan Rogers <irogers@google.com>
Fri, 8 Mar 2024 00:19:13 +0000 (16:19 -0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 21 Mar 2024 13:41:29 +0000 (10:41 -0300)
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>
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/pmus.c
tools/perf/util/pmus.h
tools/perf/util/print-events.c

index 24be587e3537847974ae3ac789c833477c048a26..81952c6cd3c6f5e8d33e20eb3a2674e9396755f8 100644 (file)
@@ -1603,6 +1603,62 @@ bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name)
        return false;
 }
 
+int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb)
+{
+       static const char *const terms[] = {
+               "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",
+       };
+       struct perf_pmu_format *format;
+       int ret;
+
+       /*
+        * max-events and driver-config are missing above as are the internal
+        * types user, metric-id, raw, legacy cache and hardware. Assert against
+        * the enum parse_events__term_type so they are kept in sync.
+        */
+       _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6,
+                      "perf_pmu__for_each_format()'s terms must be kept in sync with enum parse_events__term_type");
+       list_for_each_entry(format, &pmu->format, list) {
+               perf_pmu_format__load(pmu, format);
+               ret = cb(state, format->name, (int)format->value, format->bits);
+               if (ret)
+                       return ret;
+       }
+       if (!pmu->is_core)
+               return 0;
+
+       for (size_t i = 0; i < ARRAY_SIZE(terms); i++) {
+               int config = PERF_PMU_FORMAT_VALUE_CONFIG;
+
+               if (i < PERF_PMU_FORMAT_VALUE_CONFIG_END)
+                       config = i;
+
+               ret = cb(state, terms[i], config, /*bits=*/NULL);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
 bool is_pmu_core(const char *name)
 {
        return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name);
@@ -1697,8 +1753,12 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
        pmu_add_cpu_aliases(pmu);
        list_for_each_entry(event, &pmu->aliases, list) {
                size_t buf_used;
+               int pmu_name_len;
 
                info.pmu_name = event->pmu_name ?: pmu->name;
+               pmu_name_len = skip_duplicate_pmus
+                       ? pmu_name_len_no_suffix(info.pmu_name, /*num=*/NULL)
+                       : (int)strlen(info.pmu_name);
                info.alias = NULL;
                if (event->desc) {
                        info.name = event->name;
@@ -1723,7 +1783,7 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
                info.encoding_desc = buf + buf_used;
                parse_events_terms__to_strbuf(&event->terms, &sb);
                buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
-                               "%s/%s/", info.pmu_name, sb.buf) + 1;
+                               "%.*s/%s/", pmu_name_len, info.pmu_name, sb.buf) + 1;
                info.topic = event->topic;
                info.str = sb.buf;
                info.deprecated = event->deprecated;
index e35d985206db517dc32a4d71a49b67e6b10ce182..9f5284b29ecf46e731cfc14054d43366803540fb 100644 (file)
@@ -196,6 +196,8 @@ struct pmu_event_info {
 };
 
 typedef int (*pmu_event_callback)(void *state, struct pmu_event_info *info);
+typedef int (*pmu_format_callback)(void *state, const char *name, int config,
+                                  const unsigned long *bits);
 
 void pmu_add_sys_aliases(struct perf_pmu *pmu);
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
@@ -215,6 +217,7 @@ int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, p
 int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load);
 void perf_pmu_format__set_value(void *format, int config, unsigned long *bits);
 bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name);
+int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb);
 
 bool is_pmu_core(const char *name);
 bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu);
index 16505071d362f43e004867e1548fc73de2e84316..2fd369e45832b6335ebd2ef75b5f2e12b41dfc80 100644 (file)
@@ -16,6 +16,7 @@
 #include "pmus.h"
 #include "pmu.h"
 #include "print-events.h"
+#include "strbuf.h"
 
 /*
  * core_pmus:  A PMU belongs to core_pmus if it's name is "cpu" or it's sysfs
@@ -503,6 +504,99 @@ void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *p
        zfree(&aliases);
 }
 
+struct build_format_string_args {
+       struct strbuf short_string;
+       struct strbuf long_string;
+       int num_formats;
+};
+
+static int build_format_string(void *state, const char *name, int config,
+                              const unsigned long *bits)
+{
+       struct build_format_string_args *args = state;
+       unsigned int num_bits;
+       int ret1, ret2 = 0;
+
+       (void)config;
+       args->num_formats++;
+       if (args->num_formats > 1) {
+               strbuf_addch(&args->long_string, ',');
+               if (args->num_formats < 4)
+                       strbuf_addch(&args->short_string, ',');
+       }
+       num_bits = bits ? bitmap_weight(bits, PERF_PMU_FORMAT_BITS) : 0;
+       if (num_bits <= 1) {
+               ret1 = strbuf_addf(&args->long_string, "%s", name);
+               if (args->num_formats < 4)
+                       ret2 = strbuf_addf(&args->short_string, "%s", name);
+       } else if (num_bits > 8) {
+               ret1 = strbuf_addf(&args->long_string, "%s=0..0x%llx", name,
+                                  ULLONG_MAX >> (64 - num_bits));
+               if (args->num_formats < 4) {
+                       ret2 = strbuf_addf(&args->short_string, "%s=0..0x%llx", name,
+                                          ULLONG_MAX >> (64 - num_bits));
+               }
+       } else {
+               ret1 = strbuf_addf(&args->long_string, "%s=0..%llu", name,
+                                 ULLONG_MAX >> (64 - num_bits));
+               if (args->num_formats < 4) {
+                       ret2 = strbuf_addf(&args->short_string, "%s=0..%llu", name,
+                                          ULLONG_MAX >> (64 - num_bits));
+               }
+       }
+       return ret1 < 0 ? ret1 : (ret2 < 0 ? ret2 : 0);
+}
+
+void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state)
+{
+       bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state);
+       struct perf_pmu *(*scan_fn)(struct perf_pmu *);
+       struct perf_pmu *pmu = NULL;
+
+       if (skip_duplicate_pmus)
+               scan_fn = perf_pmus__scan_skip_duplicates;
+       else
+               scan_fn = perf_pmus__scan;
+
+       while ((pmu = scan_fn(pmu)) != NULL) {
+               struct build_format_string_args format_args = {
+                       .short_string = STRBUF_INIT,
+                       .long_string = STRBUF_INIT,
+                       .num_formats = 0,
+               };
+               int len = pmu_name_len_no_suffix(pmu->name, /*num=*/NULL);
+               const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";
+
+               if (!pmu->is_core)
+                       desc = NULL;
+
+               strbuf_addf(&format_args.short_string, "%.*s/", len, pmu->name);
+               strbuf_addf(&format_args.long_string, "%.*s/", len, pmu->name);
+               perf_pmu__for_each_format(pmu, &format_args, build_format_string);
+
+               if (format_args.num_formats > 3)
+                       strbuf_addf(&format_args.short_string, ",.../modifier");
+               else
+                       strbuf_addf(&format_args.short_string, "/modifier");
+
+               strbuf_addf(&format_args.long_string, "/modifier");
+               print_cb->print_event(print_state,
+                               /*topic=*/NULL,
+                               /*pmu_name=*/NULL,
+                               format_args.short_string.buf,
+                               /*event_alias=*/NULL,
+                               /*scale_unit=*/NULL,
+                               /*deprecated=*/false,
+                               "Raw event descriptor",
+                               desc,
+                               /*long_desc=*/NULL,
+                               format_args.long_string.buf);
+
+               strbuf_release(&format_args.short_string);
+               strbuf_release(&format_args.long_string);
+       }
+}
+
 bool perf_pmus__have_event(const char *pname, const char *name)
 {
        struct perf_pmu *pmu = perf_pmus__find(pname);
index 94d2a08d894b7d21411f04a662bd52f93ea65a3d..eec599d8aebda65a166a90f6244a1792c9090c36 100644 (file)
@@ -18,6 +18,7 @@ struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu);
 const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str);
 
 void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state);
+void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state);
 bool perf_pmus__have_event(const char *pname, const char *name);
 int perf_pmus__num_core_pmus(void);
 bool perf_pmus__supports_extended_type(void);
index e0d2b49bab660af1ac92744a34c6370670d88cb6..3f38c27f0157616b3e3a7108505010d438c37be7 100644 (file)
@@ -39,7 +39,7 @@ static const char * const event_type_descriptors[] = {
        "Software event",
        "Tracepoint event",
        "Hardware cache event",
-       "Raw hardware event descriptor",
+       "Raw event descriptor",
        "Hardware breakpoint",
 };
 
@@ -416,8 +416,6 @@ void print_symbol_events(const struct print_callbacks *print_cb, void *print_sta
  */
 void print_events(const struct print_callbacks *print_cb, void *print_state)
 {
-       char *tmp;
-
        print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE,
                        event_symbols_hw, PERF_COUNT_HW_MAX);
        print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE,
@@ -441,21 +439,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
                        /*long_desc=*/NULL,
                        /*encoding_desc=*/NULL);
 
-       if (asprintf(&tmp, "%s/t1=v1[,t2=v2,t3 ...]/modifier",
-                    perf_pmus__scan_core(/*pmu=*/NULL)->name) > 0) {
-               print_cb->print_event(print_state,
-                               /*topic=*/NULL,
-                               /*pmu_name=*/NULL,
-                               tmp,
-                               /*event_alias=*/NULL,
-                               /*scale_unit=*/NULL,
-                               /*deprecated=*/false,
-                               event_type_descriptors[PERF_TYPE_RAW],
-                               "(see 'man perf-list' on how to encode it)",
-                               /*long_desc=*/NULL,
-                               /*encoding_desc=*/NULL);
-               free(tmp);
-       }
+       perf_pmus__print_raw_pmu_events(print_cb, print_state);
 
        print_cb->print_event(print_state,
                        /*topic=*/NULL,