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