]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf parse-events: Add terms for legacy hardware and cache config values
authorIan Rogers <irogers@google.com>
Sun, 5 Oct 2025 18:24:13 +0000 (11:24 -0700)
committerNamhyung Kim <namhyung@kernel.org>
Wed, 15 Oct 2025 14:59:10 +0000 (23:59 +0900)
Add the PMU terms legacy-hardware-config and
legacy-cache-config. These terms are similar to the config term in
that their values are assigned to the perf_event_attr config
value. They differ in that the PMU type is switched to be either
PERF_TYPE_HARDWARE or PERF_TYPE_HW_CACHE, and the PMU type is moved
into the extended type information of the config value. This will
allow later patches to add legacy events to json.

An example use of the terms is in the following:
```
$ perf stat -vv -e 'cpu/legacy-hardware-config=1/,cpu/legacy-cache-config=0x10001/' true
Using CPUID GenuineIntel-6-8D-1
Attempt to add: cpu/legacy-hardware-config=0x1/
..after resolving event: cpu/legacy-hardware-config=0x1/
Attempt to add: cpu/legacy-cache-config=0x10001/
..after resolving event: cpu/legacy-cache-config=0x10001/
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
  type                             0 (PERF_TYPE_HARDWARE)
  size                             136
  config                           0x1 (PERF_COUNT_HW_INSTRUCTIONS)
  sample_type                      IDENTIFIER
  read_format                      TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
  disabled                         1
  inherit                          1
  enable_on_exec                   1
------------------------------------------------------------
sys_perf_event_open: pid 994937  cpu -1  group_fd -1  flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
  type                             3 (PERF_TYPE_HW_CACHE)
  size                             136
  config                           0x10001 (PERF_COUNT_HW_CACHE_RESULT_MISS | PERF_COUNT_HW_CACHE_OP_READ | PERF_COUNT_HW_CACHE_L1I)
  sample_type                      IDENTIFIER
  read_format                      TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
  disabled                         1
  inherit                          1
  enable_on_exec                   1
------------------------------------------------------------
sys_perf_event_open: pid 994937  cpu -1  group_fd -1  flags 0x8 = 4
cpu/legacy-hardware-config=1/: -1: 1364046 414756 414756
cpu/legacy-cache-config=0x10001/: -1: 57453 414756 414756
cpu/legacy-hardware-config=1/: 1364046 414756 414756
cpu/legacy-cache-config=0x10001/: 57453 414756 414756

 Performance counter stats for 'true':

         1,364,046      cpu/legacy-hardware-config=1/
            57,453      cpu/legacy-cache-config=0x10001/

       0.001988593 seconds time elapsed

       0.002194000 seconds user
       0.000000000 seconds sys
```

Tested-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: James Clark <james.clark@linaro.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.l
tools/perf/util/pmu.c

index e0f18e9c80002e99a9f26eb71d1be6d435fc4613..4e003abe90f0d14fc5a44a6c5a8356b09f3f1343 100644 (file)
@@ -868,6 +868,8 @@ const char *parse_events__term_type_str(enum parse_events__term_type term_type)
                [PARSE_EVENTS__TERM_TYPE_RAW]                   = "raw",
                [PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE]          = "legacy-cache",
                [PARSE_EVENTS__TERM_TYPE_HARDWARE]              = "hardware",
+               [PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG]        = "legacy-hardware-config",
+               [PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG]   = "legacy-cache-config",
                [PARSE_EVENTS__TERM_TYPE_CPU]                   = "cpu",
                [PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV]         = "ratio-to-prev",
        };
