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

Configure Feed

Select the types of activity you want to include in your feed.

perf pmu: Abstract alias/event struct

In order to be able to lazily compute aliases/events for a PMU, move
the struct perf_pmu_alias into pmu.c.

Add perf_pmu__find_event and perf_pmu__for_each_event that take a
callback that is called for the found event or for each event.

The layout of struct pmu and the event/alias list is unchanged but the
API is altered so that aliases are no longer directly accessed, allowing
for later changes.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Gaosheng Cui <cuigaosheng1@huawei.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jing Zhang <renyu.zj@linux.alibaba.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
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: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20230824041330.266337-3-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
c3245d20 50402641

+365 -322
+2 -6
tools/perf/bench/pmu-scan.c
··· 57 57 r->is_core = pmu->is_core; 58 58 r->nr_caps = pmu->nr_caps; 59 59 60 - r->nr_aliases = 0; 61 - list_for_each(list, &pmu->aliases) 62 - r->nr_aliases++; 60 + r->nr_aliases = perf_pmu__num_events(pmu); 63 61 64 62 r->nr_formats = 0; 65 63 list_for_each(list, &pmu->format) ··· 96 98 return -1; 97 99 } 98 100 99 - nr = 0; 100 - list_for_each(list, &pmu->aliases) 101 - nr++; 101 + nr = perf_pmu__num_events(pmu); 102 102 if (nr != r->nr_aliases) { 103 103 pr_err("Unmatched number of event aliases in %s: expect %d vs got %d\n", 104 104 pmu->name, r->nr_aliases, nr);
+46 -51
tools/perf/tests/pmu-events.c
··· 341 341 return 0; 342 342 } 343 343 344 - static int compare_alias_to_test_event(struct perf_pmu_alias *alias, 344 + static int compare_alias_to_test_event(struct pmu_event_info *alias, 345 345 struct perf_pmu_test_event const *test_event, 346 346 char const *pmu_name) 347 347 { ··· 496 496 return 0; 497 497 } 498 498 499 + struct test_core_pmu_event_aliases_cb_args { 500 + struct perf_pmu_test_event const *test_event; 501 + int *count; 502 + }; 503 + 504 + static int test_core_pmu_event_aliases_cb(void *state, struct pmu_event_info *alias) 505 + { 506 + struct test_core_pmu_event_aliases_cb_args *args = state; 507 + 508 + if (compare_alias_to_test_event(alias, args->test_event, alias->pmu->name)) 509 + return -1; 510 + (*args->count)++; 511 + pr_debug2("testing aliases core PMU %s: matched event %s\n", 512 + alias->pmu_name, alias->name); 513 + return 0; 514 + } 515 + 499 516 /* Verify aliases are as expected */ 500 517 static int __test_core_pmu_event_aliases(char *pmu_name, int *count) 501 518 { ··· 539 522 pmu_add_cpu_aliases_table(pmu, table); 540 523 541 524 for (; *test_event_table; test_event_table++) { 542 - struct perf_pmu_test_event const *test_event = *test_event_table; 543 - struct pmu_event const *event = &test_event->event; 544 - struct perf_pmu_alias *alias = perf_pmu__find_alias(pmu, event->name); 525 + struct perf_pmu_test_event test_event = **test_event_table; 526 + struct pmu_event const *event = &test_event.event; 527 + struct test_core_pmu_event_aliases_cb_args args = { 528 + .test_event = &test_event, 529 + .count = count, 530 + }; 531 + int err; 545 532 546 - if (!alias) { 547 - pr_debug("testing aliases core PMU %s: no alias, alias_table->name=%s\n", 548 - pmu_name, event->name); 549 - res = -1; 550 - break; 551 - } 552 - 553 - if (compare_alias_to_test_event(alias, test_event, pmu_name)) { 554 - res = -1; 555 - break; 556 - } 557 - 558 - (*count)++; 559 - pr_debug2("testing aliases core PMU %s: matched event %s\n", 560 - pmu_name, alias->name); 533 + test_event.event.pmu = pmu_name; 534 + err = perf_pmu__find_event(pmu, event->name, &args, 535 + test_core_pmu_event_aliases_cb); 536 + if (err) 537 + res = err; 561 538 } 562 539 perf_pmu__delete(pmu); 563 540 ··· 564 553 struct perf_pmu_test_event const **table; 565 554 struct perf_pmu *pmu = &test_pmu->pmu; 566 555 const char *pmu_name = pmu->name; 567 - struct perf_pmu_alias *a, *tmp, *alias; 568 556 const struct pmu_events_table *events_table; 569 557 int res = 0; 570 558 ··· 574 564 pmu_add_sys_aliases(pmu); 575 565 576 566 /* Count how many aliases we generated */ 577 - list_for_each_entry(alias, &pmu->aliases, list) 578 - alias_count++; 567 + alias_count = perf_pmu__num_events(pmu); 579 568 580 569 /* Count how many aliases we expect from the known table */ 581 570 for (table = &test_pmu->aliases[0]; *table; table++) ··· 583 574 if (alias_count != to_match_count) { 584 575 pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n", 585 576 pmu_name, to_match_count, alias_count); 586 - res = -1; 587 - goto out; 577 + return -1; 588 578 } 589 579 590 - list_for_each_entry(alias, &pmu->aliases, list) { 591 - bool matched = false; 580 + for (table = &test_pmu->aliases[0]; *table; table++) { 581 + struct perf_pmu_test_event test_event = **table; 582 + struct pmu_event const *event = &test_event.event; 583 + int err; 584 + struct test_core_pmu_event_aliases_cb_args args = { 585 + .test_event = &test_event, 586 + .count = &matched_count, 587 + }; 592 588 593 - for (table = &test_pmu->aliases[0]; *table; table++) { 594 - struct perf_pmu_test_event const *test_event = *table; 595 - struct pmu_event const *event = &test_event->event; 596 - 597 - if (!strcmp(event->name, alias->name)) { 598 - if (compare_alias_to_test_event(alias, 599 - test_event, 600 - pmu_name)) { 601 - continue; 602 - } 603 - matched = true; 604 - matched_count++; 605 - } 606 - } 607 - 608 - if (matched == false) { 589 + err = perf_pmu__find_event(pmu, event->name, &args, 590 + test_core_pmu_event_aliases_cb); 591 + if (err) { 592 + res = err; 609 593 pr_debug("testing aliases uncore PMU %s: could not match alias %s\n", 610 - pmu_name, alias->name); 611 - res = -1; 612 - goto out; 594 + pmu_name, event->name); 595 + return -1; 613 596 } 614 597 } 615 598 ··· 609 608 pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n", 610 609 pmu_name, matched_count, alias_count); 611 610 res = -1; 612 - } 613 - 614 - out: 615 - list_for_each_entry_safe(a, tmp, &pmu->aliases, list) { 616 - list_del(&a->list); 617 - perf_pmu_free_alias(a); 618 611 } 619 612 return res; 620 613 }
+27 -40
tools/perf/util/parse-events.c
··· 193 193 struct parse_events_term *term; 194 194 195 195 list_for_each_entry(term, config_terms, list) { 196 - struct perf_pmu_alias *alias; 197 - bool matched = false; 196 + u64 num; 198 197 199 198 if (term->type_term != PARSE_EVENTS__TERM_TYPE_RAW) 200 199 continue; 201 200 202 - list_for_each_entry(alias, &pmu->aliases, list) { 203 - if (!strcmp(alias->name, term->val.str)) { 204 - free(term->config); 205 - term->config = term->val.str; 206 - term->type_val = PARSE_EVENTS__TERM_TYPE_NUM; 207 - term->type_term = PARSE_EVENTS__TERM_TYPE_USER; 208 - term->val.num = 1; 209 - term->no_value = true; 210 - matched = true; 211 - break; 212 - } 213 - } 214 - if (!matched) { 215 - u64 num; 216 - 201 + if (perf_pmu__have_event(pmu, term->val.str)) { 217 202 free(term->config); 218 - term->config = strdup("config"); 219 - errno = 0; 220 - num = strtoull(term->val.str + 1, NULL, 16); 221 - assert(errno == 0); 222 - free(term->val.str); 203 + term->config = term->val.str; 223 204 term->type_val = PARSE_EVENTS__TERM_TYPE_NUM; 224 - term->type_term = PARSE_EVENTS__TERM_TYPE_CONFIG; 225 - term->val.num = num; 226 - term->no_value = false; 205 + term->type_term = PARSE_EVENTS__TERM_TYPE_USER; 206 + term->val.num = 1; 207 + term->no_value = true; 208 + continue; 227 209 } 210 + 211 + free(term->config); 212 + term->config = strdup("config"); 213 + errno = 0; 214 + num = strtoull(term->val.str + 1, NULL, 16); 215 + assert(errno == 0); 216 + free(term->val.str); 217 + term->type_val = PARSE_EVENTS__TERM_TYPE_NUM; 218 + term->type_term = PARSE_EVENTS__TERM_TYPE_CONFIG; 219 + term->val.num = num; 220 + term->no_value = false; 228 221 } 229 222 } 230 223 ··· 1451 1458 INIT_LIST_HEAD(list); 1452 1459 1453 1460 while ((pmu = perf_pmus__scan(pmu)) != NULL) { 1454 - struct perf_pmu_alias *alias; 1455 1461 bool auto_merge_stats; 1456 1462 1457 1463 if (parse_events__filter_pmu(parse_state, pmu)) 1458 1464 continue; 1459 1465 1460 - auto_merge_stats = perf_pmu__auto_merge_stats(pmu); 1466 + if (!perf_pmu__have_event(pmu, str)) 1467 + continue; 1461 1468 1462 - list_for_each_entry(alias, &pmu->aliases, list) { 1463 - if (!strcasecmp(alias->name, str)) { 1464 - parse_events_copy_term_list(head, &orig_head); 1465 - if (!parse_events_add_pmu(parse_state, list, 1466 - pmu->name, orig_head, 1467 - auto_merge_stats, loc)) { 1468 - pr_debug("%s -> %s/%s/\n", str, 1469 - pmu->name, alias->str); 1470 - parse_state->wild_card_pmus = true; 1471 - ok++; 1472 - } 1473 - parse_events_terms__delete(orig_head); 1474 - } 1469 + auto_merge_stats = perf_pmu__auto_merge_stats(pmu); 1470 + parse_events_copy_term_list(head, &orig_head); 1471 + if (!parse_events_add_pmu(parse_state, list, pmu->name, 1472 + orig_head, auto_merge_stats, loc)) { 1473 + pr_debug("%s -> %s/%s/\n", str, pmu->name, str); 1474 + ok++; 1475 1475 } 1476 + parse_events_terms__delete(orig_head); 1476 1477 } 1477 1478 1478 1479 if (parse_state->fake_pmu) {
+194 -18
tools/perf/util/pmu.c
··· 31 31 32 32 struct perf_pmu perf_pmu__fake; 33 33 34 + #define UNIT_MAX_LEN 31 /* max length for event unit name */ 35 + 36 + /** 37 + * struct perf_pmu_alias - An event either read from sysfs or builtin in 38 + * pmu-events.c, created by parsing the pmu-events json files. 39 + */ 40 + struct perf_pmu_alias { 41 + /** @name: Name of the event like "mem-loads". */ 42 + char *name; 43 + /** @desc: Optional short description of the event. */ 44 + char *desc; 45 + /** @long_desc: Optional long description. */ 46 + char *long_desc; 47 + /** 48 + * @topic: Optional topic such as cache or pipeline, particularly for 49 + * json events. 50 + */ 51 + char *topic; 52 + /** 53 + * @str: Comma separated parameter list like 54 + * "event=0xcd,umask=0x1,ldlat=0x3". 55 + */ 56 + char *str; 57 + /** @terms: Owned list of the original parsed parameters. */ 58 + struct list_head terms; 59 + /** @list: List element of struct perf_pmu aliases. */ 60 + struct list_head list; 61 + /** @unit: Units for the event, such as bytes or cache lines. */ 62 + char unit[UNIT_MAX_LEN+1]; 63 + /** @scale: Value to scale read counter values by. */ 64 + double scale; 65 + /** 66 + * @per_pkg: Does the file 67 + * <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.per-pkg or 68 + * equivalent json value exist and have the value 1. 69 + */ 70 + bool per_pkg; 71 + /** 72 + * @snapshot: Does the file 73 + * <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.snapshot 74 + * exist and have the value 1. 75 + */ 76 + bool snapshot; 77 + /** 78 + * @deprecated: Is the event hidden and so not shown in perf list by 79 + * default. 80 + */ 81 + bool deprecated; 82 + /** 83 + * @pmu_name: The name copied from the json struct pmu_event. This can 84 + * differ from the PMU name as it won't have suffixes. 85 + */ 86 + char *pmu_name; 87 + }; 88 + 34 89 /** 35 90 * struct perf_pmu_format - Values from a format file read from 36 91 * <sysfs>/devices/cpu/format/ held in struct perf_pmu. ··· 410 355 } 411 356 412 357 /* Delete an alias entry. */ 413 - void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 358 + static void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 414 359 { 415 360 zfree(&newalias->name); 416 361 zfree(&newalias->desc); ··· 1404 1349 return perf_pmu__config_terms(pmu, attr, head_terms, zero, err); 1405 1350 } 1406 1351 1352 + static struct perf_pmu_alias *perf_pmu__find_alias(const struct perf_pmu *pmu, const char *str) 1353 + { 1354 + struct perf_pmu_alias *alias; 1355 + 1356 + list_for_each_entry(alias, &pmu->aliases, list) { 1357 + if (!strcasecmp(alias->name, str)) 1358 + return alias; 1359 + } 1360 + return NULL; 1361 + } 1362 + 1407 1363 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 1408 1364 struct parse_events_term *term) 1409 1365 { 1410 - struct perf_pmu_alias *alias; 1411 1366 char *name; 1412 1367 1413 1368 if (parse_events__is_hardcoded_term(term)) ··· 1429 1364 if (pmu_find_format(&pmu->format, term->config)) 1430 1365 return NULL; 1431 1366 name = term->config; 1367 + 1432 1368 } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1433 1369 if (strcasecmp(term->config, "event")) 1434 1370 return NULL; ··· 1438 1372 return NULL; 1439 1373 } 1440 1374 1441 - list_for_each_entry(alias, &pmu->aliases, list) { 1442 - if (!strcasecmp(alias->name, name)) 1443 - return alias; 1444 - } 1445 - return NULL; 1375 + return perf_pmu__find_alias(pmu, name); 1446 1376 } 1447 1377 1448 1378 ··· 1521 1459 return 0; 1522 1460 } 1523 1461 1524 - struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu, const char *event) 1462 + struct find_event_args { 1463 + const char *event; 1464 + void *state; 1465 + pmu_event_callback cb; 1466 + }; 1467 + 1468 + static int find_event_callback(void *state, struct pmu_event_info *info) 1525 1469 { 1526 - struct perf_pmu_alias *alias; 1470 + struct find_event_args *args = state; 1527 1471 1528 - list_for_each_entry(alias, &pmu->aliases, list) 1529 - if (!strcmp(event, alias->name)) 1530 - return alias; 1472 + if (!strcmp(args->event, info->name)) 1473 + return args->cb(args->state, info); 1531 1474 1532 - return NULL; 1475 + return 0; 1533 1476 } 1477 + 1478 + int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb) 1479 + { 1480 + struct find_event_args args = { 1481 + .event = event, 1482 + .state = state, 1483 + .cb = cb, 1484 + }; 1485 + 1486 + return perf_pmu__for_each_event(pmu, &args, find_event_callback); 1487 + } 1488 + 1534 1489 static void perf_pmu__del_formats(struct list_head *formats) 1535 1490 { 1536 1491 struct perf_pmu_format *fmt, *tmp; ··· 1587 1508 1588 1509 bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name) 1589 1510 { 1590 - struct perf_pmu_alias *alias; 1511 + return perf_pmu__find_alias(pmu, name) != NULL; 1512 + } 1591 1513 1592 - list_for_each_entry(alias, &pmu->aliases, list) { 1593 - if (!strcmp(alias->name, name)) 1594 - return true; 1514 + size_t perf_pmu__num_events(const struct perf_pmu *pmu) 1515 + { 1516 + struct list_head *list; 1517 + size_t nr = 0; 1518 + 1519 + list_for_each(list, &pmu->aliases) 1520 + nr++; 1521 + 1522 + return pmu->selectable ? nr + 1 : nr; 1523 + } 1524 + 1525 + static int sub_non_neg(int a, int b) 1526 + { 1527 + if (b > a) 1528 + return 0; 1529 + return a - b; 1530 + } 1531 + 1532 + static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, 1533 + const struct perf_pmu_alias *alias) 1534 + { 1535 + struct parse_events_term *term; 1536 + int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1537 + 1538 + list_for_each_entry(term, &alias->terms, list) { 1539 + if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1540 + used += snprintf(buf + used, sub_non_neg(len, used), 1541 + ",%s=%s", term->config, 1542 + term->val.str); 1595 1543 } 1596 - return false; 1544 + 1545 + if (sub_non_neg(len, used) > 0) { 1546 + buf[used] = '/'; 1547 + used++; 1548 + } 1549 + if (sub_non_neg(len, used) > 0) { 1550 + buf[used] = '\0'; 1551 + used++; 1552 + } else 1553 + buf[len - 1] = '\0'; 1554 + 1555 + return buf; 1556 + } 1557 + 1558 + int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_callback cb) 1559 + { 1560 + char buf[1024]; 1561 + struct perf_pmu_alias *event; 1562 + struct pmu_event_info info = { 1563 + .pmu = pmu, 1564 + }; 1565 + int ret = 0; 1566 + 1567 + list_for_each_entry(event, &pmu->aliases, list) { 1568 + size_t buf_used; 1569 + 1570 + info.pmu_name = event->pmu_name ?: pmu->name; 1571 + info.alias = NULL; 1572 + if (event->desc) { 1573 + info.name = event->name; 1574 + buf_used = 0; 1575 + } else { 1576 + info.name = format_alias(buf, sizeof(buf), pmu, event); 1577 + if (pmu->is_core) { 1578 + info.alias = info.name; 1579 + info.name = event->name; 1580 + } 1581 + buf_used = strlen(buf) + 1; 1582 + } 1583 + info.scale_unit = NULL; 1584 + if (strlen(event->unit) || event->scale != 1.0) { 1585 + info.scale_unit = buf + buf_used; 1586 + buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1587 + "%G%s", event->scale, event->unit) + 1; 1588 + } 1589 + info.desc = event->desc; 1590 + info.long_desc = event->long_desc; 1591 + info.encoding_desc = buf + buf_used; 1592 + buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1593 + "%s/%s/", info.pmu_name, event->str) + 1; 1594 + info.topic = event->topic; 1595 + info.str = event->str; 1596 + info.deprecated = event->deprecated; 1597 + ret = cb(state, &info); 1598 + if (ret) 1599 + return ret; 1600 + } 1601 + if (pmu->selectable) { 1602 + info.name = buf; 1603 + snprintf(buf, sizeof(buf), "%s//", pmu->name); 1604 + info.alias = NULL; 1605 + info.scale_unit = NULL; 1606 + info.desc = NULL; 1607 + info.long_desc = NULL; 1608 + info.encoding_desc = NULL; 1609 + info.topic = NULL; 1610 + info.pmu_name = pmu->name; 1611 + info.deprecated = false; 1612 + ret = cb(state, &info); 1613 + } 1614 + return ret; 1597 1615 } 1598 1616 1599 1617 bool perf_pmu__is_software(const struct perf_pmu *pmu)
+17 -54
tools/perf/util/pmu.h
··· 158 158 bool snapshot; 159 159 }; 160 160 161 - #define UNIT_MAX_LEN 31 /* max length for event unit name */ 162 - 163 - /** 164 - * struct perf_pmu_alias - An event either read from sysfs or builtin in 165 - * pmu-events.c, created by parsing the pmu-events json files. 166 - */ 167 - struct perf_pmu_alias { 168 - /** @name: Name of the event like "mem-loads". */ 169 - char *name; 170 - /** @desc: Optional short description of the event. */ 171 - char *desc; 172 - /** @long_desc: Optional long description. */ 173 - char *long_desc; 174 - /** 175 - * @topic: Optional topic such as cache or pipeline, particularly for 176 - * json events. 177 - */ 178 - char *topic; 179 - /** 180 - * @str: Comma separated parameter list like 181 - * "event=0xcd,umask=0x1,ldlat=0x3". 182 - */ 183 - char *str; 184 - /** @terms: Owned list of the original parsed parameters. */ 185 - struct list_head terms; 186 - /** @list: List element of struct perf_pmu aliases. */ 187 - struct list_head list; 188 - /** @unit: Units for the event, such as bytes or cache lines. */ 189 - char unit[UNIT_MAX_LEN+1]; 190 - /** @scale: Value to scale read counter values by. */ 191 - double scale; 192 - /** 193 - * @per_pkg: Does the file 194 - * <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.per-pkg or 195 - * equivalent json value exist and have the value 1. 196 - */ 197 - bool per_pkg; 198 - /** 199 - * @snapshot: Does the file 200 - * <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.snapshot 201 - * exist and have the value 1. 202 - */ 203 - bool snapshot; 204 - /** 205 - * @deprecated: Is the event hidden and so not shown in perf list by 206 - * default. 207 - */ 161 + struct pmu_event_info { 162 + const struct perf_pmu *pmu; 163 + const char *name; 164 + const char* alias; 165 + const char *scale_unit; 166 + const char *desc; 167 + const char *long_desc; 168 + const char *encoding_desc; 169 + const char *topic; 170 + const char *pmu_name; 171 + const char *str; 208 172 bool deprecated; 209 - /** 210 - * @pmu_name: The name copied from the json struct pmu_event. This can 211 - * differ from the PMU name as it won't have suffixes. 212 - */ 213 - char *pmu_name; 214 173 }; 174 + 175 + typedef int (*pmu_event_callback)(void *state, struct pmu_event_info *info); 215 176 216 177 void pmu_add_sys_aliases(struct perf_pmu *pmu); 217 178 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, ··· 186 225 int perf_pmu__format_type(struct perf_pmu *pmu, const char *name); 187 226 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 188 227 struct perf_pmu_info *info); 189 - struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu, const char *event); 228 + int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb); 190 229 191 230 int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load); 192 231 void perf_pmu_format__set_value(void *format, int config, unsigned long *bits); ··· 196 235 bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu); 197 236 bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu); 198 237 bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name); 238 + size_t perf_pmu__num_events(const struct perf_pmu *pmu); 239 + int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_callback cb); 240 + 199 241 /** 200 242 * perf_pmu_is_software - is the PMU a software PMU as in it uses the 201 243 * perf_sw_context in the kernel? ··· 223 259 char *perf_pmu__getcpuid(struct perf_pmu *pmu); 224 260 const struct pmu_events_table *pmu_events_table__find(void); 225 261 const struct pmu_metrics_table *pmu_metrics_table__find(void); 226 - void perf_pmu_free_alias(struct perf_pmu_alias *alias); 227 262 228 263 int perf_pmu__convert_scale(const char *scale, char **end, double *sval); 229 264
+79 -153
tools/perf/util/pmus.c
··· 258 258 struct sevent { 259 259 /** PMU for event. */ 260 260 const struct perf_pmu *pmu; 261 - /** 262 - * Optional event for name, desc, etc. If not present then this is a 263 - * selectable PMU and the event name is shown as "//". 264 - */ 265 - const struct perf_pmu_alias *event; 266 - /** Is the PMU for the CPU? */ 267 - bool is_cpu; 261 + const char *name; 262 + const char* alias; 263 + const char *scale_unit; 264 + const char *desc; 265 + const char *long_desc; 266 + const char *encoding_desc; 267 + const char *topic; 268 + const char *pmu_name; 269 + bool deprecated; 268 270 }; 269 271 270 272 static int cmp_sevent(const void *a, const void *b) 271 273 { 272 274 const struct sevent *as = a; 273 275 const struct sevent *bs = b; 274 - const char *a_pmu_name = NULL, *b_pmu_name = NULL; 275 - const char *a_name = "//", *a_desc = NULL, *a_topic = ""; 276 - const char *b_name = "//", *b_desc = NULL, *b_topic = ""; 276 + bool a_iscpu, b_iscpu; 277 277 int ret; 278 278 279 - if (as->event) { 280 - a_name = as->event->name; 281 - a_desc = as->event->desc; 282 - a_topic = as->event->topic ?: ""; 283 - a_pmu_name = as->event->pmu_name; 284 - } 285 - if (bs->event) { 286 - b_name = bs->event->name; 287 - b_desc = bs->event->desc; 288 - b_topic = bs->event->topic ?: ""; 289 - b_pmu_name = bs->event->pmu_name; 290 - } 291 279 /* Put extra events last. */ 292 - if (!!a_desc != !!b_desc) 293 - return !!a_desc - !!b_desc; 280 + if (!!as->desc != !!bs->desc) 281 + return !!as->desc - !!bs->desc; 294 282 295 283 /* Order by topics. */ 296 - ret = strcmp(a_topic, b_topic); 284 + ret = strcmp(as->topic ?: "", bs->topic ?: ""); 297 285 if (ret) 298 286 return ret; 299 287 300 288 /* Order CPU core events to be first */ 301 - if (as->is_cpu != bs->is_cpu) 302 - return as->is_cpu ? -1 : 1; 289 + a_iscpu = as->pmu ? as->pmu->is_core : true; 290 + b_iscpu = bs->pmu ? bs->pmu->is_core : true; 291 + if (a_iscpu != b_iscpu) 292 + return a_iscpu ? -1 : 1; 303 293 304 294 /* Order by PMU name. */ 305 295 if (as->pmu != bs->pmu) { 306 - a_pmu_name = a_pmu_name ?: (as->pmu->name ?: ""); 307 - b_pmu_name = b_pmu_name ?: (bs->pmu->name ?: ""); 308 - ret = strcmp(a_pmu_name, b_pmu_name); 296 + ret = strcmp(as->pmu_name ?: "", bs->pmu_name ?: ""); 309 297 if (ret) 310 298 return ret; 311 299 } 312 300 313 301 /* Order by event name. */ 314 - return strcmp(a_name, b_name); 302 + return strcmp(as->name, bs->name); 315 303 } 316 304 317 - static bool pmu_alias_is_duplicate(struct sevent *alias_a, 318 - struct sevent *alias_b) 305 + static bool pmu_alias_is_duplicate(struct sevent *a, struct sevent *b) 319 306 { 320 - const char *a_pmu_name = NULL, *b_pmu_name = NULL; 321 - const char *a_name = "//", *b_name = "//"; 322 - 323 - 324 - if (alias_a->event) { 325 - a_name = alias_a->event->name; 326 - a_pmu_name = alias_a->event->pmu_name; 327 - } 328 - if (alias_b->event) { 329 - b_name = alias_b->event->name; 330 - b_pmu_name = alias_b->event->pmu_name; 331 - } 332 - 333 307 /* Different names -> never duplicates */ 334 - if (strcmp(a_name, b_name)) 308 + if (strcmp(a->name ?: "//", b->name ?: "//")) 335 309 return false; 336 310 337 311 /* Don't remove duplicates for different PMUs */ 338 - a_pmu_name = a_pmu_name ?: (alias_a->pmu->name ?: ""); 339 - b_pmu_name = b_pmu_name ?: (alias_b->pmu->name ?: ""); 340 - return strcmp(a_pmu_name, b_pmu_name) == 0; 312 + return strcmp(a->pmu_name, b->pmu_name) == 0; 341 313 } 342 314 343 - static int sub_non_neg(int a, int b) 315 + struct events_callback_state { 316 + struct sevent *aliases; 317 + size_t aliases_len; 318 + size_t index; 319 + }; 320 + 321 + static int perf_pmus__print_pmu_events__callback(void *vstate, 322 + struct pmu_event_info *info) 344 323 { 345 - if (b > a) 346 - return 0; 347 - return a - b; 348 - } 324 + struct events_callback_state *state = vstate; 325 + struct sevent *s; 349 326 350 - static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, 351 - const struct perf_pmu_alias *alias) 352 - { 353 - struct parse_events_term *term; 354 - int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 355 - 356 - list_for_each_entry(term, &alias->terms, list) { 357 - if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 358 - used += snprintf(buf + used, sub_non_neg(len, used), 359 - ",%s=%s", term->config, 360 - term->val.str); 327 + if (state->index >= state->aliases_len) { 328 + pr_err("Unexpected event %s/%s/\n", info->pmu->name, info->name); 329 + return 1; 361 330 } 362 - 363 - if (sub_non_neg(len, used) > 0) { 364 - buf[used] = '/'; 365 - used++; 366 - } 367 - if (sub_non_neg(len, used) > 0) { 368 - buf[used] = '\0'; 369 - used++; 370 - } else 371 - buf[len - 1] = '\0'; 372 - 373 - return buf; 331 + s = &state->aliases[state->index]; 332 + s->pmu = info->pmu; 333 + #define COPY_STR(str) s->str = info->str ? strdup(info->str) : NULL 334 + COPY_STR(name); 335 + COPY_STR(alias); 336 + COPY_STR(scale_unit); 337 + COPY_STR(desc); 338 + COPY_STR(long_desc); 339 + COPY_STR(encoding_desc); 340 + COPY_STR(topic); 341 + COPY_STR(pmu_name); 342 + #undef COPY_STR 343 + s->deprecated = info->deprecated; 344 + state->index++; 345 + return 0; 374 346 } 375 347 376 348 void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state) 377 349 { 378 350 struct perf_pmu *pmu; 379 - struct perf_pmu_alias *event; 380 - char buf[1024]; 381 351 int printed = 0; 382 - int len, j; 352 + int len; 383 353 struct sevent *aliases; 354 + struct events_callback_state state; 384 355 385 356 pmu = NULL; 386 357 len = 0; 387 - while ((pmu = perf_pmus__scan(pmu)) != NULL) { 388 - list_for_each_entry(event, &pmu->aliases, list) 389 - len++; 390 - if (pmu->selectable) 391 - len++; 392 - } 358 + while ((pmu = perf_pmus__scan(pmu)) != NULL) 359 + len += perf_pmu__num_events(pmu); 360 + 393 361 aliases = zalloc(sizeof(struct sevent) * len); 394 362 if (!aliases) { 395 363 pr_err("FATAL: not enough memory to print PMU events\n"); 396 364 return; 397 365 } 398 366 pmu = NULL; 399 - j = 0; 367 + state = (struct events_callback_state) { 368 + .aliases = aliases, 369 + .aliases_len = len, 370 + .index = 0, 371 + }; 400 372 while ((pmu = perf_pmus__scan(pmu)) != NULL) { 401 - bool is_cpu = pmu->is_core; 402 - 403 - list_for_each_entry(event, &pmu->aliases, list) { 404 - aliases[j].event = event; 405 - aliases[j].pmu = pmu; 406 - aliases[j].is_cpu = is_cpu; 407 - j++; 408 - } 409 - if (pmu->selectable) { 410 - aliases[j].event = NULL; 411 - aliases[j].pmu = pmu; 412 - aliases[j].is_cpu = is_cpu; 413 - j++; 414 - } 373 + perf_pmu__for_each_event(pmu, &state, perf_pmus__print_pmu_events__callback); 415 374 } 416 - len = j; 417 375 qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 418 - for (j = 0; j < len; j++) { 419 - const char *name, *alias = NULL, *scale_unit = NULL, 420 - *desc = NULL, *long_desc = NULL, 421 - *encoding_desc = NULL, *topic = NULL, 422 - *pmu_name = NULL; 423 - bool deprecated = false; 424 - size_t buf_used; 425 - 376 + for (int j = 0; j < len; j++) { 426 377 /* Skip duplicates */ 427 378 if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) 428 379 continue; 429 380 430 - if (!aliases[j].event) { 431 - /* A selectable event. */ 432 - pmu_name = aliases[j].pmu->name; 433 - buf_used = snprintf(buf, sizeof(buf), "%s//", pmu_name) + 1; 434 - name = buf; 435 - } else { 436 - if (aliases[j].event->desc) { 437 - name = aliases[j].event->name; 438 - buf_used = 0; 439 - } else { 440 - name = format_alias(buf, sizeof(buf), aliases[j].pmu, 441 - aliases[j].event); 442 - if (aliases[j].is_cpu) { 443 - alias = name; 444 - name = aliases[j].event->name; 445 - } 446 - buf_used = strlen(buf) + 1; 447 - } 448 - pmu_name = aliases[j].event->pmu_name ?: (aliases[j].pmu->name ?: ""); 449 - if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) { 450 - scale_unit = buf + buf_used; 451 - buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 452 - "%G%s", aliases[j].event->scale, 453 - aliases[j].event->unit) + 1; 454 - } 455 - desc = aliases[j].event->desc; 456 - long_desc = aliases[j].event->long_desc; 457 - topic = aliases[j].event->topic; 458 - encoding_desc = buf + buf_used; 459 - buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 460 - "%s/%s/", pmu_name, aliases[j].event->str) + 1; 461 - deprecated = aliases[j].event->deprecated; 462 - } 463 381 print_cb->print_event(print_state, 464 - pmu_name, 465 - topic, 466 - name, 467 - alias, 468 - scale_unit, 469 - deprecated, 382 + aliases[j].pmu_name, 383 + aliases[j].topic, 384 + aliases[j].name, 385 + aliases[j].alias, 386 + aliases[j].scale_unit, 387 + aliases[j].deprecated, 470 388 "Kernel PMU event", 471 - desc, 472 - long_desc, 473 - encoding_desc); 389 + aliases[j].desc, 390 + aliases[j].long_desc, 391 + aliases[j].encoding_desc); 392 + zfree(&aliases[j].name); 393 + zfree(&aliases[j].alias); 394 + zfree(&aliases[j].scale_unit); 395 + zfree(&aliases[j].desc); 396 + zfree(&aliases[j].long_desc); 397 + zfree(&aliases[j].encoding_desc); 398 + zfree(&aliases[j].topic); 399 + zfree(&aliases[j].pmu_name); 474 400 } 475 401 if (printed && pager_in_use()) 476 402 printf("\n");