xref: /openbmc/linux/tools/perf/util/pmu.c (revision dc098b35)
1cd82a32eSJiri Olsa #include <linux/list.h>
2cd82a32eSJiri Olsa #include <sys/types.h>
3cd82a32eSJiri Olsa #include <sys/stat.h>
4cd82a32eSJiri Olsa #include <unistd.h>
5cd82a32eSJiri Olsa #include <stdio.h>
6cd82a32eSJiri Olsa #include <dirent.h>
7cd82a32eSJiri Olsa #include "sysfs.h"
8cd82a32eSJiri Olsa #include "util.h"
9cd82a32eSJiri Olsa #include "pmu.h"
10cd82a32eSJiri Olsa #include "parse-events.h"
117ae92e74SYan, Zheng #include "cpumap.h"
12cd82a32eSJiri Olsa 
13ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_alias {
14ab1bf653SArnaldo Carvalho de Melo 	char *name;
15ab1bf653SArnaldo Carvalho de Melo 	struct list_head terms;
16ab1bf653SArnaldo Carvalho de Melo 	struct list_head list;
17ab1bf653SArnaldo Carvalho de Melo };
18ab1bf653SArnaldo Carvalho de Melo 
19ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format {
20ab1bf653SArnaldo Carvalho de Melo 	char *name;
21ab1bf653SArnaldo Carvalho de Melo 	int value;
22ab1bf653SArnaldo Carvalho de Melo 	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
23ab1bf653SArnaldo Carvalho de Melo 	struct list_head list;
24ab1bf653SArnaldo Carvalho de Melo };
25ab1bf653SArnaldo Carvalho de Melo 
2650a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
2750a9667cSRobert Richter 
28cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name);
29cd82a32eSJiri Olsa extern FILE *perf_pmu_in;
30cd82a32eSJiri Olsa 
31cd82a32eSJiri Olsa static LIST_HEAD(pmus);
32cd82a32eSJiri Olsa 
33cd82a32eSJiri Olsa /*
34cd82a32eSJiri Olsa  * Parse & process all the sysfs attributes located under
35cd82a32eSJiri Olsa  * the directory specified in 'dir' parameter.
36cd82a32eSJiri Olsa  */
37cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head)
38cd82a32eSJiri Olsa {
39cd82a32eSJiri Olsa 	struct dirent *evt_ent;
40cd82a32eSJiri Olsa 	DIR *format_dir;
41cd82a32eSJiri Olsa 	int ret = 0;
42cd82a32eSJiri Olsa 
43cd82a32eSJiri Olsa 	format_dir = opendir(dir);
44cd82a32eSJiri Olsa 	if (!format_dir)
45cd82a32eSJiri Olsa 		return -EINVAL;
46cd82a32eSJiri Olsa 
47cd82a32eSJiri Olsa 	while (!ret && (evt_ent = readdir(format_dir))) {
48cd82a32eSJiri Olsa 		char path[PATH_MAX];
49cd82a32eSJiri Olsa 		char *name = evt_ent->d_name;
50cd82a32eSJiri Olsa 		FILE *file;
51cd82a32eSJiri Olsa 
52cd82a32eSJiri Olsa 		if (!strcmp(name, ".") || !strcmp(name, ".."))
53cd82a32eSJiri Olsa 			continue;
54cd82a32eSJiri Olsa 
55cd82a32eSJiri Olsa 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
56cd82a32eSJiri Olsa 
57cd82a32eSJiri Olsa 		ret = -EINVAL;
58cd82a32eSJiri Olsa 		file = fopen(path, "r");
59cd82a32eSJiri Olsa 		if (!file)
60cd82a32eSJiri Olsa 			break;
61cd82a32eSJiri Olsa 
62cd82a32eSJiri Olsa 		perf_pmu_in = file;
63cd82a32eSJiri Olsa 		ret = perf_pmu_parse(head, name);
64cd82a32eSJiri Olsa 		fclose(file);
65cd82a32eSJiri Olsa 	}
66cd82a32eSJiri Olsa 
67cd82a32eSJiri Olsa 	closedir(format_dir);
68cd82a32eSJiri Olsa 	return ret;
69cd82a32eSJiri Olsa }
70cd82a32eSJiri Olsa 
71cd82a32eSJiri Olsa /*
72cd82a32eSJiri Olsa  * Reading/parsing the default pmu format definition, which should be
73cd82a32eSJiri Olsa  * located at:
74cd82a32eSJiri Olsa  * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
75cd82a32eSJiri Olsa  */
76b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format)
77cd82a32eSJiri Olsa {
78cd82a32eSJiri Olsa 	struct stat st;
79cd82a32eSJiri Olsa 	char path[PATH_MAX];
80cd82a32eSJiri Olsa 	const char *sysfs;
81cd82a32eSJiri Olsa 
82cd82a32eSJiri Olsa 	sysfs = sysfs_find_mountpoint();
83cd82a32eSJiri Olsa 	if (!sysfs)
84cd82a32eSJiri Olsa 		return -1;
85cd82a32eSJiri Olsa 
86cd82a32eSJiri Olsa 	snprintf(path, PATH_MAX,
8750a9667cSRobert Richter 		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
88cd82a32eSJiri Olsa 
89cd82a32eSJiri Olsa 	if (stat(path, &st) < 0)
909bc8f9feSRobert Richter 		return 0;	/* no error if format does not exist */
91cd82a32eSJiri Olsa 
92cff7f956SJiri Olsa 	if (perf_pmu__format_parse(path, format))
93cd82a32eSJiri Olsa 		return -1;
94cd82a32eSJiri Olsa 
95cd82a32eSJiri Olsa 	return 0;
96cd82a32eSJiri Olsa }
97cd82a32eSJiri Olsa 
98a6146d50SZheng Yan static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
99a6146d50SZheng Yan {
1005c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_alias *alias;
101a6146d50SZheng Yan 	char buf[256];
102a6146d50SZheng Yan 	int ret;
103a6146d50SZheng Yan 
104a6146d50SZheng Yan 	ret = fread(buf, 1, sizeof(buf), file);
105a6146d50SZheng Yan 	if (ret == 0)
106a6146d50SZheng Yan 		return -EINVAL;
107a6146d50SZheng Yan 	buf[ret] = 0;
108a6146d50SZheng Yan 
109a6146d50SZheng Yan 	alias = malloc(sizeof(*alias));
110a6146d50SZheng Yan 	if (!alias)
111a6146d50SZheng Yan 		return -ENOMEM;
112a6146d50SZheng Yan 
113a6146d50SZheng Yan 	INIT_LIST_HEAD(&alias->terms);
114a6146d50SZheng Yan 	ret = parse_events_terms(&alias->terms, buf);
115a6146d50SZheng Yan 	if (ret) {
116a6146d50SZheng Yan 		free(alias);
117a6146d50SZheng Yan 		return ret;
118a6146d50SZheng Yan 	}
119a6146d50SZheng Yan 
120a6146d50SZheng Yan 	alias->name = strdup(name);
121a6146d50SZheng Yan 	list_add_tail(&alias->list, list);
122a6146d50SZheng Yan 	return 0;
123a6146d50SZheng Yan }
124a6146d50SZheng Yan 
125a6146d50SZheng Yan /*
126a6146d50SZheng Yan  * Process all the sysfs attributes located under the directory
127a6146d50SZheng Yan  * specified in 'dir' parameter.
128a6146d50SZheng Yan  */
129a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head)
130a6146d50SZheng Yan {
131a6146d50SZheng Yan 	struct dirent *evt_ent;
132a6146d50SZheng Yan 	DIR *event_dir;
133a6146d50SZheng Yan 	int ret = 0;
134a6146d50SZheng Yan 
135a6146d50SZheng Yan 	event_dir = opendir(dir);
136a6146d50SZheng Yan 	if (!event_dir)
137a6146d50SZheng Yan 		return -EINVAL;
138a6146d50SZheng Yan 
139a6146d50SZheng Yan 	while (!ret && (evt_ent = readdir(event_dir))) {
140a6146d50SZheng Yan 		char path[PATH_MAX];
141a6146d50SZheng Yan 		char *name = evt_ent->d_name;
142a6146d50SZheng Yan 		FILE *file;
143a6146d50SZheng Yan 
144a6146d50SZheng Yan 		if (!strcmp(name, ".") || !strcmp(name, ".."))
145a6146d50SZheng Yan 			continue;
146a6146d50SZheng Yan 
147a6146d50SZheng Yan 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
148a6146d50SZheng Yan 
149a6146d50SZheng Yan 		ret = -EINVAL;
150a6146d50SZheng Yan 		file = fopen(path, "r");
151a6146d50SZheng Yan 		if (!file)
152a6146d50SZheng Yan 			break;
153a6146d50SZheng Yan 		ret = perf_pmu__new_alias(head, name, file);
154a6146d50SZheng Yan 		fclose(file);
155a6146d50SZheng Yan 	}
156a6146d50SZheng Yan 
157a6146d50SZheng Yan 	closedir(event_dir);
158a6146d50SZheng Yan 	return ret;
159a6146d50SZheng Yan }
160a6146d50SZheng Yan 
161a6146d50SZheng Yan /*
162a6146d50SZheng Yan  * Reading the pmu event aliases definition, which should be located at:
163a6146d50SZheng Yan  * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
164a6146d50SZheng Yan  */
165b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head)
166a6146d50SZheng Yan {
167a6146d50SZheng Yan 	struct stat st;
168a6146d50SZheng Yan 	char path[PATH_MAX];
169a6146d50SZheng Yan 	const char *sysfs;
170a6146d50SZheng Yan 
171a6146d50SZheng Yan 	sysfs = sysfs_find_mountpoint();
172a6146d50SZheng Yan 	if (!sysfs)
173a6146d50SZheng Yan 		return -1;
174a6146d50SZheng Yan 
175a6146d50SZheng Yan 	snprintf(path, PATH_MAX,
176a6146d50SZheng Yan 		 "%s/bus/event_source/devices/%s/events", sysfs, name);
177a6146d50SZheng Yan 
178a6146d50SZheng Yan 	if (stat(path, &st) < 0)
1793fded963SJiri Olsa 		return 0;	 /* no error if 'events' does not exist */
180a6146d50SZheng Yan 
181a6146d50SZheng Yan 	if (pmu_aliases_parse(path, head))
182a6146d50SZheng Yan 		return -1;
183a6146d50SZheng Yan 
184a6146d50SZheng Yan 	return 0;
185a6146d50SZheng Yan }
186a6146d50SZheng Yan 
1875c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias,
188a6146d50SZheng Yan 			   struct list_head *terms)
189a6146d50SZheng Yan {
1906cee6cd3SArnaldo Carvalho de Melo 	struct parse_events_term *term, *clone;
191a6146d50SZheng Yan 	LIST_HEAD(list);
192a6146d50SZheng Yan 	int ret;
193a6146d50SZheng Yan 
194a6146d50SZheng Yan 	list_for_each_entry(term, &alias->terms, list) {
1956cee6cd3SArnaldo Carvalho de Melo 		ret = parse_events_term__clone(&clone, term);
196a6146d50SZheng Yan 		if (ret) {
197a6146d50SZheng Yan 			parse_events__free_terms(&list);
198a6146d50SZheng Yan 			return ret;
199a6146d50SZheng Yan 		}
200a6146d50SZheng Yan 		list_add_tail(&clone->list, &list);
201a6146d50SZheng Yan 	}
202a6146d50SZheng Yan 	list_splice(&list, terms);
203a6146d50SZheng Yan 	return 0;
204a6146d50SZheng Yan }
205a6146d50SZheng Yan 
206cd82a32eSJiri Olsa /*
207cd82a32eSJiri Olsa  * Reading/parsing the default pmu type value, which should be
208cd82a32eSJiri Olsa  * located at:
209cd82a32eSJiri Olsa  * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
210cd82a32eSJiri Olsa  */
211b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type)
212cd82a32eSJiri Olsa {
213cd82a32eSJiri Olsa 	struct stat st;
214cd82a32eSJiri Olsa 	char path[PATH_MAX];
215cd82a32eSJiri Olsa 	const char *sysfs;
216cd82a32eSJiri Olsa 	FILE *file;
217cd82a32eSJiri Olsa 	int ret = 0;
218cd82a32eSJiri Olsa 
219cd82a32eSJiri Olsa 	sysfs = sysfs_find_mountpoint();
220cd82a32eSJiri Olsa 	if (!sysfs)
221cd82a32eSJiri Olsa 		return -1;
222cd82a32eSJiri Olsa 
223cd82a32eSJiri Olsa 	snprintf(path, PATH_MAX,
22450a9667cSRobert Richter 		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
225cd82a32eSJiri Olsa 
226cd82a32eSJiri Olsa 	if (stat(path, &st) < 0)
227cd82a32eSJiri Olsa 		return -1;
228cd82a32eSJiri Olsa 
229cd82a32eSJiri Olsa 	file = fopen(path, "r");
230cd82a32eSJiri Olsa 	if (!file)
231cd82a32eSJiri Olsa 		return -EINVAL;
232cd82a32eSJiri Olsa 
233cd82a32eSJiri Olsa 	if (1 != fscanf(file, "%u", type))
234cd82a32eSJiri Olsa 		ret = -1;
235cd82a32eSJiri Olsa 
236cd82a32eSJiri Olsa 	fclose(file);
237cd82a32eSJiri Olsa 	return ret;
238cd82a32eSJiri Olsa }
239cd82a32eSJiri Olsa 
24050a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */
24150a9667cSRobert Richter static void pmu_read_sysfs(void)
24250a9667cSRobert Richter {
24350a9667cSRobert Richter 	char path[PATH_MAX];
24450a9667cSRobert Richter 	const char *sysfs;
24550a9667cSRobert Richter 	DIR *dir;
24650a9667cSRobert Richter 	struct dirent *dent;
24750a9667cSRobert Richter 
24850a9667cSRobert Richter 	sysfs = sysfs_find_mountpoint();
24950a9667cSRobert Richter 	if (!sysfs)
25050a9667cSRobert Richter 		return;
25150a9667cSRobert Richter 
25250a9667cSRobert Richter 	snprintf(path, PATH_MAX,
25350a9667cSRobert Richter 		 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
25450a9667cSRobert Richter 
25550a9667cSRobert Richter 	dir = opendir(path);
25650a9667cSRobert Richter 	if (!dir)
25750a9667cSRobert Richter 		return;
25850a9667cSRobert Richter 
25950a9667cSRobert Richter 	while ((dent = readdir(dir))) {
26050a9667cSRobert Richter 		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
26150a9667cSRobert Richter 			continue;
26250a9667cSRobert Richter 		/* add to static LIST_HEAD(pmus): */
26350a9667cSRobert Richter 		perf_pmu__find(dent->d_name);
26450a9667cSRobert Richter 	}
26550a9667cSRobert Richter 
26650a9667cSRobert Richter 	closedir(dir);
26750a9667cSRobert Richter }
26850a9667cSRobert Richter 
269b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name)
2707ae92e74SYan, Zheng {
2717ae92e74SYan, Zheng 	struct stat st;
2727ae92e74SYan, Zheng 	char path[PATH_MAX];
2737ae92e74SYan, Zheng 	const char *sysfs;
2747ae92e74SYan, Zheng 	FILE *file;
2757ae92e74SYan, Zheng 	struct cpu_map *cpus;
2767ae92e74SYan, Zheng 
2777ae92e74SYan, Zheng 	sysfs = sysfs_find_mountpoint();
2787ae92e74SYan, Zheng 	if (!sysfs)
2797ae92e74SYan, Zheng 		return NULL;
2807ae92e74SYan, Zheng 
2817ae92e74SYan, Zheng 	snprintf(path, PATH_MAX,
2827ae92e74SYan, Zheng 		 "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
2837ae92e74SYan, Zheng 
2847ae92e74SYan, Zheng 	if (stat(path, &st) < 0)
2857ae92e74SYan, Zheng 		return NULL;
2867ae92e74SYan, Zheng 
2877ae92e74SYan, Zheng 	file = fopen(path, "r");
2887ae92e74SYan, Zheng 	if (!file)
2897ae92e74SYan, Zheng 		return NULL;
2907ae92e74SYan, Zheng 
2917ae92e74SYan, Zheng 	cpus = cpu_map__read(file);
2927ae92e74SYan, Zheng 	fclose(file);
2937ae92e74SYan, Zheng 	return cpus;
2947ae92e74SYan, Zheng }
2957ae92e74SYan, Zheng 
296b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name)
297cd82a32eSJiri Olsa {
298cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
299cd82a32eSJiri Olsa 	LIST_HEAD(format);
300a6146d50SZheng Yan 	LIST_HEAD(aliases);
301cd82a32eSJiri Olsa 	__u32 type;
302cd82a32eSJiri Olsa 
303cd82a32eSJiri Olsa 	/*
304cd82a32eSJiri Olsa 	 * The pmu data we store & need consists of the pmu
305cd82a32eSJiri Olsa 	 * type value and format definitions. Load both right
306cd82a32eSJiri Olsa 	 * now.
307cd82a32eSJiri Olsa 	 */
308cd82a32eSJiri Olsa 	if (pmu_format(name, &format))
309cd82a32eSJiri Olsa 		return NULL;
310cd82a32eSJiri Olsa 
3113fded963SJiri Olsa 	if (pmu_aliases(name, &aliases))
3123fded963SJiri Olsa 		return NULL;
3133fded963SJiri Olsa 
314cd82a32eSJiri Olsa 	if (pmu_type(name, &type))
315cd82a32eSJiri Olsa 		return NULL;
316cd82a32eSJiri Olsa 
317cd82a32eSJiri Olsa 	pmu = zalloc(sizeof(*pmu));
318cd82a32eSJiri Olsa 	if (!pmu)
319cd82a32eSJiri Olsa 		return NULL;
320cd82a32eSJiri Olsa 
3217ae92e74SYan, Zheng 	pmu->cpus = pmu_cpumask(name);
3227ae92e74SYan, Zheng 
323cd82a32eSJiri Olsa 	INIT_LIST_HEAD(&pmu->format);
324a6146d50SZheng Yan 	INIT_LIST_HEAD(&pmu->aliases);
325cd82a32eSJiri Olsa 	list_splice(&format, &pmu->format);
326a6146d50SZheng Yan 	list_splice(&aliases, &pmu->aliases);
327cd82a32eSJiri Olsa 	pmu->name = strdup(name);
328cd82a32eSJiri Olsa 	pmu->type = type;
3299bc8f9feSRobert Richter 	list_add_tail(&pmu->list, &pmus);
330cd82a32eSJiri Olsa 	return pmu;
331cd82a32eSJiri Olsa }
332cd82a32eSJiri Olsa 
333b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name)
334cd82a32eSJiri Olsa {
335cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
336cd82a32eSJiri Olsa 
337cd82a32eSJiri Olsa 	list_for_each_entry(pmu, &pmus, list)
338cd82a32eSJiri Olsa 		if (!strcmp(pmu->name, name))
339cd82a32eSJiri Olsa 			return pmu;
340cd82a32eSJiri Olsa 
341cd82a32eSJiri Olsa 	return NULL;
342cd82a32eSJiri Olsa }
343cd82a32eSJiri Olsa 
34450a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
34550a9667cSRobert Richter {
34650a9667cSRobert Richter 	/*
34750a9667cSRobert Richter 	 * pmu iterator: If pmu is NULL, we start at the begin,
34850a9667cSRobert Richter 	 * otherwise return the next pmu. Returns NULL on end.
34950a9667cSRobert Richter 	 */
35050a9667cSRobert Richter 	if (!pmu) {
35150a9667cSRobert Richter 		pmu_read_sysfs();
35250a9667cSRobert Richter 		pmu = list_prepare_entry(pmu, &pmus, list);
35350a9667cSRobert Richter 	}
35450a9667cSRobert Richter 	list_for_each_entry_continue(pmu, &pmus, list)
35550a9667cSRobert Richter 		return pmu;
35650a9667cSRobert Richter 	return NULL;
35750a9667cSRobert Richter }
35850a9667cSRobert Richter 
359b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name)
360cd82a32eSJiri Olsa {
361cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
362cd82a32eSJiri Olsa 
363cd82a32eSJiri Olsa 	/*
364cd82a32eSJiri Olsa 	 * Once PMU is loaded it stays in the list,
365cd82a32eSJiri Olsa 	 * so we keep us from multiple reading/parsing
366cd82a32eSJiri Olsa 	 * the pmu format definitions.
367cd82a32eSJiri Olsa 	 */
368cd82a32eSJiri Olsa 	pmu = pmu_find(name);
369cd82a32eSJiri Olsa 	if (pmu)
370cd82a32eSJiri Olsa 		return pmu;
371cd82a32eSJiri Olsa 
372cd82a32eSJiri Olsa 	return pmu_lookup(name);
373cd82a32eSJiri Olsa }
374cd82a32eSJiri Olsa 
3755c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format *
376cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name)
377cd82a32eSJiri Olsa {
3785c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_format *format;
379cd82a32eSJiri Olsa 
380cd82a32eSJiri Olsa 	list_for_each_entry(format, formats, list)
381cd82a32eSJiri Olsa 		if (!strcmp(format->name, name))
382cd82a32eSJiri Olsa 			return format;
383cd82a32eSJiri Olsa 
384cd82a32eSJiri Olsa 	return NULL;
385cd82a32eSJiri Olsa }
386cd82a32eSJiri Olsa 
387cd82a32eSJiri Olsa /*
388cd82a32eSJiri Olsa  * Returns value based on the format definition (format parameter)
389cd82a32eSJiri Olsa  * and unformated value (value parameter).
390cd82a32eSJiri Olsa  *
391cd82a32eSJiri Olsa  * TODO maybe optimize a little ;)
392cd82a32eSJiri Olsa  */
393cd82a32eSJiri Olsa static __u64 pmu_format_value(unsigned long *format, __u64 value)
394cd82a32eSJiri Olsa {
395cd82a32eSJiri Olsa 	unsigned long fbit, vbit;
396cd82a32eSJiri Olsa 	__u64 v = 0;
397cd82a32eSJiri Olsa 
398cd82a32eSJiri Olsa 	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
399cd82a32eSJiri Olsa 
400cd82a32eSJiri Olsa 		if (!test_bit(fbit, format))
401cd82a32eSJiri Olsa 			continue;
402cd82a32eSJiri Olsa 
403cd82a32eSJiri Olsa 		if (!(value & (1llu << vbit++)))
404cd82a32eSJiri Olsa 			continue;
405cd82a32eSJiri Olsa 
406cd82a32eSJiri Olsa 		v |= (1llu << fbit);
407cd82a32eSJiri Olsa 	}
408cd82a32eSJiri Olsa 
409cd82a32eSJiri Olsa 	return v;
410cd82a32eSJiri Olsa }
411cd82a32eSJiri Olsa 
412cd82a32eSJiri Olsa /*
413cd82a32eSJiri Olsa  * Setup one of config[12] attr members based on the
414cd82a32eSJiri Olsa  * user input data - temr parameter.
415cd82a32eSJiri Olsa  */
416cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats,
417cd82a32eSJiri Olsa 			   struct perf_event_attr *attr,
4186cee6cd3SArnaldo Carvalho de Melo 			   struct parse_events_term *term)
419cd82a32eSJiri Olsa {
4205c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_format *format;
421cd82a32eSJiri Olsa 	__u64 *vp;
422cd82a32eSJiri Olsa 
423cd82a32eSJiri Olsa 	/*
424cd82a32eSJiri Olsa 	 * Support only for hardcoded and numnerial terms.
425cd82a32eSJiri Olsa 	 * Hardcoded terms should be already in, so nothing
426cd82a32eSJiri Olsa 	 * to be done for them.
427cd82a32eSJiri Olsa 	 */
428cd82a32eSJiri Olsa 	if (parse_events__is_hardcoded_term(term))
429cd82a32eSJiri Olsa 		return 0;
430cd82a32eSJiri Olsa 
43116fa7e82SJiri Olsa 	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
432cd82a32eSJiri Olsa 		return -EINVAL;
433cd82a32eSJiri Olsa 
434cd82a32eSJiri Olsa 	format = pmu_find_format(formats, term->config);
435cd82a32eSJiri Olsa 	if (!format)
436cd82a32eSJiri Olsa 		return -EINVAL;
437cd82a32eSJiri Olsa 
438cd82a32eSJiri Olsa 	switch (format->value) {
439cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG:
440cd82a32eSJiri Olsa 		vp = &attr->config;
441cd82a32eSJiri Olsa 		break;
442cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG1:
443cd82a32eSJiri Olsa 		vp = &attr->config1;
444cd82a32eSJiri Olsa 		break;
445cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG2:
446cd82a32eSJiri Olsa 		vp = &attr->config2;
447cd82a32eSJiri Olsa 		break;
448cd82a32eSJiri Olsa 	default:
449cd82a32eSJiri Olsa 		return -EINVAL;
450cd82a32eSJiri Olsa 	}
451cd82a32eSJiri Olsa 
45216fa7e82SJiri Olsa 	/*
45316fa7e82SJiri Olsa 	 * XXX If we ever decide to go with string values for
45416fa7e82SJiri Olsa 	 * non-hardcoded terms, here's the place to translate
45516fa7e82SJiri Olsa 	 * them into value.
45616fa7e82SJiri Olsa 	 */
457cd82a32eSJiri Olsa 	*vp |= pmu_format_value(format->bits, term->val.num);
458cd82a32eSJiri Olsa 	return 0;
459cd82a32eSJiri Olsa }
460cd82a32eSJiri Olsa 
461cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats,
462cff7f956SJiri Olsa 			   struct perf_event_attr *attr,
463cd82a32eSJiri Olsa 			   struct list_head *head_terms)
464cd82a32eSJiri Olsa {
4656cee6cd3SArnaldo Carvalho de Melo 	struct parse_events_term *term;
466cd82a32eSJiri Olsa 
4676b5fc39bSJiri Olsa 	list_for_each_entry(term, head_terms, list)
468cd82a32eSJiri Olsa 		if (pmu_config_term(formats, attr, term))
469cd82a32eSJiri Olsa 			return -EINVAL;
470cd82a32eSJiri Olsa 
471cd82a32eSJiri Olsa 	return 0;
472cd82a32eSJiri Olsa }
473cd82a32eSJiri Olsa 
474cd82a32eSJiri Olsa /*
475cd82a32eSJiri Olsa  * Configures event's 'attr' parameter based on the:
476cd82a32eSJiri Olsa  * 1) users input - specified in terms parameter
477cd82a32eSJiri Olsa  * 2) pmu format definitions - specified by pmu parameter
478cd82a32eSJiri Olsa  */
479cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
480cd82a32eSJiri Olsa 		     struct list_head *head_terms)
481cd82a32eSJiri Olsa {
482cd82a32eSJiri Olsa 	attr->type = pmu->type;
483cff7f956SJiri Olsa 	return perf_pmu__config_terms(&pmu->format, attr, head_terms);
484cd82a32eSJiri Olsa }
485cd82a32eSJiri Olsa 
4865c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
4876cee6cd3SArnaldo Carvalho de Melo 					     struct parse_events_term *term)
488a6146d50SZheng Yan {
4895c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_alias *alias;
490a6146d50SZheng Yan 	char *name;
491a6146d50SZheng Yan 
492a6146d50SZheng Yan 	if (parse_events__is_hardcoded_term(term))
493a6146d50SZheng Yan 		return NULL;
494a6146d50SZheng Yan 
495a6146d50SZheng Yan 	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
496a6146d50SZheng Yan 		if (term->val.num != 1)
497a6146d50SZheng Yan 			return NULL;
498a6146d50SZheng Yan 		if (pmu_find_format(&pmu->format, term->config))
499a6146d50SZheng Yan 			return NULL;
500a6146d50SZheng Yan 		name = term->config;
501a6146d50SZheng Yan 	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
502a6146d50SZheng Yan 		if (strcasecmp(term->config, "event"))
503a6146d50SZheng Yan 			return NULL;
504a6146d50SZheng Yan 		name = term->val.str;
505a6146d50SZheng Yan 	} else {
506a6146d50SZheng Yan 		return NULL;
507a6146d50SZheng Yan 	}
508a6146d50SZheng Yan 
509a6146d50SZheng Yan 	list_for_each_entry(alias, &pmu->aliases, list) {
510a6146d50SZheng Yan 		if (!strcasecmp(alias->name, name))
511a6146d50SZheng Yan 			return alias;
512a6146d50SZheng Yan 	}
513a6146d50SZheng Yan 	return NULL;
514a6146d50SZheng Yan }
515a6146d50SZheng Yan 
516a6146d50SZheng Yan /*
517a6146d50SZheng Yan  * Find alias in the terms list and replace it with the terms
518a6146d50SZheng Yan  * defined for the alias
519a6146d50SZheng Yan  */
520a6146d50SZheng Yan int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
521a6146d50SZheng Yan {
5226cee6cd3SArnaldo Carvalho de Melo 	struct parse_events_term *term, *h;
5235c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_alias *alias;
524a6146d50SZheng Yan 	int ret;
525a6146d50SZheng Yan 
526a6146d50SZheng Yan 	list_for_each_entry_safe(term, h, head_terms, list) {
527a6146d50SZheng Yan 		alias = pmu_find_alias(pmu, term);
528a6146d50SZheng Yan 		if (!alias)
529a6146d50SZheng Yan 			continue;
530a6146d50SZheng Yan 		ret = pmu_alias_terms(alias, &term->list);
531a6146d50SZheng Yan 		if (ret)
532a6146d50SZheng Yan 			return ret;
533a6146d50SZheng Yan 		list_del(&term->list);
534a6146d50SZheng Yan 		free(term);
535a6146d50SZheng Yan 	}
536a6146d50SZheng Yan 	return 0;
537a6146d50SZheng Yan }
538a6146d50SZheng Yan 
539cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name,
540cd82a32eSJiri Olsa 			 int config, unsigned long *bits)
541cd82a32eSJiri Olsa {
5425c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_format *format;
543cd82a32eSJiri Olsa 
544cd82a32eSJiri Olsa 	format = zalloc(sizeof(*format));
545cd82a32eSJiri Olsa 	if (!format)
546cd82a32eSJiri Olsa 		return -ENOMEM;
547cd82a32eSJiri Olsa 
548cd82a32eSJiri Olsa 	format->name = strdup(name);
549cd82a32eSJiri Olsa 	format->value = config;
550cd82a32eSJiri Olsa 	memcpy(format->bits, bits, sizeof(format->bits));
551cd82a32eSJiri Olsa 
552cd82a32eSJiri Olsa 	list_add_tail(&format->list, list);
553cd82a32eSJiri Olsa 	return 0;
554cd82a32eSJiri Olsa }
555cd82a32eSJiri Olsa 
556cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to)
557cd82a32eSJiri Olsa {
558cd82a32eSJiri Olsa 	long b;
559cd82a32eSJiri Olsa 
560cd82a32eSJiri Olsa 	if (!to)
561cd82a32eSJiri Olsa 		to = from;
562cd82a32eSJiri Olsa 
56315268138SSukadev Bhattiprolu 	memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
564cd82a32eSJiri Olsa 	for (b = from; b <= to; b++)
565cd82a32eSJiri Olsa 		set_bit(b, bits);
566cd82a32eSJiri Olsa }
567dc098b35SAndi Kleen 
568dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
569dc098b35SAndi Kleen 			  struct perf_pmu_alias *alias)
570dc098b35SAndi Kleen {
571dc098b35SAndi Kleen 	snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
572dc098b35SAndi Kleen 	return buf;
573dc098b35SAndi Kleen }
574dc098b35SAndi Kleen 
575dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
576dc098b35SAndi Kleen 			     struct perf_pmu_alias *alias)
577dc098b35SAndi Kleen {
578dc098b35SAndi Kleen 	snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
579dc098b35SAndi Kleen 	return buf;
580dc098b35SAndi Kleen }
581dc098b35SAndi Kleen 
582dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b)
583dc098b35SAndi Kleen {
584dc098b35SAndi Kleen 	const char * const *as = a;
585dc098b35SAndi Kleen 	const char * const *bs = b;
586dc098b35SAndi Kleen 	return strcmp(*as, *bs);
587dc098b35SAndi Kleen }
588dc098b35SAndi Kleen 
589dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only)
590dc098b35SAndi Kleen {
591dc098b35SAndi Kleen 	struct perf_pmu *pmu;
592dc098b35SAndi Kleen 	struct perf_pmu_alias *alias;
593dc098b35SAndi Kleen 	char buf[1024];
594dc098b35SAndi Kleen 	int printed = 0;
595dc098b35SAndi Kleen 	int len, j;
596dc098b35SAndi Kleen 	char **aliases;
597dc098b35SAndi Kleen 
598dc098b35SAndi Kleen 	pmu = NULL;
599dc098b35SAndi Kleen 	len = 0;
600dc098b35SAndi Kleen 	while ((pmu = perf_pmu__scan(pmu)) != NULL)
601dc098b35SAndi Kleen 		list_for_each_entry(alias, &pmu->aliases, list)
602dc098b35SAndi Kleen 			len++;
603dc098b35SAndi Kleen 	aliases = malloc(sizeof(char *) * len);
604dc098b35SAndi Kleen 	if (!aliases)
605dc098b35SAndi Kleen 		return;
606dc098b35SAndi Kleen 	pmu = NULL;
607dc098b35SAndi Kleen 	j = 0;
608dc098b35SAndi Kleen 	while ((pmu = perf_pmu__scan(pmu)) != NULL)
609dc098b35SAndi Kleen 		list_for_each_entry(alias, &pmu->aliases, list) {
610dc098b35SAndi Kleen 			char *name = format_alias(buf, sizeof(buf), pmu, alias);
611dc098b35SAndi Kleen 			bool is_cpu = !strcmp(pmu->name, "cpu");
612dc098b35SAndi Kleen 
613dc098b35SAndi Kleen 			if (event_glob != NULL &&
614dc098b35SAndi Kleen 			    !(strglobmatch(name, event_glob) ||
615dc098b35SAndi Kleen 			      (!is_cpu && strglobmatch(alias->name,
616dc098b35SAndi Kleen 						       event_glob))))
617dc098b35SAndi Kleen 				continue;
618dc098b35SAndi Kleen 			aliases[j] = name;
619dc098b35SAndi Kleen 			if (is_cpu && !name_only)
620dc098b35SAndi Kleen 				aliases[j] = format_alias_or(buf, sizeof(buf),
621dc098b35SAndi Kleen 							      pmu, alias);
622dc098b35SAndi Kleen 			aliases[j] = strdup(aliases[j]);
623dc098b35SAndi Kleen 			j++;
624dc098b35SAndi Kleen 		}
625dc098b35SAndi Kleen 	len = j;
626dc098b35SAndi Kleen 	qsort(aliases, len, sizeof(char *), cmp_string);
627dc098b35SAndi Kleen 	for (j = 0; j < len; j++) {
628dc098b35SAndi Kleen 		if (name_only) {
629dc098b35SAndi Kleen 			printf("%s ", aliases[j]);
630dc098b35SAndi Kleen 			continue;
631dc098b35SAndi Kleen 		}
632dc098b35SAndi Kleen 		printf("  %-50s [Kernel PMU event]\n", aliases[j]);
633dc098b35SAndi Kleen 		free(aliases[j]);
634dc098b35SAndi Kleen 		printed++;
635dc098b35SAndi Kleen 	}
636dc098b35SAndi Kleen 	if (printed)
637dc098b35SAndi Kleen 		printf("\n");
638dc098b35SAndi Kleen 	free(aliases);
639dc098b35SAndi Kleen }
640