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

perf mem: Clean up perf_mem_events__ptr()

The mem_events can be retrieved from the struct perf_pmu now. An ARCH
specific perf_mem_events__ptr() is not required anymore. Remove all of
them.

The Intel hybrid has multiple mem-events-supported PMUs. But they share
the same mem_events. Other ARCHs only support one mem-events-supported
PMU. In the configuration, it's good enough to only configure the
mem_events for one PMU. Add perf_mem_events_find_pmu() which returns the
first mem-events-supported PMU.

In the perf_mem_events__init(), the perf_pmus__scan() is not required
anymore. It avoids checking the sysfs for every PMU on the system.

Make the perf_mem_events__record_args() more generic. Remove the
perf_mem_events__print_unsupport_hybrid().

Since pmu is added as a new parameter, rename perf_mem_events__ptr() to
perf_pmu__mem_events_ptr(). Several other functions also do a similar
rename.

Reviewed-by: Ian Rogers <irogers@google.com>
Reviewed-by: Kajol Jain <kjain@linux.ibm.com>
Tested-by: Ravi Bangoria <ravi.bangoria@amd.com>
Tested-by: Kajol jain <kjain@linux.ibm.com>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Cc: james.clark@arm.com
Cc: will@kernel.org
Cc: leo.yan@linaro.org
Cc: mike.leach@linaro.org
Cc: renyu.zj@linux.alibaba.com
Cc: yuhaixin.yhx@linux.alibaba.com
Cc: tmricht@linux.ibm.com
Cc: atrajeev@linux.vnet.ibm.com
Cc: linux-arm-kernel@lists.infradead.org
Cc: john.g.garry@oracle.com
Link: https://lore.kernel.org/r/20240123185036.3461837-3-kan.liang@linux.intel.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Kan Liang and committed by
Namhyung Kim
a30450e6 bb65acdc

