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

perf pmu: Allow hardcoded terms to be applied to attributes

Hard coded terms like "config=10" are skipped by perf_pmu__config
assuming they were already applied to a perf_event_attr by parse
event's config_attr function. When doing a reverse number to name
lookup in perf_pmu__name_from_config, as the hardcoded terms aren't
applied the config value is incorrect leading to misses or false
matches. Fix this by adding a parameter to have perf_pmu__config apply
hardcoded terms too (not just in parse event's config_term_common).

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20241002032016.333748-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
c798f72c c051220d

+58 -12
+2 -1
tools/perf/arch/x86/util/intel-pt.c
··· 75 75 goto out_free; 76 76 77 77 attr.config = *config; 78 - err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*err=*/NULL); 78 + err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*apply_hardcoded=*/false, 79 + /*err=*/NULL); 79 80 if (err) 80 81 goto out_free; 81 82
+2 -1
tools/perf/tests/pmu.c
··· 176 176 } 177 177 178 178 memset(&attr, 0, sizeof(attr)); 179 - ret = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/false, /*err=*/NULL); 179 + ret = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/false, 180 + /*apply_hardcoded=*/false, /*err=*/NULL); 180 181 if (ret) { 181 182 pr_err("perf_pmu__config_terms failed"); 182 183 goto err_out;
+3 -1
tools/perf/util/parse-events.c
··· 1546 1546 return -ENOMEM; 1547 1547 } 1548 1548 1549 - if (perf_pmu__config(pmu, &attr, &parsed_terms, parse_state->error)) { 1549 + /* Skip configuring hard coded terms that were applied by config_attr. */ 1550 + if (perf_pmu__config(pmu, &attr, &parsed_terms, /*apply_hardcoded=*/false, 1551 + parse_state->error)) { 1550 1552 free_config_terms(&config_terms); 1551 1553 parse_events_terms__exit(&parsed_terms); 1552 1554 return -EINVAL;
+48 -8
tools/perf/util/pmu.c
··· 1366 1366 struct perf_event_attr *attr, 1367 1367 struct parse_events_term *term, 1368 1368 struct parse_events_terms *head_terms, 1369 - bool zero, struct parse_events_error *err) 1369 + bool zero, bool apply_hardcoded, 1370 + struct parse_events_error *err) 1370 1371 { 1371 1372 struct perf_pmu_format *format; 1372 1373 __u64 *vp; ··· 1381 1380 return 0; 1382 1381 1383 1382 /* 1384 - * Hardcoded terms should be already in, so nothing 1385 - * to be done for them. 1383 + * Hardcoded terms are generally handled in event parsing, which 1384 + * traditionally have had to handle not having a PMU. An alias may 1385 + * have hard coded config values, optionally apply them below. 1386 1386 */ 1387 - if (parse_events__is_hardcoded_term(term)) 1387 + if (parse_events__is_hardcoded_term(term)) { 1388 + /* Config terms set all bits in the config. */ 1389 + DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 1390 + 1391 + if (!apply_hardcoded) 1392 + return 0; 1393 + 1394 + bitmap_fill(bits, PERF_PMU_FORMAT_BITS); 1395 + 1396 + switch (term->type_term) { 1397 + case PARSE_EVENTS__TERM_TYPE_CONFIG: 1398 + assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); 1399 + pmu_format_value(bits, term->val.num, &attr->config, zero); 1400 + break; 1401 + case PARSE_EVENTS__TERM_TYPE_CONFIG1: 1402 + assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); 1403 + pmu_format_value(bits, term->val.num, &attr->config1, zero); 1404 + break; 1405 + case PARSE_EVENTS__TERM_TYPE_CONFIG2: 1406 + assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); 1407 + pmu_format_value(bits, term->val.num, &attr->config2, zero); 1408 + break; 1409 + case PARSE_EVENTS__TERM_TYPE_CONFIG3: 1410 + assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); 1411 + pmu_format_value(bits, term->val.num, &attr->config3, zero); 1412 + break; 1413 + case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */ 1414 + return -EINVAL; 1415 + case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_HARDWARE: 1416 + /* Skip non-config terms. */ 1417 + break; 1418 + default: 1419 + break; 1420 + } 1388 1421 return 0; 1422 + } 1389 1423 1390 1424 format = pmu_find_format(&pmu->format, term->config); 1391 1425 if (!format) { ··· 1523 1487 int perf_pmu__config_terms(const struct perf_pmu *pmu, 1524 1488 struct perf_event_attr *attr, 1525 1489 struct parse_events_terms *terms, 1526 - bool zero, struct parse_events_error *err) 1490 + bool zero, bool apply_hardcoded, 1491 + struct parse_events_error *err) 1527 1492 { 1528 1493 struct parse_events_term *term; 1529 1494 1530 1495 list_for_each_entry(term, &terms->terms, list) { 1531 - if (pmu_config_term(pmu, attr, term, terms, zero, err)) 1496 + if (pmu_config_term(pmu, attr, term, terms, zero, apply_hardcoded, err)) 1532 1497 return -EINVAL; 1533 1498 } 1534 1499 ··· 1543 1506 */ 1544 1507 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1545 1508 struct parse_events_terms *head_terms, 1509 + bool apply_hardcoded, 1546 1510 struct parse_events_error *err) 1547 1511 { 1548 1512 bool zero = !!pmu->perf_event_attr_init_default; ··· 1552 1514 if (perf_pmu__is_fake(pmu)) 1553 1515 return 0; 1554 1516 1555 - return perf_pmu__config_terms(pmu, attr, head_terms, zero, err); 1517 + return perf_pmu__config_terms(pmu, attr, head_terms, zero, apply_hardcoded, err); 1556 1518 } 1557 1519 1558 1520 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, ··· 2321 2283 pmu_add_cpu_aliases(pmu); 2322 2284 list_for_each_entry(event, &pmu->aliases, list) { 2323 2285 struct perf_event_attr attr = {.config = 0,}; 2324 - int ret = perf_pmu__config(pmu, &attr, &event->terms, NULL); 2286 + 2287 + int ret = perf_pmu__config(pmu, &attr, &event->terms, /*apply_hardcoded=*/true, 2288 + /*err=*/NULL); 2325 2289 2326 2290 if (ret == 0 && config == attr.config) 2327 2291 return event->name;
+3 -1
tools/perf/util/pmu.h
··· 206 206 void pmu_add_sys_aliases(struct perf_pmu *pmu); 207 207 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 208 208 struct parse_events_terms *head_terms, 209 + bool apply_hardcoded, 209 210 struct parse_events_error *error); 210 211 int perf_pmu__config_terms(const struct perf_pmu *pmu, 211 212 struct perf_event_attr *attr, 212 213 struct parse_events_terms *terms, 213 - bool zero, struct parse_events_error *error); 214 + bool zero, bool apply_hardcoded, 215 + struct parse_events_error *error); 214 216 __u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name); 215 217 int perf_pmu__format_type(struct perf_pmu *pmu, const char *name); 216 218 int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,