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

perf parse-events: Avoid scanning PMUs that can't contain events

Add perf_pmus__scan_for_event that only reads sysfs for pmus that
could contain a given event.

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

authored by

Ian Rogers and committed by
Namhyung Kim
e1ec69ed 9c9f4a27

+97 -15
+18 -15
tools/perf/util/parse-events.c
··· 490 490 int ret = 0; 491 491 struct evsel *first_wildcard_match = NULL; 492 492 493 - while ((pmu = perf_pmus__scan(pmu)) != NULL) { 493 + while ((pmu = perf_pmus__scan_for_event(pmu, name)) != NULL) { 494 494 LIST_HEAD(config_terms); 495 495 struct perf_event_attr attr; 496 496 ··· 1681 1681 1682 1682 INIT_LIST_HEAD(list); 1683 1683 1684 - while ((pmu = perf_pmus__scan(pmu)) != NULL) { 1684 + while ((pmu = perf_pmus__scan_for_event(pmu, event_name)) != NULL) { 1685 + 1685 1686 if (parse_events__filter_pmu(parse_state, pmu)) 1686 1687 continue; 1687 1688 ··· 1761 1760 1762 1761 pmu = NULL; 1763 1762 /* Failed to add, try wildcard expansion of event_or_pmu as a PMU name. */ 1764 - while ((pmu = perf_pmus__scan(pmu)) != NULL) { 1765 - if (!parse_events__filter_pmu(parse_state, pmu) && 1766 - perf_pmu__wildcard_match(pmu, event_or_pmu)) { 1767 - if (!parse_events_add_pmu(parse_state, *listp, pmu, 1768 - const_parsed_terms, 1769 - first_wildcard_match, 1770 - /*alternate_hw_config=*/PERF_COUNT_HW_MAX)) { 1771 - ok++; 1772 - parse_state->wild_card_pmus = true; 1773 - } 1774 - if (first_wildcard_match == NULL) 1775 - first_wildcard_match = 1776 - container_of((*listp)->prev, struct evsel, core.node); 1763 + while ((pmu = perf_pmus__scan_matching_wildcard(pmu, event_or_pmu)) != NULL) { 1764 + 1765 + if (parse_events__filter_pmu(parse_state, pmu)) 1766 + continue; 1767 + 1768 + if (!parse_events_add_pmu(parse_state, *listp, pmu, 1769 + const_parsed_terms, 1770 + first_wildcard_match, 1771 + /*alternate_hw_config=*/PERF_COUNT_HW_MAX)) { 1772 + ok++; 1773 + parse_state->wild_card_pmus = true; 1774 + } 1775 + if (first_wildcard_match == NULL) { 1776 + first_wildcard_match = 1777 + container_of((*listp)->prev, struct evsel, core.node); 1777 1778 } 1778 1779 } 1779 1780 if (ok)
+77
tools/perf/util/pmus.c
··· 19 19 #include "tool_pmu.h" 20 20 #include "print-events.h" 21 21 #include "strbuf.h" 22 + #include "string2.h" 22 23 23 24 /* 24 25 * core_pmus: A PMU belongs to core_pmus if it's name is "cpu" or it's sysfs ··· 348 347 list_for_each_entry_continue(pmu, &core_pmus, list) 349 348 return pmu; 350 349 350 + return NULL; 351 + } 352 + 353 + struct perf_pmu *perf_pmus__scan_for_event(struct perf_pmu *pmu, const char *event) 354 + { 355 + bool use_core_pmus = !pmu || pmu->is_core; 356 + 357 + if (!pmu) { 358 + /* Hwmon filename values that aren't used. */ 359 + enum hwmon_type type; 360 + int number; 361 + /* 362 + * Core PMUs, other sysfs PMUs and tool PMU can take all event 363 + * types or aren't wother optimizing for. 364 + */ 365 + unsigned int to_read_pmus = PERF_TOOL_PMU_TYPE_PE_CORE_MASK | 366 + PERF_TOOL_PMU_TYPE_PE_OTHER_MASK | 367 + PERF_TOOL_PMU_TYPE_TOOL_MASK; 368 + 369 + /* Could the event be a hwmon event? */ 370 + if (parse_hwmon_filename(event, &type, &number, /*item=*/NULL, /*alarm=*/NULL)) 371 + to_read_pmus |= PERF_TOOL_PMU_TYPE_HWMON_MASK; 372 + 373 + pmu_read_sysfs(to_read_pmus); 374 + pmu = list_prepare_entry(pmu, &core_pmus, list); 375 + } 376 + if (use_core_pmus) { 377 + list_for_each_entry_continue(pmu, &core_pmus, list) 378 + return pmu; 379 + 380 + pmu = NULL; 381 + pmu = list_prepare_entry(pmu, &other_pmus, list); 382 + } 383 + list_for_each_entry_continue(pmu, &other_pmus, list) 384 + return pmu; 385 + return NULL; 386 + } 387 + 388 + struct perf_pmu *perf_pmus__scan_matching_wildcard(struct perf_pmu *pmu, const char *wildcard) 389 + { 390 + bool use_core_pmus = !pmu || pmu->is_core; 391 + 392 + if (!pmu) { 393 + /* 394 + * Core PMUs, other sysfs PMUs and tool PMU can have any name or 395 + * aren't wother optimizing for. 396 + */ 397 + unsigned int to_read_pmus = PERF_TOOL_PMU_TYPE_PE_CORE_MASK | 398 + PERF_TOOL_PMU_TYPE_PE_OTHER_MASK | 399 + PERF_TOOL_PMU_TYPE_TOOL_MASK; 400 + 401 + /* 402 + * Hwmon PMUs have an alias from a sysfs name like hwmon0, 403 + * hwmon1, etc. or have a name of hwmon_<name>. They therefore 404 + * can only have a wildcard match if the wildcard begins with 405 + * "hwmon". 406 + */ 407 + if (strisglob(wildcard) || 408 + (strlen(wildcard) >= 5 && strncmp("hwmon", wildcard, 5) == 0)) 409 + to_read_pmus |= PERF_TOOL_PMU_TYPE_HWMON_MASK; 410 + 411 + pmu_read_sysfs(to_read_pmus); 412 + pmu = list_prepare_entry(pmu, &core_pmus, list); 413 + } 414 + if (use_core_pmus) { 415 + list_for_each_entry_continue(pmu, &core_pmus, list) { 416 + if (perf_pmu__wildcard_match(pmu, wildcard)) 417 + return pmu; 418 + } 419 + pmu = NULL; 420 + pmu = list_prepare_entry(pmu, &other_pmus, list); 421 + } 422 + list_for_each_entry_continue(pmu, &other_pmus, list) { 423 + if (perf_pmu__wildcard_match(pmu, wildcard)) 424 + return pmu; 425 + } 351 426 return NULL; 352 427 } 353 428
+2
tools/perf/util/pmus.h
··· 19 19 20 20 struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu); 21 21 struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu); 22 + struct perf_pmu *perf_pmus__scan_for_event(struct perf_pmu *pmu, const char *event); 23 + struct perf_pmu *perf_pmus__scan_matching_wildcard(struct perf_pmu *pmu, const char *wildcard); 22 24 23 25 const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str); 24 26