+105 -93
+1 -9
tools/perf/arch/arm64/util/mem-events.c
··· 13 13 14 14 static char mem_ev_name[100]; 15 15 16 - struct perf_mem_event *perf_mem_events__ptr(int i) 17 - { 18 - if (i >= PERF_MEM_EVENTS__MAX) 19 - return NULL; 20 - 21 - return &perf_mem_events_arm[i]; 22 - } 23 - 24 16 const char *perf_mem_events__name(int i, const char *pmu_name __maybe_unused) 25 17 { 26 - struct perf_mem_event *e = perf_mem_events__ptr(i); 18 + struct perf_mem_event *e = &perf_mem_events_arm[i]; 27 19 28 20 if (i >= PERF_MEM_EVENTS__MAX) 29 21 return NULL;
+6 -12
tools/perf/arch/x86/util/mem-events.c
··· 28 28 E("mem-ldst", "ibs_op//", "ibs_op"), 29 29 }; 30 30 31 - struct perf_mem_event *perf_mem_events__ptr(int i) 32 - { 33 - if (i >= PERF_MEM_EVENTS__MAX) 34 - return NULL; 35 - 36 - if (x86__is_amd_cpu()) 37 - return &perf_mem_events_amd[i]; 38 - 39 - return &perf_mem_events_intel[i]; 40 - } 41 - 42 31 bool is_mem_loads_aux_event(struct evsel *leader) 43 32 { 44 33 struct perf_pmu *pmu = perf_pmus__find("cpu"); ··· 43 54 44 55 const char *perf_mem_events__name(int i, const char *pmu_name) 45 56 { 46 - struct perf_mem_event *e = perf_mem_events__ptr(i); 57 + struct perf_mem_event *e; 58 + 59 + if (x86__is_amd_cpu()) 60 + e = &perf_mem_events_amd[i]; 61 + else 62 + e = &perf_mem_events_intel[i]; 47 63 48 64 if (!e) 49 65 return NULL;
+21 -7
tools/perf/builtin-c2c.c
··· 3215 3215 const char *str, int unset __maybe_unused) 3216 3216 { 3217 3217 bool *event_set = (bool *) opt->value; 3218 + struct perf_pmu *pmu; 3219 + 3220 + pmu = perf_mem_events_find_pmu(); 3221 + if (!pmu) { 3222 + pr_err("failed: there is no PMU that supports perf c2c\n"); 3223 + exit(-1); 3224 + } 3218 3225 3219 3226 if (!strcmp(str, "list")) { 3220 - perf_mem_events__list(); 3227 + perf_pmu__mem_events_list(pmu); 3221 3228 exit(0); 3222 3229 } 3223 - if (perf_mem_events__parse(str)) 3230 + if (perf_pmu__mem_events_parse(pmu, str)) 3224 3231 exit(-1); 3225 3232 3226 3233 *event_set = true; ··· 3252 3245 bool all_user = false, all_kernel = false; 3253 3246 bool event_set = false; 3254 3247 struct perf_mem_event *e; 3248 + struct perf_pmu *pmu; 3255 3249 struct option options[] = { 3256 3250 OPT_CALLBACK('e', "event", &event_set, "event", 3257 3251 "event selector. Use 'perf c2c record -e list' to list available events", ··· 3264 3256 OPT_END() 3265 3257 }; 3266 3258 3267 - if (perf_mem_events__init()) { 3259 + pmu = perf_mem_events_find_pmu(); 3260 + if (!pmu) { 3261 + pr_err("failed: no PMU supports the memory events\n"); 3262 + return -1; 3263 + } 3264 + 3265 + if (perf_pmu__mem_events_init(pmu)) { 3268 3266 pr_err("failed: memory events not supported\n"); 3269 3267 return -1; 3270 3268 } ··· 3294 3280 rec_argv[i++] = "record"; 3295 3281 3296 3282 if (!event_set) { 3297 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD_STORE); 3283 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD_STORE); 3298 3284 /* 3299 3285 * The load and store operations are required, use the event 3300 3286 * PERF_MEM_EVENTS__LOAD_STORE if it is supported. ··· 3303 3289 e->record = true; 3304 3290 rec_argv[i++] = "-W"; 3305 3291 } else { 3306 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); 3292 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD); 3307 3293 e->record = true; 3308 3294 3309 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); 3295 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__STORE); 3310 3296 e->record = true; 3311 3297 } 3312 3298 } 3313 3299 3314 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); 3300 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD); 3315 3301 if (e->record) 3316 3302 rec_argv[i++] = "-W"; 3317 3303
+21 -7
tools/perf/builtin-mem.c
··· 43 43 const char *str, int unset __maybe_unused) 44 44 { 45 45 struct perf_mem *mem = *(struct perf_mem **)opt->value; 46 + struct perf_pmu *pmu; 47 + 48 + pmu = perf_mem_events_find_pmu(); 49 + if (!pmu) { 50 + pr_err("failed: there is no PMU that supports perf mem\n"); 51 + exit(-1); 52 + } 46 53 47 54 if (!strcmp(str, "list")) { 48 - perf_mem_events__list(); 55 + perf_pmu__mem_events_list(pmu); 49 56 exit(0); 50 57 } 51 - if (perf_mem_events__parse(str)) 58 + if (perf_pmu__mem_events_parse(pmu, str)) 52 59 exit(-1); 53 60 54 61 mem->operation = 0; ··· 79 72 int ret; 80 73 bool all_user = false, all_kernel = false; 81 74 struct perf_mem_event *e; 75 + struct perf_pmu *pmu; 82 76 struct option options[] = { 83 77 OPT_CALLBACK('e', "event", &mem, "event", 84 78 "event selector. use 'perf mem record -e list' to list available events", ··· 92 84 OPT_END() 93 85 }; 94 86 95 - if (perf_mem_events__init()) { 87 + pmu = perf_mem_events_find_pmu(); 88 + if (!pmu) { 89 + pr_err("failed: no PMU supports the memory events\n"); 90 + return -1; 91 + } 92 + 93 + if (perf_pmu__mem_events_init(pmu)) { 96 94 pr_err("failed: memory events not supported\n"); 97 95 return -1; 98 96 } ··· 127 113 128 114 rec_argv[i++] = "record"; 129 115 130 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD_STORE); 116 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD_STORE); 131 117 132 118 /* 133 119 * The load and store operations are required, use the event ··· 140 126 rec_argv[i++] = "-W"; 141 127 } else { 142 128 if (mem->operation & MEM_OPERATION_LOAD) { 143 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); 129 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD); 144 130 e->record = true; 145 131 } 146 132 147 133 if (mem->operation & MEM_OPERATION_STORE) { 148 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); 134 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__STORE); 149 135 e->record = true; 150 136 } 151 137 } 152 138 153 - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); 139 + e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD); 154 140 if (e->record) 155 141 rec_argv[i++] = "-W"; 156 142
+51 -54
tools/perf/util/mem-events.c
··· 29 29 static char mem_loads_name[100]; 30 30 static bool mem_loads_name__init; 31 31 32 - struct perf_mem_event * __weak perf_mem_events__ptr(int i) 32 + struct perf_mem_event *perf_pmu__mem_events_ptr(struct perf_pmu *pmu, int i) 33 33 { 34 - if (i >= PERF_MEM_EVENTS__MAX) 34 + if (i >= PERF_MEM_EVENTS__MAX || !pmu) 35 35 return NULL; 36 36 37 - return &perf_mem_events[i]; 37 + return &pmu->mem_events[i]; 38 + } 39 + 40 + static struct perf_pmu *perf_pmus__scan_mem(struct perf_pmu *pmu) 41 + { 42 + while ((pmu = perf_pmus__scan(pmu)) != NULL) { 43 + if (pmu->mem_events) 44 + return pmu; 45 + } 46 + return NULL; 47 + } 48 + 49 + struct perf_pmu *perf_mem_events_find_pmu(void) 50 + { 51 + /* 52 + * The current perf mem doesn't support per-PMU configuration. 53 + * The exact same configuration is applied to all the 54 + * mem_events supported PMUs. 55 + * Return the first mem_events supported PMU. 56 + * 57 + * Notes: The only case which may support multiple mem_events 58 + * supported PMUs is Intel hybrid. The exact same mem_events 59 + * is shared among the PMUs. Only configure the first PMU 60 + * is good enough as well. 61 + */ 62 + return perf_pmus__scan_mem(NULL); 38 63 } 39 64 40 65 const char * __weak perf_mem_events__name(int i, const char *pmu_name __maybe_unused) 41 66 { 42 - struct perf_mem_event *e = perf_mem_events__ptr(i); 67 + struct perf_mem_event *e = &perf_mem_events[i]; 43 68 44 69 if (!e) 45 70 return NULL; ··· 86 61 return false; 87 62 } 88 63 89 - int perf_mem_events__parse(const char *str) 64 + int perf_pmu__mem_events_parse(struct perf_pmu *pmu, const char *str) 90 65 { 91 66 char *tok, *saveptr = NULL; 92 67 bool found = false; ··· 104 79 105 80 while (tok) { 106 81 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 107 - struct perf_mem_event *e = perf_mem_events__ptr(j); 82 + struct perf_mem_event *e = perf_pmu__mem_events_ptr(pmu, j); 108 83 109 84 if (!e->tag) 110 85 continue; ··· 137 112 return !stat(path, &st); 138 113 } 139 114 140 - int perf_mem_events__init(void) 115 + int perf_pmu__mem_events_init(struct perf_pmu *pmu) 141 116 { 142 117 const char *mnt = sysfs__mount(); 143 118 bool found = false; ··· 147 122 return -ENOENT; 148 123 149 124 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 150 - struct perf_mem_event *e = perf_mem_events__ptr(j); 151 - struct perf_pmu *pmu = NULL; 125 + struct perf_mem_event *e = perf_pmu__mem_events_ptr(pmu, j); 152 126 153 127 /* 154 128 * If the event entry isn't valid, skip initialization ··· 156 132 if (!e->tag) 157 133 continue; 158 134 159 - /* 160 - * Scan all PMUs not just core ones, since perf mem/c2c on 161 - * platforms like AMD uses IBS OP PMU which is independent 162 - * of core PMU. 163 - */ 164 - while ((pmu = perf_pmus__scan(pmu)) != NULL) { 165 - e->supported |= perf_mem_event__supported(mnt, pmu, e); 166 - if (e->supported) { 167 - found = true; 168 - break; 169 - } 170 - } 135 + e->supported |= perf_mem_event__supported(mnt, pmu, e); 136 + if (e->supported) 137 + found = true; 171 138 } 172 139 173 140 return found ? 0 : -ENOENT; 174 141 } 175 142 176 - void perf_mem_events__list(void) 143 + void perf_pmu__mem_events_list(struct perf_pmu *pmu) 177 144 { 178 145 int j; 179 146 180 147 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 181 - struct perf_mem_event *e = perf_mem_events__ptr(j); 148 + struct perf_mem_event *e = perf_pmu__mem_events_ptr(pmu, j); 182 149 183 150 fprintf(stderr, "%-*s%-*s%s", 184 151 e->tag ? 13 : 0, ··· 180 165 } 181 166 } 182 167 183 - static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e, 184 - int idx) 185 - { 186 - const char *mnt = sysfs__mount(); 187 - struct perf_pmu *pmu = NULL; 188 - 189 - while ((pmu = perf_pmus__scan(pmu)) != NULL) { 190 - if (!perf_mem_event__supported(mnt, pmu, e)) { 191 - pr_err("failed: event '%s' not supported\n", 192 - perf_mem_events__name(idx, pmu->name)); 193 - } 194 - } 195 - } 196 - 197 168 int perf_mem_events__record_args(const char **rec_argv, int *argv_nr, 198 169 char **rec_tmp, int *tmp_nr) 199 170 { 200 171 const char *mnt = sysfs__mount(); 172 + struct perf_pmu *pmu = NULL; 201 173 int i = *argv_nr, k = 0; 202 174 struct perf_mem_event *e; 203 175 204 - for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 205 - e = perf_mem_events__ptr(j); 206 - if (!e->record) 207 - continue; 208 176 209 - if (perf_pmus__num_mem_pmus() == 1) { 177 + while ((pmu = perf_pmus__scan_mem(pmu)) != NULL) { 178 + for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 179 + e = perf_pmu__mem_events_ptr(pmu, j); 180 + 181 + if (!e->record) 182 + continue; 183 + 210 184 if (!e->supported) { 211 185 pr_err("failed: event '%s' not supported\n", 212 - perf_mem_events__name(j, NULL)); 186 + perf_mem_events__name(j, pmu->name)); 213 187 return -1; 214 188 } 215 189 216 - rec_argv[i++] = "-e"; 217 - rec_argv[i++] = perf_mem_events__name(j, NULL); 218 - } else { 219 - struct perf_pmu *pmu = NULL; 220 - 221 - if (!e->supported) { 222 - perf_mem_events__print_unsupport_hybrid(e, j); 223 - return -1; 224 - } 225 - 226 - while ((pmu = perf_pmus__scan(pmu)) != NULL) { 190 + if (perf_pmus__num_mem_pmus() == 1) { 191 + rec_argv[i++] = "-e"; 192 + rec_argv[i++] = perf_mem_events__name(j, NULL); 193 + } else { 227 194 const char *s = perf_mem_events__name(j, pmu->name); 228 195 229 196 if (!perf_mem_event__supported(mnt, pmu, e))
+5 -4
tools/perf/util/mem-events.h
··· 36 36 extern unsigned int perf_mem_events__loads_ldlat; 37 37 extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]; 38 38 39 - int perf_mem_events__parse(const char *str); 40 - int perf_mem_events__init(void); 39 + int perf_pmu__mem_events_parse(struct perf_pmu *pmu, const char *str); 40 + int perf_pmu__mem_events_init(struct perf_pmu *pmu); 41 41 42 42 const char *perf_mem_events__name(int i, const char *pmu_name); 43 - struct perf_mem_event *perf_mem_events__ptr(int i); 43 + struct perf_mem_event *perf_pmu__mem_events_ptr(struct perf_pmu *pmu, int i); 44 + struct perf_pmu *perf_mem_events_find_pmu(void); 44 45 bool is_mem_loads_aux_event(struct evsel *leader); 45 46 46 - void perf_mem_events__list(void); 47 + void perf_pmu__mem_events_list(struct perf_pmu *pmu); 47 48 int perf_mem_events__record_args(const char **rec_argv, int *argv_nr, 48 49 char **rec_tmp, int *tmp_nr); 49 50