xref: /openbmc/linux/tools/perf/arch/x86/util/pmu.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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