1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/list.h> 3 #include <linux/zalloc.h> 4 #include <subcmd/pager.h> 5 #include <sys/types.h> 6 #include <dirent.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include "debug.h" 10 #include "evsel.h" 11 #include "pmus.h" 12 #include "pmu.h" 13 #include "print-events.h" 14 15 static LIST_HEAD(core_pmus); 16 static LIST_HEAD(other_pmus); 17 18 void perf_pmus__destroy(void) 19 { 20 struct perf_pmu *pmu, *tmp; 21 22 list_for_each_entry_safe(pmu, tmp, &core_pmus, list) { 23 list_del(&pmu->list); 24 25 perf_pmu__delete(pmu); 26 } 27 list_for_each_entry_safe(pmu, tmp, &other_pmus, list) { 28 list_del(&pmu->list); 29 30 perf_pmu__delete(pmu); 31 } 32 } 33 34 static struct perf_pmu *pmu_find(const char *name) 35 { 36 struct perf_pmu *pmu; 37 38 list_for_each_entry(pmu, &core_pmus, list) { 39 if (!strcmp(pmu->name, name) || 40 (pmu->alias_name && !strcmp(pmu->alias_name, name))) 41 return pmu; 42 } 43 list_for_each_entry(pmu, &other_pmus, list) { 44 if (!strcmp(pmu->name, name) || 45 (pmu->alias_name && !strcmp(pmu->alias_name, name))) 46 return pmu; 47 } 48 49 return NULL; 50 } 51 52 struct perf_pmu *perf_pmus__find(const char *name) 53 { 54 struct perf_pmu *pmu; 55 int dirfd; 56 57 /* 58 * Once PMU is loaded it stays in the list, 59 * so we keep us from multiple reading/parsing 60 * the pmu format definitions. 61 */ 62 pmu = pmu_find(name); 63 if (pmu) 64 return pmu; 65 66 dirfd = perf_pmu__event_source_devices_fd(); 67 pmu = perf_pmu__lookup(is_pmu_core(name) ? &core_pmus : &other_pmus, dirfd, name); 68 close(dirfd); 69 70 return pmu; 71 } 72 73 static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name) 74 { 75 struct perf_pmu *pmu; 76 77 /* 78 * Once PMU is loaded it stays in the list, 79 * so we keep us from multiple reading/parsing 80 * the pmu format definitions. 81 */ 82 pmu = pmu_find(name); 83 if (pmu) 84 return pmu; 85 86 return perf_pmu__lookup(is_pmu_core(name) ? &core_pmus : &other_pmus, dirfd, name); 87 } 88 89 /* Add all pmus in sysfs to pmu list: */ 90 static void pmu_read_sysfs(void) 91 { 92 int fd; 93 DIR *dir; 94 struct dirent *dent; 95 96 fd = perf_pmu__event_source_devices_fd(); 97 if (fd < 0) 98 return; 99 100 dir = fdopendir(fd); 101 if (!dir) 102 return; 103 104 while ((dent = readdir(dir))) { 105 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 106 continue; 107 /* add to static LIST_HEAD(core_pmus) or LIST_HEAD(other_pmus): */ 108 perf_pmu__find2(fd, dent->d_name); 109 } 110 111 closedir(dir); 112 } 113 114 struct perf_pmu *perf_pmus__find_by_type(unsigned int type) 115 { 116 struct perf_pmu *pmu; 117 118 list_for_each_entry(pmu, &core_pmus, list) { 119 if (pmu->type == type) 120 return pmu; 121 } 122 list_for_each_entry(pmu, &other_pmus, list) { 123 if (pmu->type == type) 124 return pmu; 125 } 126 return NULL; 127 } 128 129 /* 130 * pmu iterator: If pmu is NULL, we start at the begin, otherwise return the 131 * next pmu. Returns NULL on end. 132 */ 133 struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu) 134 { 135 bool use_core_pmus = !pmu || pmu->is_core; 136 137 if (!pmu) { 138 pmu_read_sysfs(); 139 pmu = list_prepare_entry(pmu, &core_pmus, list); 140 } 141 if (use_core_pmus) { 142 list_for_each_entry_continue(pmu, &core_pmus, list) 143 return pmu; 144 145 pmu = NULL; 146 pmu = list_prepare_entry(pmu, &other_pmus, list); 147 } 148 list_for_each_entry_continue(pmu, &other_pmus, list) 149 return pmu; 150 return NULL; 151 } 152 153 const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str) 154 { 155 struct perf_pmu *pmu = NULL; 156 157 while ((pmu = perf_pmus__scan(pmu)) != NULL) { 158 if (!strcmp(pmu->name, str)) 159 return pmu; 160 /* Ignore "uncore_" prefix. */ 161 if (!strncmp(pmu->name, "uncore_", 7)) { 162 if (!strcmp(pmu->name + 7, str)) 163 return pmu; 164 } 165 /* Ignore "cpu_" prefix on Intel hybrid PMUs. */ 166 if (!strncmp(pmu->name, "cpu_", 4)) { 167 if (!strcmp(pmu->name + 4, str)) 168 return pmu; 169 } 170 } 171 return NULL; 172 } 173 174 int perf_pmus__num_mem_pmus(void) 175 { 176 struct perf_pmu *pmu = NULL; 177 int count = 0; 178 179 while ((pmu = perf_pmus__scan(pmu)) != NULL) { 180 if (perf_pmu__is_mem_pmu(pmu)) 181 count++; 182 } 183 return count; 184 } 185 186 /** Struct for ordering events as output in perf list. */ 187 struct sevent { 188 /** PMU for event. */ 189 const struct perf_pmu *pmu; 190 /** 191 * Optional event for name, desc, etc. If not present then this is a 192 * selectable PMU and the event name is shown as "//". 193 */ 194 const struct perf_pmu_alias *event; 195 /** Is the PMU for the CPU? */ 196 bool is_cpu; 197 }; 198 199 static int cmp_sevent(const void *a, const void *b) 200 { 201 const struct sevent *as = a; 202 const struct sevent *bs = b; 203 const char *a_pmu_name = NULL, *b_pmu_name = NULL; 204 const char *a_name = "//", *a_desc = NULL, *a_topic = ""; 205 const char *b_name = "//", *b_desc = NULL, *b_topic = ""; 206 int ret; 207 208 if (as->event) { 209 a_name = as->event->name; 210 a_desc = as->event->desc; 211 a_topic = as->event->topic ?: ""; 212 a_pmu_name = as->event->pmu_name; 213 } 214 if (bs->event) { 215 b_name = bs->event->name; 216 b_desc = bs->event->desc; 217 b_topic = bs->event->topic ?: ""; 218 b_pmu_name = bs->event->pmu_name; 219 } 220 /* Put extra events last. */ 221 if (!!a_desc != !!b_desc) 222 return !!a_desc - !!b_desc; 223 224 /* Order by topics. */ 225 ret = strcmp(a_topic, b_topic); 226 if (ret) 227 return ret; 228 229 /* Order CPU core events to be first */ 230 if (as->is_cpu != bs->is_cpu) 231 return as->is_cpu ? -1 : 1; 232 233 /* Order by PMU name. */ 234 if (as->pmu != bs->pmu) { 235 a_pmu_name = a_pmu_name ?: (as->pmu->name ?: ""); 236 b_pmu_name = b_pmu_name ?: (bs->pmu->name ?: ""); 237 ret = strcmp(a_pmu_name, b_pmu_name); 238 if (ret) 239 return ret; 240 } 241 242 /* Order by event name. */ 243 return strcmp(a_name, b_name); 244 } 245 246 static bool pmu_alias_is_duplicate(struct sevent *alias_a, 247 struct sevent *alias_b) 248 { 249 const char *a_pmu_name = NULL, *b_pmu_name = NULL; 250 const char *a_name = "//", *b_name = "//"; 251 252 253 if (alias_a->event) { 254 a_name = alias_a->event->name; 255 a_pmu_name = alias_a->event->pmu_name; 256 } 257 if (alias_b->event) { 258 b_name = alias_b->event->name; 259 b_pmu_name = alias_b->event->pmu_name; 260 } 261 262 /* Different names -> never duplicates */ 263 if (strcmp(a_name, b_name)) 264 return false; 265 266 /* Don't remove duplicates for different PMUs */ 267 a_pmu_name = a_pmu_name ?: (alias_a->pmu->name ?: ""); 268 b_pmu_name = b_pmu_name ?: (alias_b->pmu->name ?: ""); 269 return strcmp(a_pmu_name, b_pmu_name) == 0; 270 } 271 272 static int sub_non_neg(int a, int b) 273 { 274 if (b > a) 275 return 0; 276 return a - b; 277 } 278 279 static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, 280 const struct perf_pmu_alias *alias) 281 { 282 struct parse_events_term *term; 283 int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 284 285 list_for_each_entry(term, &alias->terms, list) { 286 if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 287 used += snprintf(buf + used, sub_non_neg(len, used), 288 ",%s=%s", term->config, 289 term->val.str); 290 } 291 292 if (sub_non_neg(len, used) > 0) { 293 buf[used] = '/'; 294 used++; 295 } 296 if (sub_non_neg(len, used) > 0) { 297 buf[used] = '\0'; 298 used++; 299 } else 300 buf[len - 1] = '\0'; 301 302 return buf; 303 } 304 305 void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state) 306 { 307 struct perf_pmu *pmu; 308 struct perf_pmu_alias *event; 309 char buf[1024]; 310 int printed = 0; 311 int len, j; 312 struct sevent *aliases; 313 314 pmu = NULL; 315 len = 0; 316 while ((pmu = perf_pmus__scan(pmu)) != NULL) { 317 list_for_each_entry(event, &pmu->aliases, list) 318 len++; 319 if (pmu->selectable) 320 len++; 321 } 322 aliases = zalloc(sizeof(struct sevent) * len); 323 if (!aliases) { 324 pr_err("FATAL: not enough memory to print PMU events\n"); 325 return; 326 } 327 pmu = NULL; 328 j = 0; 329 while ((pmu = perf_pmus__scan(pmu)) != NULL) { 330 bool is_cpu = pmu->is_core; 331 332 list_for_each_entry(event, &pmu->aliases, list) { 333 aliases[j].event = event; 334 aliases[j].pmu = pmu; 335 aliases[j].is_cpu = is_cpu; 336 j++; 337 } 338 if (pmu->selectable) { 339 aliases[j].event = NULL; 340 aliases[j].pmu = pmu; 341 aliases[j].is_cpu = is_cpu; 342 j++; 343 } 344 } 345 len = j; 346 qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 347 for (j = 0; j < len; j++) { 348 const char *name, *alias = NULL, *scale_unit = NULL, 349 *desc = NULL, *long_desc = NULL, 350 *encoding_desc = NULL, *topic = NULL, 351 *pmu_name = NULL; 352 bool deprecated = false; 353 size_t buf_used; 354 355 /* Skip duplicates */ 356 if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) 357 continue; 358 359 if (!aliases[j].event) { 360 /* A selectable event. */ 361 pmu_name = aliases[j].pmu->name; 362 buf_used = snprintf(buf, sizeof(buf), "%s//", pmu_name) + 1; 363 name = buf; 364 } else { 365 if (aliases[j].event->desc) { 366 name = aliases[j].event->name; 367 buf_used = 0; 368 } else { 369 name = format_alias(buf, sizeof(buf), aliases[j].pmu, 370 aliases[j].event); 371 if (aliases[j].is_cpu) { 372 alias = name; 373 name = aliases[j].event->name; 374 } 375 buf_used = strlen(buf) + 1; 376 } 377 pmu_name = aliases[j].event->pmu_name ?: (aliases[j].pmu->name ?: ""); 378 if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) { 379 scale_unit = buf + buf_used; 380 buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 381 "%G%s", aliases[j].event->scale, 382 aliases[j].event->unit) + 1; 383 } 384 desc = aliases[j].event->desc; 385 long_desc = aliases[j].event->long_desc; 386 topic = aliases[j].event->topic; 387 encoding_desc = buf + buf_used; 388 buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 389 "%s/%s/", pmu_name, aliases[j].event->str) + 1; 390 deprecated = aliases[j].event->deprecated; 391 } 392 print_cb->print_event(print_state, 393 pmu_name, 394 topic, 395 name, 396 alias, 397 scale_unit, 398 deprecated, 399 "Kernel PMU event", 400 desc, 401 long_desc, 402 encoding_desc); 403 } 404 if (printed && pager_in_use()) 405 printf("\n"); 406 407 zfree(&aliases); 408 } 409 410 bool perf_pmus__have_event(const char *pname, const char *name) 411 { 412 struct perf_pmu *pmu = perf_pmus__find(pname); 413 414 return pmu && perf_pmu__have_event(pmu, name); 415 } 416 417 bool perf_pmus__has_hybrid(void) 418 { 419 static bool hybrid_scanned, has_hybrid; 420 421 if (!hybrid_scanned) { 422 struct perf_pmu *pmu = NULL; 423 424 while ((pmu = perf_pmus__scan(pmu)) != NULL) { 425 if (pmu->is_core && is_pmu_hybrid(pmu->name)) { 426 has_hybrid = true; 427 break; 428 } 429 } 430 hybrid_scanned = true; 431 } 432 return has_hybrid; 433 } 434 435 struct perf_pmu *evsel__find_pmu(const struct evsel *evsel) 436 { 437 struct perf_pmu *pmu = evsel->pmu; 438 439 if (!pmu) { 440 pmu = perf_pmus__find_by_type(evsel->core.attr.type); 441 ((struct evsel *)evsel)->pmu = pmu; 442 } 443 return pmu; 444 } 445