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

perf pmu: Move pmu__find_core_pmu() to pmus.c

pmu__find_core_pmu() more logically belongs in pmus.c because it
iterates over all PMUs, so move it to pmus.c

At the same time rename it to perf_pmus__find_core_pmu() to match the
naming convention in this file.

list_prepare_entry() can't be used in perf_pmus__scan_core() anymore now
that it's called from the same compilation unit. This is with -O2
(specifically -O1 -ftree-vrp -finline-functions
-finline-small-functions) which allow the bounds of the array
access to be determined at compile time. list_prepare_entry() subtracts
the offset of the 'list' member in struct perf_pmu from &core_pmus,
which isn't a struct perf_pmu. The compiler sees that pmu results in
&core_pmus - 8 and refuses to compile. At runtime this works because
list_for_each_entry_continue() always adds the offset back again before
dereferencing ->next, but it's technically undefined behavior. With
-fsanitize=undefined an additional warning is generated.

Using list_first_entry_or_null() to get the first entry here avoids
doing &core_pmus - 8 but has the same result and fixes both the compile
warning and the undefined behavior warning. There are other uses of
list_prepare_entry() in pmus.c, but the compiler doesn't seem to be
able to see that they can also be called with &core_pmus, so I won't
change any at this time.

Signed-off-by: James Clark <james.clark@arm.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Reviewed-by: John Garry <john.g.garry@oracle.com>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Eduard Zingerman <eddyz87@gmail.com>
Cc: Will Deacon <will@kernel.org>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Jing Zhang <renyu.zj@linux.alibaba.com>
Cc: Haixin Yu <yuhaixin.yhx@linux.alibaba.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20230913153355.138331-2-james.clark@arm.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

James Clark and committed by
Namhyung Kim
3d0f5f45 21ce931e

+25 -24
+3 -3
tools/perf/arch/arm64/util/pmu.c
··· 10 10 11 11 const struct pmu_metrics_table *pmu_metrics_table__find(void) 12 12 { 13 - struct perf_pmu *pmu = pmu__find_core_pmu(); 13 + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); 14 14 15 15 if (pmu) 16 16 return perf_pmu__find_metrics_table(pmu); ··· 20 20 21 21 const struct pmu_events_table *pmu_events_table__find(void) 22 22 { 23 - struct perf_pmu *pmu = pmu__find_core_pmu(); 23 + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); 24 24 25 25 if (pmu) 26 26 return perf_pmu__find_events_table(pmu); ··· 32 32 { 33 33 char path[PATH_MAX]; 34 34 unsigned long long slots = 0; 35 - struct perf_pmu *pmu = pmu__find_core_pmu(); 35 + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); 36 36 37 37 if (pmu) { 38 38 perf_pmu__pathname_scnprintf(path, sizeof(path),
+1 -1
tools/perf/tests/expr.c
··· 76 76 struct expr_parse_ctx *ctx; 77 77 bool is_intel = false; 78 78 char strcmp_cpuid_buf[256]; 79 - struct perf_pmu *pmu = pmu__find_core_pmu(); 79 + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); 80 80 char *cpuid = perf_pmu__getcpuid(pmu); 81 81 char *escaped_cpuid1, *escaped_cpuid2; 82 82
+1 -1
tools/perf/util/expr.c
··· 509 509 bool compute_ids __maybe_unused, const char *test_id) 510 510 { 511 511 double ret; 512 - struct perf_pmu *pmu = pmu__find_core_pmu(); 512 + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); 513 513 char *cpuid = perf_pmu__getcpuid(pmu); 514 514 515 515 if (!cpuid)
-17
tools/perf/util/pmu.c
··· 2050 2050 zfree(&pmu->id); 2051 2051 free(pmu); 2052 2052 } 2053 - 2054 - struct perf_pmu *pmu__find_core_pmu(void) 2055 - { 2056 - struct perf_pmu *pmu = NULL; 2057 - 2058 - while ((pmu = perf_pmus__scan_core(pmu))) { 2059 - /* 2060 - * The cpumap should cover all CPUs. Otherwise, some CPUs may 2061 - * not support some events or have different event IDs. 2062 - */ 2063 - if (RC_CHK_ACCESS(pmu->cpus)->nr != cpu__max_cpu().cpu) 2064 - return NULL; 2065 - 2066 - return pmu; 2067 - } 2068 - return NULL; 2069 - }
+1 -1
tools/perf/util/pmu.h
··· 264 264 struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name); 265 265 struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus); 266 266 void perf_pmu__delete(struct perf_pmu *pmu); 267 - struct perf_pmu *pmu__find_core_pmu(void); 267 + struct perf_pmu *perf_pmus__find_core_pmu(void); 268 268 269 269 #endif /* __PMU_H */
+19 -1
tools/perf/util/pmus.c
··· 10 10 #include <pthread.h> 11 11 #include <string.h> 12 12 #include <unistd.h> 13 + #include "cpumap.h" 13 14 #include "debug.h" 14 15 #include "evsel.h" 15 16 #include "pmus.h" ··· 269 268 { 270 269 if (!pmu) { 271 270 pmu_read_sysfs(/*core_only=*/true); 272 - pmu = list_prepare_entry(pmu, &core_pmus, list); 271 + return list_first_entry_or_null(&core_pmus, typeof(*pmu), list); 273 272 } 274 273 list_for_each_entry_continue(pmu, &core_pmus, list) 275 274 return pmu; ··· 592 591 ((struct evsel *)evsel)->pmu = pmu; 593 592 } 594 593 return pmu; 594 + } 595 + 596 + struct perf_pmu *perf_pmus__find_core_pmu(void) 597 + { 598 + struct perf_pmu *pmu = NULL; 599 + 600 + while ((pmu = perf_pmus__scan_core(pmu))) { 601 + /* 602 + * The cpumap should cover all CPUs. Otherwise, some CPUs may 603 + * not support some events or have different event IDs. 604 + */ 605 + if (RC_CHK_ACCESS(pmu->cpus)->nr != cpu__max_cpu().cpu) 606 + return NULL; 607 + 608 + return pmu; 609 + } 610 + return NULL; 595 611 }