1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
25efb1d54SAdrian Hunter #include <string.h>
313d60ba0SKan Liang #include <stdio.h>
413d60ba0SKan Liang #include <sys/types.h>
513d60ba0SKan Liang #include <dirent.h>
613d60ba0SKan Liang #include <fcntl.h>
744fe619bSArnaldo Carvalho de Melo #include <linux/stddef.h>
85efb1d54SAdrian Hunter #include <linux/perf_event.h>
913d60ba0SKan Liang #include <linux/zalloc.h>
1013d60ba0SKan Liang #include <api/fs/fs.h>
1113d60ba0SKan Liang #include <errno.h>
125efb1d54SAdrian Hunter
13441b62acSIan Rogers #include "../../../util/intel-pt.h"
14441b62acSIan Rogers #include "../../../util/intel-bts.h"
15441b62acSIan Rogers #include "../../../util/pmu.h"
1613d60ba0SKan Liang #include "../../../util/fncache.h"
17f0dc2082SRavi Bangoria #include "../../../util/pmus.h"
18f0dc2082SRavi Bangoria #include "env.h"
1913d60ba0SKan Liang
2013d60ba0SKan Liang struct pmu_alias {
2113d60ba0SKan Liang char *name;
2213d60ba0SKan Liang char *alias;
2313d60ba0SKan Liang struct list_head list;
2413d60ba0SKan Liang };
2513d60ba0SKan Liang
2613d60ba0SKan Liang static LIST_HEAD(pmu_alias_name_list);
2713d60ba0SKan Liang static bool cached_list;
285efb1d54SAdrian Hunter
perf_pmu__get_default_config(struct perf_pmu * pmu __maybe_unused)295efb1d54SAdrian Hunter struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
305efb1d54SAdrian Hunter {
315efb1d54SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
323c7b84d4SIan Rogers if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) {
333c7b84d4SIan Rogers pmu->auxtrace = true;
345efb1d54SAdrian Hunter return intel_pt_pmu_default_config(pmu);
353c7b84d4SIan Rogers }
363c7b84d4SIan Rogers if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) {
373c7b84d4SIan Rogers pmu->auxtrace = true;
38d0170af7SAdrian Hunter pmu->selectable = true;
393c7b84d4SIan Rogers }
405efb1d54SAdrian Hunter #endif
415efb1d54SAdrian Hunter return NULL;
425efb1d54SAdrian Hunter }
4313d60ba0SKan Liang
pmu_alias__delete(struct pmu_alias * pmu_alias)4413d60ba0SKan Liang static void pmu_alias__delete(struct pmu_alias *pmu_alias)
4513d60ba0SKan Liang {
4613d60ba0SKan Liang if (!pmu_alias)
4713d60ba0SKan Liang return;
4813d60ba0SKan Liang
4913d60ba0SKan Liang zfree(&pmu_alias->name);
5013d60ba0SKan Liang zfree(&pmu_alias->alias);
5113d60ba0SKan Liang free(pmu_alias);
5213d60ba0SKan Liang }
5313d60ba0SKan Liang
pmu_alias__new(char * name,char * alias)5413d60ba0SKan Liang static struct pmu_alias *pmu_alias__new(char *name, char *alias)
5513d60ba0SKan Liang {
5613d60ba0SKan Liang struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias));
5713d60ba0SKan Liang
5813d60ba0SKan Liang if (pmu_alias) {
5913d60ba0SKan Liang pmu_alias->name = strdup(name);
6013d60ba0SKan Liang if (!pmu_alias->name)
6113d60ba0SKan Liang goto out_delete;
6213d60ba0SKan Liang
6313d60ba0SKan Liang pmu_alias->alias = strdup(alias);
6413d60ba0SKan Liang if (!pmu_alias->alias)
6513d60ba0SKan Liang goto out_delete;
6613d60ba0SKan Liang }
6713d60ba0SKan Liang return pmu_alias;
6813d60ba0SKan Liang
6913d60ba0SKan Liang out_delete:
7013d60ba0SKan Liang pmu_alias__delete(pmu_alias);
7113d60ba0SKan Liang return NULL;
7213d60ba0SKan Liang }
7313d60ba0SKan Liang
setup_pmu_alias_list(void)7413d60ba0SKan Liang static int setup_pmu_alias_list(void)
7513d60ba0SKan Liang {
7646378665SNamhyung Kim int fd, dirfd;
7713d60ba0SKan Liang DIR *dir;
7813d60ba0SKan Liang struct dirent *dent;
7913d60ba0SKan Liang struct pmu_alias *pmu_alias;
8013d60ba0SKan Liang char buf[MAX_PMU_NAME_LEN];
8113d60ba0SKan Liang FILE *file;
8213d60ba0SKan Liang int ret = -ENOMEM;
8313d60ba0SKan Liang
8446378665SNamhyung Kim dirfd = perf_pmu__event_source_devices_fd();
8546378665SNamhyung Kim if (dirfd < 0)
8613d60ba0SKan Liang return -1;
8713d60ba0SKan Liang
8846378665SNamhyung Kim dir = fdopendir(dirfd);
8913d60ba0SKan Liang if (!dir)
9013d60ba0SKan Liang return -errno;
9113d60ba0SKan Liang
9213d60ba0SKan Liang while ((dent = readdir(dir))) {
9313d60ba0SKan Liang if (!strcmp(dent->d_name, ".") ||
9413d60ba0SKan Liang !strcmp(dent->d_name, ".."))
9513d60ba0SKan Liang continue;
9613d60ba0SKan Liang
9746378665SNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, dent->d_name, "alias", O_RDONLY);
9846378665SNamhyung Kim if (fd < 0)
9913d60ba0SKan Liang continue;
10013d60ba0SKan Liang
10146378665SNamhyung Kim file = fdopen(fd, "r");
10213d60ba0SKan Liang if (!file)
10313d60ba0SKan Liang continue;
10413d60ba0SKan Liang
10513d60ba0SKan Liang if (!fgets(buf, sizeof(buf), file)) {
10613d60ba0SKan Liang fclose(file);
10713d60ba0SKan Liang continue;
10813d60ba0SKan Liang }
10913d60ba0SKan Liang
11013d60ba0SKan Liang fclose(file);
11113d60ba0SKan Liang
11213d60ba0SKan Liang /* Remove the last '\n' */
11313d60ba0SKan Liang buf[strlen(buf) - 1] = 0;
11413d60ba0SKan Liang
11513d60ba0SKan Liang pmu_alias = pmu_alias__new(dent->d_name, buf);
11613d60ba0SKan Liang if (!pmu_alias)
11713d60ba0SKan Liang goto close_dir;
11813d60ba0SKan Liang
11913d60ba0SKan Liang list_add_tail(&pmu_alias->list, &pmu_alias_name_list);
12013d60ba0SKan Liang }
12113d60ba0SKan Liang
12213d60ba0SKan Liang ret = 0;
12313d60ba0SKan Liang
12413d60ba0SKan Liang close_dir:
12513d60ba0SKan Liang closedir(dir);
12613d60ba0SKan Liang return ret;
12713d60ba0SKan Liang }
12813d60ba0SKan Liang
__pmu_find_real_name(const char * name)129*c091ee90SIan Rogers static const char *__pmu_find_real_name(const char *name)
13013d60ba0SKan Liang {
13113d60ba0SKan Liang struct pmu_alias *pmu_alias;
13213d60ba0SKan Liang
13313d60ba0SKan Liang list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) {
13413d60ba0SKan Liang if (!strcmp(name, pmu_alias->alias))
13513d60ba0SKan Liang return pmu_alias->name;
13613d60ba0SKan Liang }
13713d60ba0SKan Liang
138*c091ee90SIan Rogers return name;
13913d60ba0SKan Liang }
14013d60ba0SKan Liang
pmu_find_real_name(const char * name)141*c091ee90SIan Rogers const char *pmu_find_real_name(const char *name)
14213d60ba0SKan Liang {
14313d60ba0SKan Liang if (cached_list)
14413d60ba0SKan Liang return __pmu_find_real_name(name);
14513d60ba0SKan Liang
14613d60ba0SKan Liang setup_pmu_alias_list();
14713d60ba0SKan Liang cached_list = true;
14813d60ba0SKan Liang
14913d60ba0SKan Liang return __pmu_find_real_name(name);
15013d60ba0SKan Liang }
15113d60ba0SKan Liang
__pmu_find_alias_name(const char * name)152*c091ee90SIan Rogers static const char *__pmu_find_alias_name(const char *name)
15313d60ba0SKan Liang {
15413d60ba0SKan Liang struct pmu_alias *pmu_alias;
15513d60ba0SKan Liang
15613d60ba0SKan Liang list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) {
15713d60ba0SKan Liang if (!strcmp(name, pmu_alias->name))
15813d60ba0SKan Liang return pmu_alias->alias;
15913d60ba0SKan Liang }
16013d60ba0SKan Liang return NULL;
16113d60ba0SKan Liang }
16213d60ba0SKan Liang
pmu_find_alias_name(const char * name)163*c091ee90SIan Rogers const char *pmu_find_alias_name(const char *name)
16413d60ba0SKan Liang {
16513d60ba0SKan Liang if (cached_list)
16613d60ba0SKan Liang return __pmu_find_alias_name(name);
16713d60ba0SKan Liang
16813d60ba0SKan Liang setup_pmu_alias_list();
16913d60ba0SKan Liang cached_list = true;
17013d60ba0SKan Liang
17113d60ba0SKan Liang return __pmu_find_alias_name(name);
17213d60ba0SKan Liang }
173f0dc2082SRavi Bangoria
perf_pmus__num_mem_pmus(void)174f0dc2082SRavi Bangoria int perf_pmus__num_mem_pmus(void)
175f0dc2082SRavi Bangoria {
176f0dc2082SRavi Bangoria /* AMD uses IBS OP pmu and not a core PMU for perf mem/c2c */
177f0dc2082SRavi Bangoria if (x86__is_amd_cpu())
178f0dc2082SRavi Bangoria return 1;
179f0dc2082SRavi Bangoria
180f0dc2082SRavi Bangoria /* Intel uses core pmus for perf mem/c2c */
181f0dc2082SRavi Bangoria return perf_pmus__num_core_pmus();
182f0dc2082SRavi Bangoria }
183