@@ -921,6 +923,8 @@ config_term_avail(enum parse_events__term_type term_type, struct parse_events_er
        case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
        case PARSE_EVENTS__TERM_TYPE_HARDWARE:
        case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
+       case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
+       case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
        default:
                if (!err)
                        return false;
@@ -1093,6 +1097,8 @@ do {                                                                                      \
        case PARSE_EVENTS__TERM_TYPE_USER:
        case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
        case PARSE_EVENTS__TERM_TYPE_HARDWARE:
+       case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
+       case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
        default:
                parse_events_error__handle(parse_state->error, term->err_term,
                                        strdup(parse_events__term_type_str(term->type_term)),
@@ -1115,10 +1121,68 @@ do {                                                                                    \
 #undef CHECK_TYPE_VAL
 }
 
+static bool check_pmu_is_core(__u32 type, const struct parse_events_term *term,
+                             struct parse_events_error *err)
+{
+       struct perf_pmu *pmu = NULL;
+
+       /* Avoid loading all PMUs with perf_pmus__find_by_type, just scan the core ones. */
+       while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+               if (pmu->type == type)
+                       return true;
+       }
+       parse_events_error__handle(err, term->err_val,
+                               strdup("needs a core PMU"),
+                               NULL);
+       return false;
+}
+
 static int config_term_pmu(struct perf_event_attr *attr,
                           struct parse_events_term *term,
                           struct parse_events_state *parse_state)
 {
+       if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG) {
+               if (check_type_val(term, parse_state->error, PARSE_EVENTS__TERM_TYPE_NUM))
+                       return -EINVAL;
+               if (term->val.num >= PERF_COUNT_HW_MAX) {
+                       parse_events_error__handle(parse_state->error, term->err_val,
+                                                  strdup("too big"),
+                                                  NULL);
+                       return -EINVAL;
+               }
+               if (!check_pmu_is_core(attr->type, term, parse_state->error))
+                       return -EINVAL;
+               attr->config = term->val.num;
+               if (perf_pmus__supports_extended_type())
+                       attr->config |= (__u64)attr->type << PERF_PMU_TYPE_SHIFT;
+               attr->type = PERF_TYPE_HARDWARE;
+               return 0;
+       }
+       if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG) {
+               int cache_type, cache_op, cache_result;
+
+               if (check_type_val(term, parse_state->error, PARSE_EVENTS__TERM_TYPE_NUM))
+                       return -EINVAL;
+               cache_type = term->val.num & 0xFF;
+               cache_op = (term->val.num >> 8) & 0xFF;
+               cache_result = (term->val.num >> 16) & 0xFF;
+               if ((term->val.num & ~0xFFFFFF) ||
+                    cache_type >= PERF_COUNT_HW_CACHE_MAX ||
+                    cache_op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+                    cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) {
+                       parse_events_error__handle(parse_state->error, term->err_val,
+                                                  strdup("too big"),
+                                                  NULL);
+                       return -EINVAL;
+               }
+               if (!check_pmu_is_core(attr->type, term, parse_state->error))
+                       return -EINVAL;
+               attr->config = term->val.num;
+               if (perf_pmus__supports_extended_type())
+                       attr->config |= (__u64)attr->type << PERF_PMU_TYPE_SHIFT;
+               attr->type = PERF_TYPE_HW_CACHE;
+               return 0;
+       }
        if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) {
                struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
 
@@ -1205,6 +1269,8 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
        case PARSE_EVENTS__TERM_TYPE_CONFIG1:
        case PARSE_EVENTS__TERM_TYPE_CONFIG2:
        case PARSE_EVENTS__TERM_TYPE_CONFIG3:
+       case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
+       case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
        case PARSE_EVENTS__TERM_TYPE_NAME:
        case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
        case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
@@ -1348,6 +1414,8 @@ do {                                                              \
                case PARSE_EVENTS__TERM_TYPE_CONFIG1:
                case PARSE_EVENTS__TERM_TYPE_CONFIG2:
                case PARSE_EVENTS__TERM_TYPE_CONFIG3:
+               case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
+               case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
                case PARSE_EVENTS__TERM_TYPE_NAME:
                case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
                case PARSE_EVENTS__TERM_TYPE_RAW:
@@ -1386,6 +1454,8 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
                case PARSE_EVENTS__TERM_TYPE_CONFIG1:
                case PARSE_EVENTS__TERM_TYPE_CONFIG2:
                case PARSE_EVENTS__TERM_TYPE_CONFIG3:
+               case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
+               case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
                case PARSE_EVENTS__TERM_TYPE_NAME:
                case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
                case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
index 3052a48978f8b42c4e868499e60e6b48b87629ef..ad782da63c83e86e3cb8b074394714a07b2ec9ad 100644 (file)
@@ -83,7 +83,9 @@ enum parse_events__term_type {
        PARSE_EVENTS__TERM_TYPE_HARDWARE,
        PARSE_EVENTS__TERM_TYPE_CPU,
        PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV,
-#define        __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV + 1)
+       PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG,
+       PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG,
+#define        __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG + 1)
 };
 
 struct parse_events_term {
index d65eb32124c8e211388565f6cddd00cad309ac65..5c8924a9dbfcaacbdf8e49e806e9f8caa332e728 100644 (file)
@@ -332,6 +332,8 @@ aux-sample-size             { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZ
 metric-id              { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); }
 cpu                    { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CPU); }
 ratio-to-prev          { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV); }
+legacy-hardware-config         { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG); }
+legacy-cache-config    { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG); }
 cpu-cycles|cycles                              { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
 stalled-cycles-frontend|idle-cycles-frontend   { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
 stalled-cycles-backend|idle-cycles-backend     { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
index 2c3e539851c480e92d94cc05ca0982d1771b1191..e25a4201f9ade40ac65415358e67bee881f25872 100644 (file)
@@ -1532,6 +1532,34 @@ static int pmu_config_term(const struct perf_pmu *pmu,
                        assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
                        pmu_format_value(bits, term->val.num, &attr->config3, zero);
                        break;
+               case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
+                       assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+                       assert(term->val.num < PERF_COUNT_HW_MAX);
+                       assert(pmu->is_core);
+                       attr->config = term->val.num;
+                       if (perf_pmus__supports_extended_type())
+                               attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
+                       attr->type = PERF_TYPE_HARDWARE;
+                       break;
+               case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG: {
+#ifndef NDEBUG
+                       int cache_type = term->val.num & 0xFF;
+                       int cache_op = (term->val.num >> 8) & 0xFF;
+                       int cache_result = (term->val.num >> 16) & 0xFF;
+
+                       assert(cache_type < PERF_COUNT_HW_CACHE_MAX);
+                       assert(cache_op < PERF_COUNT_HW_CACHE_OP_MAX);
+                       assert(cache_result < PERF_COUNT_HW_CACHE_RESULT_MAX);
+#endif
+                       assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+                       assert((term->val.num & ~0xFFFFFF) == 0);
+                       assert(pmu->is_core);
+                       attr->config = term->val.num;
+                       if (perf_pmus__supports_extended_type())
+                               attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
+                       attr->type = PERF_TYPE_HW_CACHE;
+                       break;
+               }
                case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */
                        return -EINVAL;
                case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
@@ -1923,6 +1951,8 @@ int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_call
                "config1=0..0xffffffffffffffff",
                "config2=0..0xffffffffffffffff",
                "config3=0..0xffffffffffffffff",
+               "legacy-hardware-config=0..9,",
+               "legacy-cache-config=0..0xffffff,",
                "name=string",
                "period=number",
                "freq=number",