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

perf pmu: Save detected hybrid pmus to a global pmu list

We identify the cpu_core pmu and cpu_atom pmu by explicitly
checking following files:

For cpu_core, checks:
"/sys/bus/event_source/devices/cpu_core/cpus"

For cpu_atom, checks:
"/sys/bus/event_source/devices/cpu_atom/cpus"

If the 'cpus' file exists and it has data, the pmu exists.

But in order not to hardcode the "cpu_core" and "cpu_atom",
and make the code in a generic way.

So if the path "/sys/bus/event_source/devices/cpu_xxx/cpus" exists, the
hybrid pmu exists. All the detected hybrid pmus are linked to a global
list 'perf_pmu__hybrid_pmus' and then next we just need to iterate the
list to get all hybrid pmu by using perf_pmu__for_each_hybrid_pmu.

Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210427070139.25256-6-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Jin Yao and committed by
Arnaldo Carvalho de Melo
44462430 32705de7

+80 -1
+1
tools/perf/util/Build
··· 69 69 perf-y += pmu.o 70 70 perf-y += pmu-flex.o 71 71 perf-y += pmu-bison.o 72 + perf-y += pmu-hybrid.o 72 73 perf-y += trace-event-read.o 73 74 perf-y += trace-event-info.o 74 75 perf-y += trace-event-scripting.o
+49
tools/perf/util/pmu-hybrid.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/list.h> 3 + #include <linux/compiler.h> 4 + #include <linux/string.h> 5 + #include <linux/zalloc.h> 6 + #include <sys/types.h> 7 + #include <errno.h> 8 + #include <fcntl.h> 9 + #include <sys/stat.h> 10 + #include <unistd.h> 11 + #include <stdio.h> 12 + #include <stdbool.h> 13 + #include <stdarg.h> 14 + #include <locale.h> 15 + #include <api/fs/fs.h> 16 + #include "fncache.h" 17 + #include "pmu-hybrid.h" 18 + 19 + LIST_HEAD(perf_pmu__hybrid_pmus); 20 + 21 + bool perf_pmu__hybrid_mounted(const char *name) 22 + { 23 + char path[PATH_MAX]; 24 + const char *sysfs; 25 + FILE *file; 26 + int n, cpu; 27 + 28 + if (strncmp(name, "cpu_", 4)) 29 + return false; 30 + 31 + sysfs = sysfs__mountpoint(); 32 + if (!sysfs) 33 + return false; 34 + 35 + snprintf(path, PATH_MAX, CPUS_TEMPLATE_CPU, sysfs, name); 36 + if (!file_available(path)) 37 + return false; 38 + 39 + file = fopen(path, "r"); 40 + if (!file) 41 + return false; 42 + 43 + n = fscanf(file, "%u", &cpu); 44 + fclose(file); 45 + if (n <= 0) 46 + return false; 47 + 48 + return true; 49 + }
+18
tools/perf/util/pmu-hybrid.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __PMU_HYBRID_H 3 + #define __PMU_HYBRID_H 4 + 5 + #include <linux/perf_event.h> 6 + #include <linux/compiler.h> 7 + #include <linux/list.h> 8 + #include <stdbool.h> 9 + #include "pmu.h" 10 + 11 + extern struct list_head perf_pmu__hybrid_pmus; 12 + 13 + #define perf_pmu__for_each_hybrid_pmu(pmu) \ 14 + list_for_each_entry(pmu, &perf_pmu__hybrid_pmus, hybrid_list) 15 + 16 + bool perf_pmu__hybrid_mounted(const char *name); 17 + 18 + #endif /* __PMU_HYBRID_H */
+8 -1
tools/perf/util/pmu.c
··· 25 25 #include "string2.h" 26 26 #include "strbuf.h" 27 27 #include "fncache.h" 28 + #include "pmu-hybrid.h" 28 29 29 30 struct perf_pmu perf_pmu__fake; 30 31 ··· 614 613 */ 615 614 #define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier" 616 615 #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 617 - #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 618 616 619 617 static struct perf_cpu_map *pmu_cpumask(const char *name) 620 618 { ··· 644 644 { 645 645 char path[PATH_MAX]; 646 646 const char *sysfs; 647 + 648 + if (perf_pmu__hybrid_mounted(name)) 649 + return false; 647 650 648 651 sysfs = sysfs__mountpoint(); 649 652 snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); ··· 954 951 pmu->is_uncore = pmu_is_uncore(name); 955 952 if (pmu->is_uncore) 956 953 pmu->id = pmu_id(name); 954 + pmu->is_hybrid = perf_pmu__hybrid_mounted(name); 957 955 pmu->max_precise = pmu_max_precise(name); 958 956 pmu_add_cpu_aliases(&aliases, pmu); 959 957 pmu_add_sys_aliases(&aliases, pmu); ··· 965 961 list_splice(&format, &pmu->format); 966 962 list_splice(&aliases, &pmu->aliases); 967 963 list_add_tail(&pmu->list, &pmus); 964 + 965 + if (pmu->is_hybrid) 966 + list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus); 968 967 969 968 pmu->default_config = perf_pmu__get_default_config(pmu); 970 969
+4
tools/perf/util/pmu.h
··· 5 5 #include <linux/bitmap.h> 6 6 #include <linux/compiler.h> 7 7 #include <linux/perf_event.h> 8 + #include <linux/list.h> 8 9 #include <stdbool.h> 9 10 #include "parse-events.h" 10 11 #include "pmu-events/pmu-events.h" ··· 20 19 21 20 #define PERF_PMU_FORMAT_BITS 64 22 21 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 22 + #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 23 23 24 24 struct perf_event_attr; 25 25 ··· 36 34 __u32 type; 37 35 bool selectable; 38 36 bool is_uncore; 37 + bool is_hybrid; 39 38 bool auxtrace; 40 39 int max_precise; 41 40 struct perf_event_attr *default_config; ··· 45 42 struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ 46 43 struct list_head caps; /* HEAD struct perf_pmu_caps -> list */ 47 44 struct list_head list; /* ELEM */ 45 + struct list_head hybrid_list; 48 46 }; 49 47 50 48 extern struct perf_pmu perf_pmu__fake;