162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <string.h> 362306a36Sopenharmony_ci#include <stdio.h> 462306a36Sopenharmony_ci#include <sys/types.h> 562306a36Sopenharmony_ci#include <dirent.h> 662306a36Sopenharmony_ci#include <fcntl.h> 762306a36Sopenharmony_ci#include <linux/stddef.h> 862306a36Sopenharmony_ci#include <linux/perf_event.h> 962306a36Sopenharmony_ci#include <linux/zalloc.h> 1062306a36Sopenharmony_ci#include <api/fs/fs.h> 1162306a36Sopenharmony_ci#include <errno.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "../../../util/intel-pt.h" 1462306a36Sopenharmony_ci#include "../../../util/intel-bts.h" 1562306a36Sopenharmony_ci#include "../../../util/pmu.h" 1662306a36Sopenharmony_ci#include "../../../util/fncache.h" 1762306a36Sopenharmony_ci#include "../../../util/pmus.h" 1862306a36Sopenharmony_ci#include "env.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct pmu_alias { 2162306a36Sopenharmony_ci char *name; 2262306a36Sopenharmony_ci char *alias; 2362306a36Sopenharmony_ci struct list_head list; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic LIST_HEAD(pmu_alias_name_list); 2762306a36Sopenharmony_cistatic bool cached_list; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci#ifdef HAVE_AUXTRACE_SUPPORT 3262306a36Sopenharmony_ci if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) { 3362306a36Sopenharmony_ci pmu->auxtrace = true; 3462306a36Sopenharmony_ci return intel_pt_pmu_default_config(pmu); 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) { 3762306a36Sopenharmony_ci pmu->auxtrace = true; 3862306a36Sopenharmony_ci pmu->selectable = true; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci#endif 4162306a36Sopenharmony_ci return NULL; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void pmu_alias__delete(struct pmu_alias *pmu_alias) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci if (!pmu_alias) 4762306a36Sopenharmony_ci return; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci zfree(&pmu_alias->name); 5062306a36Sopenharmony_ci zfree(&pmu_alias->alias); 5162306a36Sopenharmony_ci free(pmu_alias); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic struct pmu_alias *pmu_alias__new(char *name, char *alias) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias)); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (pmu_alias) { 5962306a36Sopenharmony_ci pmu_alias->name = strdup(name); 6062306a36Sopenharmony_ci if (!pmu_alias->name) 6162306a36Sopenharmony_ci goto out_delete; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci pmu_alias->alias = strdup(alias); 6462306a36Sopenharmony_ci if (!pmu_alias->alias) 6562306a36Sopenharmony_ci goto out_delete; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci return pmu_alias; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciout_delete: 7062306a36Sopenharmony_ci pmu_alias__delete(pmu_alias); 7162306a36Sopenharmony_ci return NULL; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int setup_pmu_alias_list(void) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int fd, dirfd; 7762306a36Sopenharmony_ci DIR *dir; 7862306a36Sopenharmony_ci struct dirent *dent; 7962306a36Sopenharmony_ci struct pmu_alias *pmu_alias; 8062306a36Sopenharmony_ci char buf[MAX_PMU_NAME_LEN]; 8162306a36Sopenharmony_ci FILE *file; 8262306a36Sopenharmony_ci int ret = -ENOMEM; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci dirfd = perf_pmu__event_source_devices_fd(); 8562306a36Sopenharmony_ci if (dirfd < 0) 8662306a36Sopenharmony_ci return -1; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci dir = fdopendir(dirfd); 8962306a36Sopenharmony_ci if (!dir) 9062306a36Sopenharmony_ci return -errno; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci while ((dent = readdir(dir))) { 9362306a36Sopenharmony_ci if (!strcmp(dent->d_name, ".") || 9462306a36Sopenharmony_ci !strcmp(dent->d_name, "..")) 9562306a36Sopenharmony_ci continue; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci fd = perf_pmu__pathname_fd(dirfd, dent->d_name, "alias", O_RDONLY); 9862306a36Sopenharmony_ci if (fd < 0) 9962306a36Sopenharmony_ci continue; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci file = fdopen(fd, "r"); 10262306a36Sopenharmony_ci if (!file) 10362306a36Sopenharmony_ci continue; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (!fgets(buf, sizeof(buf), file)) { 10662306a36Sopenharmony_ci fclose(file); 10762306a36Sopenharmony_ci continue; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci fclose(file); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Remove the last '\n' */ 11362306a36Sopenharmony_ci buf[strlen(buf) - 1] = 0; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci pmu_alias = pmu_alias__new(dent->d_name, buf); 11662306a36Sopenharmony_ci if (!pmu_alias) 11762306a36Sopenharmony_ci goto close_dir; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci list_add_tail(&pmu_alias->list, &pmu_alias_name_list); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ret = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciclose_dir: 12562306a36Sopenharmony_ci closedir(dir); 12662306a36Sopenharmony_ci return ret; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic const char *__pmu_find_real_name(const char *name) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct pmu_alias *pmu_alias; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 13462306a36Sopenharmony_ci if (!strcmp(name, pmu_alias->alias)) 13562306a36Sopenharmony_ci return pmu_alias->name; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return name; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciconst char *pmu_find_real_name(const char *name) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci if (cached_list) 14462306a36Sopenharmony_ci return __pmu_find_real_name(name); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci setup_pmu_alias_list(); 14762306a36Sopenharmony_ci cached_list = true; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return __pmu_find_real_name(name); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic const char *__pmu_find_alias_name(const char *name) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct pmu_alias *pmu_alias; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 15762306a36Sopenharmony_ci if (!strcmp(name, pmu_alias->name)) 15862306a36Sopenharmony_ci return pmu_alias->alias; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci return NULL; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciconst char *pmu_find_alias_name(const char *name) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci if (cached_list) 16662306a36Sopenharmony_ci return __pmu_find_alias_name(name); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci setup_pmu_alias_list(); 16962306a36Sopenharmony_ci cached_list = true; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return __pmu_find_alias_name(name); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciint perf_pmus__num_mem_pmus(void) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci /* AMD uses IBS OP pmu and not a core PMU for perf mem/c2c */ 17762306a36Sopenharmony_ci if (x86__is_amd_cpu()) 17862306a36Sopenharmony_ci return 1; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Intel uses core pmus for perf mem/c2c */ 18162306a36Sopenharmony_ci return perf_pmus__num_core_pmus(); 18262306a36Sopenharmony_ci} 183