737 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/list.h>3#include <linux/list_sort.h>4#include <linux/string.h>5#include <linux/zalloc.h>6#include <subcmd/pager.h>7#include <sys/types.h>8#include <ctype.h>9#include <dirent.h>10#include <pthread.h>11#include <string.h>12#include <unistd.h>13#include "cpumap.h"14#include "debug.h"15#include "evsel.h"16#include "pmus.h"17#include "pmu.h"18#include "print-events.h"19#include "strbuf.h"20 21/*22 * core_pmus: A PMU belongs to core_pmus if it's name is "cpu" or it's sysfs23 * directory contains "cpus" file. All PMUs belonging to core_pmus24 * must have pmu->is_core=1. If there are more than one PMU in25 * this list, perf interprets it as a heterogeneous platform.26 * (FWIW, certain ARM platforms having heterogeneous cores uses27 * homogeneous PMU, and thus they are treated as homogeneous28 * platform by perf because core_pmus will have only one entry)29 * other_pmus: All other PMUs which are not part of core_pmus list. It doesn't30 * matter whether PMU is present per SMT-thread or outside of the31 * core in the hw. For e.g., an instance of AMD ibs_fetch// and32 * ibs_op// PMUs is present in each hw SMT thread, however they33 * are captured under other_pmus. PMUs belonging to other_pmus34 * must have pmu->is_core=0 but pmu->is_uncore could be 0 or 1.35 */36static LIST_HEAD(core_pmus);37static LIST_HEAD(other_pmus);38static bool read_sysfs_core_pmus;39static bool read_sysfs_all_pmus;40 41static void pmu_read_sysfs(bool core_only);42 43size_t pmu_name_len_no_suffix(const char *str)44{45 int orig_len, len;46 bool has_hex_digits = false;47 48 orig_len = len = strlen(str);49 50 /* Count trailing digits. */51 while (len > 0 && isxdigit(str[len - 1])) {52 if (!isdigit(str[len - 1]))53 has_hex_digits = true;54 len--;55 }56 57 if (len > 0 && len != orig_len && str[len - 1] == '_') {58 /*59 * There is a '_{num}' suffix. For decimal suffixes any length60 * will do, for hexadecimal ensure more than 2 hex digits so61 * that S390's cpum_cf PMU doesn't match.62 */63 if (!has_hex_digits || (orig_len - len) > 2)64 return len - 1;65 }66 /* Use the full length. */67 return orig_len;68}69 70int pmu_name_cmp(const char *lhs_pmu_name, const char *rhs_pmu_name)71{72 unsigned long long lhs_num = 0, rhs_num = 0;73 size_t lhs_pmu_name_len = pmu_name_len_no_suffix(lhs_pmu_name);74 size_t rhs_pmu_name_len = pmu_name_len_no_suffix(rhs_pmu_name);75 int ret = strncmp(lhs_pmu_name, rhs_pmu_name,76 lhs_pmu_name_len < rhs_pmu_name_len ? lhs_pmu_name_len : rhs_pmu_name_len);77 78 if (lhs_pmu_name_len != rhs_pmu_name_len || ret != 0 || lhs_pmu_name_len == 0)79 return ret;80 81 if (lhs_pmu_name_len + 1 < strlen(lhs_pmu_name))82 lhs_num = strtoull(&lhs_pmu_name[lhs_pmu_name_len + 1], NULL, 16);83 if (rhs_pmu_name_len + 1 < strlen(rhs_pmu_name))84 rhs_num = strtoull(&rhs_pmu_name[rhs_pmu_name_len + 1], NULL, 16);85 86 return lhs_num < rhs_num ? -1 : (lhs_num > rhs_num ? 1 : 0);87}88 89void perf_pmus__destroy(void)90{91 struct perf_pmu *pmu, *tmp;92 93 list_for_each_entry_safe(pmu, tmp, &core_pmus, list) {94 list_del(&pmu->list);95 96 perf_pmu__delete(pmu);97 }98 list_for_each_entry_safe(pmu, tmp, &other_pmus, list) {99 list_del(&pmu->list);100 101 perf_pmu__delete(pmu);102 }103 read_sysfs_core_pmus = false;104 read_sysfs_all_pmus = false;105}106 107static struct perf_pmu *pmu_find(const char *name)108{109 struct perf_pmu *pmu;110 111 list_for_each_entry(pmu, &core_pmus, list) {112 if (!strcmp(pmu->name, name) ||113 (pmu->alias_name && !strcmp(pmu->alias_name, name)))114 return pmu;115 }116 list_for_each_entry(pmu, &other_pmus, list) {117 if (!strcmp(pmu->name, name) ||118 (pmu->alias_name && !strcmp(pmu->alias_name, name)))119 return pmu;120 }121 122 return NULL;123}124 125struct perf_pmu *perf_pmus__find(const char *name)126{127 struct perf_pmu *pmu;128 int dirfd;129 bool core_pmu;130 131 /*132 * Once PMU is loaded it stays in the list,133 * so we keep us from multiple reading/parsing134 * the pmu format definitions.135 */136 pmu = pmu_find(name);137 if (pmu)138 return pmu;139 140 if (read_sysfs_all_pmus)141 return NULL;142 143 core_pmu = is_pmu_core(name);144 if (core_pmu && read_sysfs_core_pmus)145 return NULL;146 147 dirfd = perf_pmu__event_source_devices_fd();148 pmu = perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name,149 /*eager_load=*/false);150 close(dirfd);151 152 if (!pmu) {153 /*154 * Looking up an inidividual PMU failed. This may mean name is155 * an alias, so read the PMUs from sysfs and try to find again.156 */157 pmu_read_sysfs(core_pmu);158 pmu = pmu_find(name);159 }160 return pmu;161}162 163static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)164{165 struct perf_pmu *pmu;166 bool core_pmu;167 168 /*169 * Once PMU is loaded it stays in the list,170 * so we keep us from multiple reading/parsing171 * the pmu format definitions.172 */173 pmu = pmu_find(name);174 if (pmu)175 return pmu;176 177 if (read_sysfs_all_pmus)178 return NULL;179 180 core_pmu = is_pmu_core(name);181 if (core_pmu && read_sysfs_core_pmus)182 return NULL;183 184 return perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name,185 /*eager_load=*/false);186}187 188static int pmus_cmp(void *priv __maybe_unused,189 const struct list_head *lhs, const struct list_head *rhs)190{191 struct perf_pmu *lhs_pmu = container_of(lhs, struct perf_pmu, list);192 struct perf_pmu *rhs_pmu = container_of(rhs, struct perf_pmu, list);193 194 return pmu_name_cmp(lhs_pmu->name ?: "", rhs_pmu->name ?: "");195}196 197/* Add all pmus in sysfs to pmu list: */198static void pmu_read_sysfs(bool core_only)199{200 int fd;201 DIR *dir;202 struct dirent *dent;203 204 if (read_sysfs_all_pmus || (core_only && read_sysfs_core_pmus))205 return;206 207 fd = perf_pmu__event_source_devices_fd();208 if (fd < 0)209 return;210 211 dir = fdopendir(fd);212 if (!dir) {213 close(fd);214 return;215 }216 217 while ((dent = readdir(dir))) {218 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))219 continue;220 if (core_only && !is_pmu_core(dent->d_name))221 continue;222 /* add to static LIST_HEAD(core_pmus) or LIST_HEAD(other_pmus): */223 perf_pmu__find2(fd, dent->d_name);224 }225 226 closedir(dir);227 if (list_empty(&core_pmus)) {228 if (!perf_pmu__create_placeholder_core_pmu(&core_pmus))229 pr_err("Failure to set up any core PMUs\n");230 }231 list_sort(NULL, &core_pmus, pmus_cmp);232 list_sort(NULL, &other_pmus, pmus_cmp);233 if (!list_empty(&core_pmus)) {234 read_sysfs_core_pmus = true;235 if (!core_only)236 read_sysfs_all_pmus = true;237 }238}239 240static struct perf_pmu *__perf_pmus__find_by_type(unsigned int type)241{242 struct perf_pmu *pmu;243 244 list_for_each_entry(pmu, &core_pmus, list) {245 if (pmu->type == type)246 return pmu;247 }248 249 list_for_each_entry(pmu, &other_pmus, list) {250 if (pmu->type == type)251 return pmu;252 }253 return NULL;254}255 256struct perf_pmu *perf_pmus__find_by_type(unsigned int type)257{258 struct perf_pmu *pmu = __perf_pmus__find_by_type(type);259 260 if (pmu || read_sysfs_all_pmus)261 return pmu;262 263 pmu_read_sysfs(/*core_only=*/false);264 pmu = __perf_pmus__find_by_type(type);265 return pmu;266}267 268/*269 * pmu iterator: If pmu is NULL, we start at the begin, otherwise return the270 * next pmu. Returns NULL on end.271 */272struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu)273{274 bool use_core_pmus = !pmu || pmu->is_core;275 276 if (!pmu) {277 pmu_read_sysfs(/*core_only=*/false);278 pmu = list_prepare_entry(pmu, &core_pmus, list);279 }280 if (use_core_pmus) {281 list_for_each_entry_continue(pmu, &core_pmus, list)282 return pmu;283 284 pmu = NULL;285 pmu = list_prepare_entry(pmu, &other_pmus, list);286 }287 list_for_each_entry_continue(pmu, &other_pmus, list)288 return pmu;289 return NULL;290}291 292struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu)293{294 if (!pmu) {295 pmu_read_sysfs(/*core_only=*/true);296 return list_first_entry_or_null(&core_pmus, typeof(*pmu), list);297 }298 list_for_each_entry_continue(pmu, &core_pmus, list)299 return pmu;300 301 return NULL;302}303 304static struct perf_pmu *perf_pmus__scan_skip_duplicates(struct perf_pmu *pmu)305{306 bool use_core_pmus = !pmu || pmu->is_core;307 int last_pmu_name_len = 0;308 const char *last_pmu_name = (pmu && pmu->name) ? pmu->name : "";309 310 if (!pmu) {311 pmu_read_sysfs(/*core_only=*/false);312 pmu = list_prepare_entry(pmu, &core_pmus, list);313 } else314 last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");315 316 if (use_core_pmus) {317 list_for_each_entry_continue(pmu, &core_pmus, list) {318 int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");319 320 if (last_pmu_name_len == pmu_name_len &&321 !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len))322 continue;323 324 return pmu;325 }326 pmu = NULL;327 pmu = list_prepare_entry(pmu, &other_pmus, list);328 }329 list_for_each_entry_continue(pmu, &other_pmus, list) {330 int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");331 332 if (last_pmu_name_len == pmu_name_len &&333 !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len))334 continue;335 336 return pmu;337 }338 return NULL;339}340 341const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str)342{343 struct perf_pmu *pmu = NULL;344 345 while ((pmu = perf_pmus__scan(pmu)) != NULL) {346 if (!strcmp(pmu->name, str))347 return pmu;348 /* Ignore "uncore_" prefix. */349 if (!strncmp(pmu->name, "uncore_", 7)) {350 if (!strcmp(pmu->name + 7, str))351 return pmu;352 }353 /* Ignore "cpu_" prefix on Intel hybrid PMUs. */354 if (!strncmp(pmu->name, "cpu_", 4)) {355 if (!strcmp(pmu->name + 4, str))356 return pmu;357 }358 }359 return NULL;360}361 362/** Struct for ordering events as output in perf list. */363struct sevent {364 /** PMU for event. */365 const struct perf_pmu *pmu;366 const char *name;367 const char* alias;368 const char *scale_unit;369 const char *desc;370 const char *long_desc;371 const char *encoding_desc;372 const char *topic;373 const char *pmu_name;374 const char *event_type_desc;375 bool deprecated;376};377 378static int cmp_sevent(const void *a, const void *b)379{380 const struct sevent *as = a;381 const struct sevent *bs = b;382 bool a_iscpu, b_iscpu;383 int ret;384 385 /* Put extra events last. */386 if (!!as->desc != !!bs->desc)387 return !!as->desc - !!bs->desc;388 389 /* Order by topics. */390 ret = strcmp(as->topic ?: "", bs->topic ?: "");391 if (ret)392 return ret;393 394 /* Order CPU core events to be first */395 a_iscpu = as->pmu ? as->pmu->is_core : true;396 b_iscpu = bs->pmu ? bs->pmu->is_core : true;397 if (a_iscpu != b_iscpu)398 return a_iscpu ? -1 : 1;399 400 /* Order by PMU name. */401 if (as->pmu != bs->pmu) {402 ret = strcmp(as->pmu_name ?: "", bs->pmu_name ?: "");403 if (ret)404 return ret;405 }406 407 /* Order by event name. */408 return strcmp(as->name, bs->name);409}410 411static bool pmu_alias_is_duplicate(struct sevent *a, struct sevent *b)412{413 /* Different names -> never duplicates */414 if (strcmp(a->name ?: "//", b->name ?: "//"))415 return false;416 417 /* Don't remove duplicates for different PMUs */418 return strcmp(a->pmu_name, b->pmu_name) == 0;419}420 421struct events_callback_state {422 struct sevent *aliases;423 size_t aliases_len;424 size_t index;425};426 427static int perf_pmus__print_pmu_events__callback(void *vstate,428 struct pmu_event_info *info)429{430 struct events_callback_state *state = vstate;431 struct sevent *s;432 433 if (state->index >= state->aliases_len) {434 pr_err("Unexpected event %s/%s/\n", info->pmu->name, info->name);435 return 1;436 }437 s = &state->aliases[state->index];438 s->pmu = info->pmu;439#define COPY_STR(str) s->str = info->str ? strdup(info->str) : NULL440 COPY_STR(name);441 COPY_STR(alias);442 COPY_STR(scale_unit);443 COPY_STR(desc);444 COPY_STR(long_desc);445 COPY_STR(encoding_desc);446 COPY_STR(topic);447 COPY_STR(pmu_name);448 COPY_STR(event_type_desc);449#undef COPY_STR450 s->deprecated = info->deprecated;451 state->index++;452 return 0;453}454 455void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state)456{457 struct perf_pmu *pmu;458 int printed = 0;459 int len;460 struct sevent *aliases;461 struct events_callback_state state;462 bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state);463 struct perf_pmu *(*scan_fn)(struct perf_pmu *);464 465 if (skip_duplicate_pmus)466 scan_fn = perf_pmus__scan_skip_duplicates;467 else468 scan_fn = perf_pmus__scan;469 470 pmu = NULL;471 len = 0;472 while ((pmu = scan_fn(pmu)) != NULL)473 len += perf_pmu__num_events(pmu);474 475 aliases = zalloc(sizeof(struct sevent) * len);476 if (!aliases) {477 pr_err("FATAL: not enough memory to print PMU events\n");478 return;479 }480 pmu = NULL;481 state = (struct events_callback_state) {482 .aliases = aliases,483 .aliases_len = len,484 .index = 0,485 };486 while ((pmu = scan_fn(pmu)) != NULL) {487 perf_pmu__for_each_event(pmu, skip_duplicate_pmus, &state,488 perf_pmus__print_pmu_events__callback);489 }490 qsort(aliases, len, sizeof(struct sevent), cmp_sevent);491 for (int j = 0; j < len; j++) {492 /* Skip duplicates */493 if (j < len - 1 && pmu_alias_is_duplicate(&aliases[j], &aliases[j + 1]))494 goto free;495 496 print_cb->print_event(print_state,497 aliases[j].pmu_name,498 aliases[j].topic,499 aliases[j].name,500 aliases[j].alias,501 aliases[j].scale_unit,502 aliases[j].deprecated,503 aliases[j].event_type_desc,504 aliases[j].desc,505 aliases[j].long_desc,506 aliases[j].encoding_desc);507free:508 zfree(&aliases[j].name);509 zfree(&aliases[j].alias);510 zfree(&aliases[j].scale_unit);511 zfree(&aliases[j].desc);512 zfree(&aliases[j].long_desc);513 zfree(&aliases[j].encoding_desc);514 zfree(&aliases[j].topic);515 zfree(&aliases[j].pmu_name);516 zfree(&aliases[j].event_type_desc);517 }518 if (printed && pager_in_use())519 printf("\n");520 521 zfree(&aliases);522}523 524struct build_format_string_args {525 struct strbuf short_string;526 struct strbuf long_string;527 int num_formats;528};529 530static int build_format_string(void *state, const char *name, int config,531 const unsigned long *bits)532{533 struct build_format_string_args *args = state;534 unsigned int num_bits;535 int ret1, ret2 = 0;536 537 (void)config;538 args->num_formats++;539 if (args->num_formats > 1) {540 strbuf_addch(&args->long_string, ',');541 if (args->num_formats < 4)542 strbuf_addch(&args->short_string, ',');543 }544 num_bits = bits ? bitmap_weight(bits, PERF_PMU_FORMAT_BITS) : 0;545 if (num_bits <= 1) {546 ret1 = strbuf_addf(&args->long_string, "%s", name);547 if (args->num_formats < 4)548 ret2 = strbuf_addf(&args->short_string, "%s", name);549 } else if (num_bits > 8) {550 ret1 = strbuf_addf(&args->long_string, "%s=0..0x%llx", name,551 ULLONG_MAX >> (64 - num_bits));552 if (args->num_formats < 4) {553 ret2 = strbuf_addf(&args->short_string, "%s=0..0x%llx", name,554 ULLONG_MAX >> (64 - num_bits));555 }556 } else {557 ret1 = strbuf_addf(&args->long_string, "%s=0..%llu", name,558 ULLONG_MAX >> (64 - num_bits));559 if (args->num_formats < 4) {560 ret2 = strbuf_addf(&args->short_string, "%s=0..%llu", name,561 ULLONG_MAX >> (64 - num_bits));562 }563 }564 return ret1 < 0 ? ret1 : (ret2 < 0 ? ret2 : 0);565}566 567void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state)568{569 bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state);570 struct perf_pmu *(*scan_fn)(struct perf_pmu *);571 struct perf_pmu *pmu = NULL;572 573 if (skip_duplicate_pmus)574 scan_fn = perf_pmus__scan_skip_duplicates;575 else576 scan_fn = perf_pmus__scan;577 578 while ((pmu = scan_fn(pmu)) != NULL) {579 struct build_format_string_args format_args = {580 .short_string = STRBUF_INIT,581 .long_string = STRBUF_INIT,582 .num_formats = 0,583 };584 int len = pmu_name_len_no_suffix(pmu->name);585 const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";586 587 if (!pmu->is_core)588 desc = NULL;589 590 strbuf_addf(&format_args.short_string, "%.*s/", len, pmu->name);591 strbuf_addf(&format_args.long_string, "%.*s/", len, pmu->name);592 perf_pmu__for_each_format(pmu, &format_args, build_format_string);593 594 if (format_args.num_formats > 3)595 strbuf_addf(&format_args.short_string, ",.../modifier");596 else597 strbuf_addf(&format_args.short_string, "/modifier");598 599 strbuf_addf(&format_args.long_string, "/modifier");600 print_cb->print_event(print_state,601 /*topic=*/NULL,602 /*pmu_name=*/NULL,603 format_args.short_string.buf,604 /*event_alias=*/NULL,605 /*scale_unit=*/NULL,606 /*deprecated=*/false,607 "Raw event descriptor",608 desc,609 /*long_desc=*/NULL,610 format_args.long_string.buf);611 612 strbuf_release(&format_args.short_string);613 strbuf_release(&format_args.long_string);614 }615}616 617bool perf_pmus__have_event(const char *pname, const char *name)618{619 struct perf_pmu *pmu = perf_pmus__find(pname);620 621 return pmu && perf_pmu__have_event(pmu, name);622}623 624int perf_pmus__num_core_pmus(void)625{626 static int count;627 628 if (!count) {629 struct perf_pmu *pmu = NULL;630 631 while ((pmu = perf_pmus__scan_core(pmu)) != NULL)632 count++;633 }634 return count;635}636 637static bool __perf_pmus__supports_extended_type(void)638{639 struct perf_pmu *pmu = NULL;640 641 if (perf_pmus__num_core_pmus() <= 1)642 return false;643 644 while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {645 if (!is_event_supported(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES | ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)))646 return false;647 }648 649 return true;650}651 652static bool perf_pmus__do_support_extended_type;653 654static void perf_pmus__init_supports_extended_type(void)655{656 perf_pmus__do_support_extended_type = __perf_pmus__supports_extended_type();657}658 659bool perf_pmus__supports_extended_type(void)660{661 static pthread_once_t extended_type_once = PTHREAD_ONCE_INIT;662 663 pthread_once(&extended_type_once, perf_pmus__init_supports_extended_type);664 665 return perf_pmus__do_support_extended_type;666}667 668char *perf_pmus__default_pmu_name(void)669{670 int fd;671 DIR *dir;672 struct dirent *dent;673 char *result = NULL;674 675 if (!list_empty(&core_pmus))676 return strdup(list_first_entry(&core_pmus, struct perf_pmu, list)->name);677 678 fd = perf_pmu__event_source_devices_fd();679 if (fd < 0)680 return strdup("cpu");681 682 dir = fdopendir(fd);683 if (!dir) {684 close(fd);685 return strdup("cpu");686 }687 688 while ((dent = readdir(dir))) {689 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))690 continue;691 if (is_pmu_core(dent->d_name)) {692 result = strdup(dent->d_name);693 break;694 }695 }696 697 closedir(dir);698 return result ?: strdup("cpu");699}700 701struct perf_pmu *evsel__find_pmu(const struct evsel *evsel)702{703 struct perf_pmu *pmu = evsel->pmu;704 705 if (!pmu) {706 pmu = perf_pmus__find_by_type(evsel->core.attr.type);707 ((struct evsel *)evsel)->pmu = pmu;708 }709 return pmu;710}711 712struct perf_pmu *perf_pmus__find_core_pmu(void)713{714 return perf_pmus__scan_core(NULL);715}716 717struct perf_pmu *perf_pmus__add_test_pmu(int test_sysfs_dirfd, const char *name)718{719 /*720 * Some PMU functions read from the sysfs mount point, so care is721 * needed, hence passing the eager_load flag to load things like the722 * format files.723 */724 return perf_pmu__lookup(&other_pmus, test_sysfs_dirfd, name, /*eager_load=*/true);725}726 727struct perf_pmu *perf_pmus__fake_pmu(void)728{729 static struct perf_pmu fake = {730 .name = "fake",731 .type = PERF_PMU_TYPE_FAKE,732 .format = LIST_HEAD_INIT(fake.format),733 };734 735 return &fake;736}737