xref: /openbmc/linux/tools/perf/util/pmu.c (revision 88aca8d9)
1cd82a32eSJiri Olsa #include <linux/list.h>
2cd82a32eSJiri Olsa #include <sys/types.h>
3cd82a32eSJiri Olsa #include <unistd.h>
4cd82a32eSJiri Olsa #include <stdio.h>
5cd82a32eSJiri Olsa #include <dirent.h>
64299a549SJiri Olsa #include "fs.h"
7410136f5SStephane Eranian #include <locale.h>
8cd82a32eSJiri Olsa #include "util.h"
9cd82a32eSJiri Olsa #include "pmu.h"
10cd82a32eSJiri Olsa #include "parse-events.h"
117ae92e74SYan, Zheng #include "cpumap.h"
12cd82a32eSJiri Olsa 
13410136f5SStephane Eranian #define UNIT_MAX_LEN	31 /* max length for event unit name */
14410136f5SStephane Eranian 
15ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_alias {
16ab1bf653SArnaldo Carvalho de Melo 	char *name;
17ab1bf653SArnaldo Carvalho de Melo 	struct list_head terms;
18ab1bf653SArnaldo Carvalho de Melo 	struct list_head list;
19410136f5SStephane Eranian 	char unit[UNIT_MAX_LEN+1];
20410136f5SStephane Eranian 	double scale;
21ab1bf653SArnaldo Carvalho de Melo };
22ab1bf653SArnaldo Carvalho de Melo 
23ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format {
24ab1bf653SArnaldo Carvalho de Melo 	char *name;
25ab1bf653SArnaldo Carvalho de Melo 	int value;
26ab1bf653SArnaldo Carvalho de Melo 	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
27ab1bf653SArnaldo Carvalho de Melo 	struct list_head list;
28ab1bf653SArnaldo Carvalho de Melo };
29ab1bf653SArnaldo Carvalho de Melo 
3050a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
3150a9667cSRobert Richter 
32cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name);
33cd82a32eSJiri Olsa extern FILE *perf_pmu_in;
34cd82a32eSJiri Olsa 
35cd82a32eSJiri Olsa static LIST_HEAD(pmus);
36cd82a32eSJiri Olsa 
37cd82a32eSJiri Olsa /*
38cd82a32eSJiri Olsa  * Parse & process all the sysfs attributes located under
39cd82a32eSJiri Olsa  * the directory specified in 'dir' parameter.
40cd82a32eSJiri Olsa  */
41cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head)
42cd82a32eSJiri Olsa {
43cd82a32eSJiri Olsa 	struct dirent *evt_ent;
44cd82a32eSJiri Olsa 	DIR *format_dir;
45cd82a32eSJiri Olsa 	int ret = 0;
46cd82a32eSJiri Olsa 
47cd82a32eSJiri Olsa 	format_dir = opendir(dir);
48cd82a32eSJiri Olsa 	if (!format_dir)
49cd82a32eSJiri Olsa 		return -EINVAL;
50cd82a32eSJiri Olsa 
51cd82a32eSJiri Olsa 	while (!ret && (evt_ent = readdir(format_dir))) {
52cd82a32eSJiri Olsa 		char path[PATH_MAX];
53cd82a32eSJiri Olsa 		char *name = evt_ent->d_name;
54cd82a32eSJiri Olsa 		FILE *file;
55cd82a32eSJiri Olsa 
56cd82a32eSJiri Olsa 		if (!strcmp(name, ".") || !strcmp(name, ".."))
57cd82a32eSJiri Olsa 			continue;
58cd82a32eSJiri Olsa 
59cd82a32eSJiri Olsa 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
60cd82a32eSJiri Olsa 
61cd82a32eSJiri Olsa 		ret = -EINVAL;
62cd82a32eSJiri Olsa 		file = fopen(path, "r");
63cd82a32eSJiri Olsa 		if (!file)
64cd82a32eSJiri Olsa 			break;
65cd82a32eSJiri Olsa 
66cd82a32eSJiri Olsa 		perf_pmu_in = file;
67cd82a32eSJiri Olsa 		ret = perf_pmu_parse(head, name);
68cd82a32eSJiri Olsa 		fclose(file);
69cd82a32eSJiri Olsa 	}
70cd82a32eSJiri Olsa 
71cd82a32eSJiri Olsa 	closedir(format_dir);
72cd82a32eSJiri Olsa 	return ret;
73cd82a32eSJiri Olsa }
74cd82a32eSJiri Olsa 
75cd82a32eSJiri Olsa /*
76cd82a32eSJiri Olsa  * Reading/parsing the default pmu format definition, which should be
77cd82a32eSJiri Olsa  * located at:
78cd82a32eSJiri Olsa  * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
79cd82a32eSJiri Olsa  */
80b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format)
81cd82a32eSJiri Olsa {
82cd82a32eSJiri Olsa 	struct stat st;
83cd82a32eSJiri Olsa 	char path[PATH_MAX];
84cf38fadaSArnaldo Carvalho de Melo 	const char *sysfs = sysfs__mountpoint();
85cd82a32eSJiri Olsa 
86cd82a32eSJiri Olsa 	if (!sysfs)
87cd82a32eSJiri Olsa 		return -1;
88cd82a32eSJiri Olsa 
89cd82a32eSJiri Olsa 	snprintf(path, PATH_MAX,
9050a9667cSRobert Richter 		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
91cd82a32eSJiri Olsa 
92cd82a32eSJiri Olsa 	if (stat(path, &st) < 0)
939bc8f9feSRobert Richter 		return 0;	/* no error if format does not exist */
94cd82a32eSJiri Olsa 
95cff7f956SJiri Olsa 	if (perf_pmu__format_parse(path, format))
96cd82a32eSJiri Olsa 		return -1;
97cd82a32eSJiri Olsa 
98cd82a32eSJiri Olsa 	return 0;
99cd82a32eSJiri Olsa }
100cd82a32eSJiri Olsa 
101410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
102410136f5SStephane Eranian {
103410136f5SStephane Eranian 	struct stat st;
104410136f5SStephane Eranian 	ssize_t sret;
105410136f5SStephane Eranian 	char scale[128];
106410136f5SStephane Eranian 	int fd, ret = -1;
107410136f5SStephane Eranian 	char path[PATH_MAX];
108410136f5SStephane Eranian 	char *lc;
109410136f5SStephane Eranian 
110410136f5SStephane Eranian 	snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
111410136f5SStephane Eranian 
112410136f5SStephane Eranian 	fd = open(path, O_RDONLY);
113410136f5SStephane Eranian 	if (fd == -1)
114410136f5SStephane Eranian 		return -1;
115410136f5SStephane Eranian 
116410136f5SStephane Eranian 	if (fstat(fd, &st) < 0)
117410136f5SStephane Eranian 		goto error;
118410136f5SStephane Eranian 
119410136f5SStephane Eranian 	sret = read(fd, scale, sizeof(scale)-1);
120410136f5SStephane Eranian 	if (sret < 0)
121410136f5SStephane Eranian 		goto error;
122410136f5SStephane Eranian 
123410136f5SStephane Eranian 	scale[sret] = '\0';
124410136f5SStephane Eranian 	/*
125410136f5SStephane Eranian 	 * save current locale
126410136f5SStephane Eranian 	 */
127410136f5SStephane Eranian 	lc = setlocale(LC_NUMERIC, NULL);
128410136f5SStephane Eranian 
129410136f5SStephane Eranian 	/*
130410136f5SStephane Eranian 	 * force to C locale to ensure kernel
131410136f5SStephane Eranian 	 * scale string is converted correctly.
132410136f5SStephane Eranian 	 * kernel uses default C locale.
133410136f5SStephane Eranian 	 */
134410136f5SStephane Eranian 	setlocale(LC_NUMERIC, "C");
135410136f5SStephane Eranian 
136410136f5SStephane Eranian 	alias->scale = strtod(scale, NULL);
137410136f5SStephane Eranian 
138410136f5SStephane Eranian 	/* restore locale */
139410136f5SStephane Eranian 	setlocale(LC_NUMERIC, lc);
140410136f5SStephane Eranian 
141410136f5SStephane Eranian 	ret = 0;
142410136f5SStephane Eranian error:
143410136f5SStephane Eranian 	close(fd);
144410136f5SStephane Eranian 	return ret;
145410136f5SStephane Eranian }
146410136f5SStephane Eranian 
147410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
148410136f5SStephane Eranian {
149410136f5SStephane Eranian 	char path[PATH_MAX];
150410136f5SStephane Eranian 	ssize_t sret;
151410136f5SStephane Eranian 	int fd;
152410136f5SStephane Eranian 
153410136f5SStephane Eranian 	snprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
154410136f5SStephane Eranian 
155410136f5SStephane Eranian 	fd = open(path, O_RDONLY);
156410136f5SStephane Eranian 	if (fd == -1)
157410136f5SStephane Eranian 		return -1;
158410136f5SStephane Eranian 
159410136f5SStephane Eranian 		sret = read(fd, alias->unit, UNIT_MAX_LEN);
160410136f5SStephane Eranian 	if (sret < 0)
161410136f5SStephane Eranian 		goto error;
162410136f5SStephane Eranian 
163410136f5SStephane Eranian 	close(fd);
164410136f5SStephane Eranian 
165410136f5SStephane Eranian 	alias->unit[sret] = '\0';
166410136f5SStephane Eranian 
167410136f5SStephane Eranian 	return 0;
168410136f5SStephane Eranian error:
169410136f5SStephane Eranian 	close(fd);
170410136f5SStephane Eranian 	alias->unit[0] = '\0';
171410136f5SStephane Eranian 	return -1;
172410136f5SStephane Eranian }
173410136f5SStephane Eranian 
174410136f5SStephane Eranian static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
175a6146d50SZheng Yan {
1765c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_alias *alias;
177a6146d50SZheng Yan 	char buf[256];
178a6146d50SZheng Yan 	int ret;
179a6146d50SZheng Yan 
180a6146d50SZheng Yan 	ret = fread(buf, 1, sizeof(buf), file);
181a6146d50SZheng Yan 	if (ret == 0)
182a6146d50SZheng Yan 		return -EINVAL;
183a6146d50SZheng Yan 	buf[ret] = 0;
184a6146d50SZheng Yan 
185a6146d50SZheng Yan 	alias = malloc(sizeof(*alias));
186a6146d50SZheng Yan 	if (!alias)
187a6146d50SZheng Yan 		return -ENOMEM;
188a6146d50SZheng Yan 
189a6146d50SZheng Yan 	INIT_LIST_HEAD(&alias->terms);
190410136f5SStephane Eranian 	alias->scale = 1.0;
191410136f5SStephane Eranian 	alias->unit[0] = '\0';
192410136f5SStephane Eranian 
193a6146d50SZheng Yan 	ret = parse_events_terms(&alias->terms, buf);
194a6146d50SZheng Yan 	if (ret) {
195a6146d50SZheng Yan 		free(alias);
196a6146d50SZheng Yan 		return ret;
197a6146d50SZheng Yan 	}
198a6146d50SZheng Yan 
199a6146d50SZheng Yan 	alias->name = strdup(name);
200410136f5SStephane Eranian 	/*
201410136f5SStephane Eranian 	 * load unit name and scale if available
202410136f5SStephane Eranian 	 */
203410136f5SStephane Eranian 	perf_pmu__parse_unit(alias, dir, name);
204410136f5SStephane Eranian 	perf_pmu__parse_scale(alias, dir, name);
205410136f5SStephane Eranian 
206a6146d50SZheng Yan 	list_add_tail(&alias->list, list);
207410136f5SStephane Eranian 
208a6146d50SZheng Yan 	return 0;
209a6146d50SZheng Yan }
210a6146d50SZheng Yan 
211a6146d50SZheng Yan /*
212a6146d50SZheng Yan  * Process all the sysfs attributes located under the directory
213a6146d50SZheng Yan  * specified in 'dir' parameter.
214a6146d50SZheng Yan  */
215a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head)
216a6146d50SZheng Yan {
217a6146d50SZheng Yan 	struct dirent *evt_ent;
218a6146d50SZheng Yan 	DIR *event_dir;
219410136f5SStephane Eranian 	size_t len;
220a6146d50SZheng Yan 	int ret = 0;
221a6146d50SZheng Yan 
222a6146d50SZheng Yan 	event_dir = opendir(dir);
223a6146d50SZheng Yan 	if (!event_dir)
224a6146d50SZheng Yan 		return -EINVAL;
225a6146d50SZheng Yan 
226a6146d50SZheng Yan 	while (!ret && (evt_ent = readdir(event_dir))) {
227a6146d50SZheng Yan 		char path[PATH_MAX];
228a6146d50SZheng Yan 		char *name = evt_ent->d_name;
229a6146d50SZheng Yan 		FILE *file;
230a6146d50SZheng Yan 
231a6146d50SZheng Yan 		if (!strcmp(name, ".") || !strcmp(name, ".."))
232a6146d50SZheng Yan 			continue;
233a6146d50SZheng Yan 
234410136f5SStephane Eranian 		/*
235410136f5SStephane Eranian 		 * skip .unit and .scale info files
236410136f5SStephane Eranian 		 * parsed in perf_pmu__new_alias()
237410136f5SStephane Eranian 		 */
238410136f5SStephane Eranian 		len = strlen(name);
239410136f5SStephane Eranian 		if (len > 5 && !strcmp(name + len - 5, ".unit"))
240410136f5SStephane Eranian 			continue;
241410136f5SStephane Eranian 		if (len > 6 && !strcmp(name + len - 6, ".scale"))
242410136f5SStephane Eranian 			continue;
243410136f5SStephane Eranian 
244a6146d50SZheng Yan 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
245a6146d50SZheng Yan 
246a6146d50SZheng Yan 		ret = -EINVAL;
247a6146d50SZheng Yan 		file = fopen(path, "r");
248a6146d50SZheng Yan 		if (!file)
249a6146d50SZheng Yan 			break;
250410136f5SStephane Eranian 
251410136f5SStephane Eranian 		ret = perf_pmu__new_alias(head, dir, name, file);
252a6146d50SZheng Yan 		fclose(file);
253a6146d50SZheng Yan 	}
254a6146d50SZheng Yan 
255a6146d50SZheng Yan 	closedir(event_dir);
256a6146d50SZheng Yan 	return ret;
257a6146d50SZheng Yan }
258a6146d50SZheng Yan 
259a6146d50SZheng Yan /*
260a6146d50SZheng Yan  * Reading the pmu event aliases definition, which should be located at:
261a6146d50SZheng Yan  * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
262a6146d50SZheng Yan  */
263b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head)
264a6146d50SZheng Yan {
265a6146d50SZheng Yan 	struct stat st;
266a6146d50SZheng Yan 	char path[PATH_MAX];
267cf38fadaSArnaldo Carvalho de Melo 	const char *sysfs = sysfs__mountpoint();
268a6146d50SZheng Yan 
269a6146d50SZheng Yan 	if (!sysfs)
270a6146d50SZheng Yan 		return -1;
271a6146d50SZheng Yan 
272a6146d50SZheng Yan 	snprintf(path, PATH_MAX,
273a6146d50SZheng Yan 		 "%s/bus/event_source/devices/%s/events", sysfs, name);
274a6146d50SZheng Yan 
275a6146d50SZheng Yan 	if (stat(path, &st) < 0)
2763fded963SJiri Olsa 		return 0;	 /* no error if 'events' does not exist */
277a6146d50SZheng Yan 
278a6146d50SZheng Yan 	if (pmu_aliases_parse(path, head))
279a6146d50SZheng Yan 		return -1;
280a6146d50SZheng Yan 
281a6146d50SZheng Yan 	return 0;
282a6146d50SZheng Yan }
283a6146d50SZheng Yan 
2845c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias,
285a6146d50SZheng Yan 			   struct list_head *terms)
286a6146d50SZheng Yan {
2876cee6cd3SArnaldo Carvalho de Melo 	struct parse_events_term *term, *clone;
288a6146d50SZheng Yan 	LIST_HEAD(list);
289a6146d50SZheng Yan 	int ret;
290a6146d50SZheng Yan 
291a6146d50SZheng Yan 	list_for_each_entry(term, &alias->terms, list) {
2926cee6cd3SArnaldo Carvalho de Melo 		ret = parse_events_term__clone(&clone, term);
293a6146d50SZheng Yan 		if (ret) {
294a6146d50SZheng Yan 			parse_events__free_terms(&list);
295a6146d50SZheng Yan 			return ret;
296a6146d50SZheng Yan 		}
297a6146d50SZheng Yan 		list_add_tail(&clone->list, &list);
298a6146d50SZheng Yan 	}
299a6146d50SZheng Yan 	list_splice(&list, terms);
300a6146d50SZheng Yan 	return 0;
301a6146d50SZheng Yan }
302a6146d50SZheng Yan 
303cd82a32eSJiri Olsa /*
304cd82a32eSJiri Olsa  * Reading/parsing the default pmu type value, which should be
305cd82a32eSJiri Olsa  * located at:
306cd82a32eSJiri Olsa  * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
307cd82a32eSJiri Olsa  */
308b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type)
309cd82a32eSJiri Olsa {
310cd82a32eSJiri Olsa 	struct stat st;
311cd82a32eSJiri Olsa 	char path[PATH_MAX];
312cd82a32eSJiri Olsa 	FILE *file;
313cd82a32eSJiri Olsa 	int ret = 0;
314cf38fadaSArnaldo Carvalho de Melo 	const char *sysfs = sysfs__mountpoint();
315cd82a32eSJiri Olsa 
316cd82a32eSJiri Olsa 	if (!sysfs)
317cd82a32eSJiri Olsa 		return -1;
318cd82a32eSJiri Olsa 
319cd82a32eSJiri Olsa 	snprintf(path, PATH_MAX,
32050a9667cSRobert Richter 		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
321cd82a32eSJiri Olsa 
322cd82a32eSJiri Olsa 	if (stat(path, &st) < 0)
323cd82a32eSJiri Olsa 		return -1;
324cd82a32eSJiri Olsa 
325cd82a32eSJiri Olsa 	file = fopen(path, "r");
326cd82a32eSJiri Olsa 	if (!file)
327cd82a32eSJiri Olsa 		return -EINVAL;
328cd82a32eSJiri Olsa 
329cd82a32eSJiri Olsa 	if (1 != fscanf(file, "%u", type))
330cd82a32eSJiri Olsa 		ret = -1;
331cd82a32eSJiri Olsa 
332cd82a32eSJiri Olsa 	fclose(file);
333cd82a32eSJiri Olsa 	return ret;
334cd82a32eSJiri Olsa }
335cd82a32eSJiri Olsa 
33650a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */
33750a9667cSRobert Richter static void pmu_read_sysfs(void)
33850a9667cSRobert Richter {
33950a9667cSRobert Richter 	char path[PATH_MAX];
34050a9667cSRobert Richter 	DIR *dir;
34150a9667cSRobert Richter 	struct dirent *dent;
342cf38fadaSArnaldo Carvalho de Melo 	const char *sysfs = sysfs__mountpoint();
34350a9667cSRobert Richter 
34450a9667cSRobert Richter 	if (!sysfs)
34550a9667cSRobert Richter 		return;
34650a9667cSRobert Richter 
34750a9667cSRobert Richter 	snprintf(path, PATH_MAX,
34850a9667cSRobert Richter 		 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
34950a9667cSRobert Richter 
35050a9667cSRobert Richter 	dir = opendir(path);
35150a9667cSRobert Richter 	if (!dir)
35250a9667cSRobert Richter 		return;
35350a9667cSRobert Richter 
35450a9667cSRobert Richter 	while ((dent = readdir(dir))) {
35550a9667cSRobert Richter 		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
35650a9667cSRobert Richter 			continue;
35750a9667cSRobert Richter 		/* add to static LIST_HEAD(pmus): */
35850a9667cSRobert Richter 		perf_pmu__find(dent->d_name);
35950a9667cSRobert Richter 	}
36050a9667cSRobert Richter 
36150a9667cSRobert Richter 	closedir(dir);
36250a9667cSRobert Richter }
36350a9667cSRobert Richter 
364b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name)
3657ae92e74SYan, Zheng {
3667ae92e74SYan, Zheng 	struct stat st;
3677ae92e74SYan, Zheng 	char path[PATH_MAX];
3687ae92e74SYan, Zheng 	FILE *file;
3697ae92e74SYan, Zheng 	struct cpu_map *cpus;
370cf38fadaSArnaldo Carvalho de Melo 	const char *sysfs = sysfs__mountpoint();
3717ae92e74SYan, Zheng 
3727ae92e74SYan, Zheng 	if (!sysfs)
3737ae92e74SYan, Zheng 		return NULL;
3747ae92e74SYan, Zheng 
3757ae92e74SYan, Zheng 	snprintf(path, PATH_MAX,
3767ae92e74SYan, Zheng 		 "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
3777ae92e74SYan, Zheng 
3787ae92e74SYan, Zheng 	if (stat(path, &st) < 0)
3797ae92e74SYan, Zheng 		return NULL;
3807ae92e74SYan, Zheng 
3817ae92e74SYan, Zheng 	file = fopen(path, "r");
3827ae92e74SYan, Zheng 	if (!file)
3837ae92e74SYan, Zheng 		return NULL;
3847ae92e74SYan, Zheng 
3857ae92e74SYan, Zheng 	cpus = cpu_map__read(file);
3867ae92e74SYan, Zheng 	fclose(file);
3877ae92e74SYan, Zheng 	return cpus;
3887ae92e74SYan, Zheng }
3897ae92e74SYan, Zheng 
390b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name)
391cd82a32eSJiri Olsa {
392cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
393cd82a32eSJiri Olsa 	LIST_HEAD(format);
394a6146d50SZheng Yan 	LIST_HEAD(aliases);
395cd82a32eSJiri Olsa 	__u32 type;
396cd82a32eSJiri Olsa 
397cd82a32eSJiri Olsa 	/*
398cd82a32eSJiri Olsa 	 * The pmu data we store & need consists of the pmu
399cd82a32eSJiri Olsa 	 * type value and format definitions. Load both right
400cd82a32eSJiri Olsa 	 * now.
401cd82a32eSJiri Olsa 	 */
402cd82a32eSJiri Olsa 	if (pmu_format(name, &format))
403cd82a32eSJiri Olsa 		return NULL;
404cd82a32eSJiri Olsa 
4053fded963SJiri Olsa 	if (pmu_aliases(name, &aliases))
4063fded963SJiri Olsa 		return NULL;
4073fded963SJiri Olsa 
408cd82a32eSJiri Olsa 	if (pmu_type(name, &type))
409cd82a32eSJiri Olsa 		return NULL;
410cd82a32eSJiri Olsa 
411cd82a32eSJiri Olsa 	pmu = zalloc(sizeof(*pmu));
412cd82a32eSJiri Olsa 	if (!pmu)
413cd82a32eSJiri Olsa 		return NULL;
414cd82a32eSJiri Olsa 
4157ae92e74SYan, Zheng 	pmu->cpus = pmu_cpumask(name);
4167ae92e74SYan, Zheng 
417cd82a32eSJiri Olsa 	INIT_LIST_HEAD(&pmu->format);
418a6146d50SZheng Yan 	INIT_LIST_HEAD(&pmu->aliases);
419cd82a32eSJiri Olsa 	list_splice(&format, &pmu->format);
420a6146d50SZheng Yan 	list_splice(&aliases, &pmu->aliases);
421cd82a32eSJiri Olsa 	pmu->name = strdup(name);
422cd82a32eSJiri Olsa 	pmu->type = type;
4239bc8f9feSRobert Richter 	list_add_tail(&pmu->list, &pmus);
424cd82a32eSJiri Olsa 	return pmu;
425cd82a32eSJiri Olsa }
426cd82a32eSJiri Olsa 
427b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name)
428cd82a32eSJiri Olsa {
429cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
430cd82a32eSJiri Olsa 
431cd82a32eSJiri Olsa 	list_for_each_entry(pmu, &pmus, list)
432cd82a32eSJiri Olsa 		if (!strcmp(pmu->name, name))
433cd82a32eSJiri Olsa 			return pmu;
434cd82a32eSJiri Olsa 
435cd82a32eSJiri Olsa 	return NULL;
436cd82a32eSJiri Olsa }
437cd82a32eSJiri Olsa 
43850a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
43950a9667cSRobert Richter {
44050a9667cSRobert Richter 	/*
44150a9667cSRobert Richter 	 * pmu iterator: If pmu is NULL, we start at the begin,
44250a9667cSRobert Richter 	 * otherwise return the next pmu. Returns NULL on end.
44350a9667cSRobert Richter 	 */
44450a9667cSRobert Richter 	if (!pmu) {
44550a9667cSRobert Richter 		pmu_read_sysfs();
44650a9667cSRobert Richter 		pmu = list_prepare_entry(pmu, &pmus, list);
44750a9667cSRobert Richter 	}
44850a9667cSRobert Richter 	list_for_each_entry_continue(pmu, &pmus, list)
44950a9667cSRobert Richter 		return pmu;
45050a9667cSRobert Richter 	return NULL;
45150a9667cSRobert Richter }
45250a9667cSRobert Richter 
453b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name)
454cd82a32eSJiri Olsa {
455cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
456cd82a32eSJiri Olsa 
457cd82a32eSJiri Olsa 	/*
458cd82a32eSJiri Olsa 	 * Once PMU is loaded it stays in the list,
459cd82a32eSJiri Olsa 	 * so we keep us from multiple reading/parsing
460cd82a32eSJiri Olsa 	 * the pmu format definitions.
461cd82a32eSJiri Olsa 	 */
462cd82a32eSJiri Olsa 	pmu = pmu_find(name);
463cd82a32eSJiri Olsa 	if (pmu)
464cd82a32eSJiri Olsa 		return pmu;
465cd82a32eSJiri Olsa 
466cd82a32eSJiri Olsa 	return pmu_lookup(name);
467cd82a32eSJiri Olsa }
468cd82a32eSJiri Olsa 
4695c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format *
470cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name)
471cd82a32eSJiri Olsa {
4725c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_format *format;
473cd82a32eSJiri Olsa 
474cd82a32eSJiri Olsa 	list_for_each_entry(format, formats, list)
475cd82a32eSJiri Olsa 		if (!strcmp(format->name, name))
476cd82a32eSJiri Olsa 			return format;
477cd82a32eSJiri Olsa 
478cd82a32eSJiri Olsa 	return NULL;
479cd82a32eSJiri Olsa }
480cd82a32eSJiri Olsa 
481cd82a32eSJiri Olsa /*
482cd82a32eSJiri Olsa  * Returns value based on the format definition (format parameter)
483cd82a32eSJiri Olsa  * and unformated value (value parameter).
484cd82a32eSJiri Olsa  *
485cd82a32eSJiri Olsa  * TODO maybe optimize a little ;)
486cd82a32eSJiri Olsa  */
487cd82a32eSJiri Olsa static __u64 pmu_format_value(unsigned long *format, __u64 value)
488cd82a32eSJiri Olsa {
489cd82a32eSJiri Olsa 	unsigned long fbit, vbit;
490cd82a32eSJiri Olsa 	__u64 v = 0;
491cd82a32eSJiri Olsa 
492cd82a32eSJiri Olsa 	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
493cd82a32eSJiri Olsa 
494cd82a32eSJiri Olsa 		if (!test_bit(fbit, format))
495cd82a32eSJiri Olsa 			continue;
496cd82a32eSJiri Olsa 
497cd82a32eSJiri Olsa 		if (!(value & (1llu << vbit++)))
498cd82a32eSJiri Olsa 			continue;
499cd82a32eSJiri Olsa 
500cd82a32eSJiri Olsa 		v |= (1llu << fbit);
501cd82a32eSJiri Olsa 	}
502cd82a32eSJiri Olsa 
503cd82a32eSJiri Olsa 	return v;
504cd82a32eSJiri Olsa }
505cd82a32eSJiri Olsa 
506cd82a32eSJiri Olsa /*
507cd82a32eSJiri Olsa  * Setup one of config[12] attr members based on the
50888aca8d9SCody P Schafer  * user input data - term parameter.
509cd82a32eSJiri Olsa  */
510cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats,
511cd82a32eSJiri Olsa 			   struct perf_event_attr *attr,
5126cee6cd3SArnaldo Carvalho de Melo 			   struct parse_events_term *term)
513cd82a32eSJiri Olsa {
5145c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_format *format;
515cd82a32eSJiri Olsa 	__u64 *vp;
516cd82a32eSJiri Olsa 
517cd82a32eSJiri Olsa 	/*
518cd82a32eSJiri Olsa 	 * Support only for hardcoded and numnerial terms.
519cd82a32eSJiri Olsa 	 * Hardcoded terms should be already in, so nothing
520cd82a32eSJiri Olsa 	 * to be done for them.
521cd82a32eSJiri Olsa 	 */
522cd82a32eSJiri Olsa 	if (parse_events__is_hardcoded_term(term))
523cd82a32eSJiri Olsa 		return 0;
524cd82a32eSJiri Olsa 
52516fa7e82SJiri Olsa 	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
526cd82a32eSJiri Olsa 		return -EINVAL;
527cd82a32eSJiri Olsa 
528cd82a32eSJiri Olsa 	format = pmu_find_format(formats, term->config);
529cd82a32eSJiri Olsa 	if (!format)
530cd82a32eSJiri Olsa 		return -EINVAL;
531cd82a32eSJiri Olsa 
532cd82a32eSJiri Olsa 	switch (format->value) {
533cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG:
534cd82a32eSJiri Olsa 		vp = &attr->config;
535cd82a32eSJiri Olsa 		break;
536cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG1:
537cd82a32eSJiri Olsa 		vp = &attr->config1;
538cd82a32eSJiri Olsa 		break;
539cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG2:
540cd82a32eSJiri Olsa 		vp = &attr->config2;
541cd82a32eSJiri Olsa 		break;
542cd82a32eSJiri Olsa 	default:
543cd82a32eSJiri Olsa 		return -EINVAL;
544cd82a32eSJiri Olsa 	}
545cd82a32eSJiri Olsa 
54616fa7e82SJiri Olsa 	/*
54716fa7e82SJiri Olsa 	 * XXX If we ever decide to go with string values for
54816fa7e82SJiri Olsa 	 * non-hardcoded terms, here's the place to translate
54916fa7e82SJiri Olsa 	 * them into value.
55016fa7e82SJiri Olsa 	 */
551cd82a32eSJiri Olsa 	*vp |= pmu_format_value(format->bits, term->val.num);
552cd82a32eSJiri Olsa 	return 0;
553cd82a32eSJiri Olsa }
554cd82a32eSJiri Olsa 
555cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats,
556cff7f956SJiri Olsa 			   struct perf_event_attr *attr,
557cd82a32eSJiri Olsa 			   struct list_head *head_terms)
558cd82a32eSJiri Olsa {
5596cee6cd3SArnaldo Carvalho de Melo 	struct parse_events_term *term;
560cd82a32eSJiri Olsa 
5616b5fc39bSJiri Olsa 	list_for_each_entry(term, head_terms, list)
562cd82a32eSJiri Olsa 		if (pmu_config_term(formats, attr, term))
563cd82a32eSJiri Olsa 			return -EINVAL;
564cd82a32eSJiri Olsa 
565cd82a32eSJiri Olsa 	return 0;
566cd82a32eSJiri Olsa }
567cd82a32eSJiri Olsa 
568cd82a32eSJiri Olsa /*
569cd82a32eSJiri Olsa  * Configures event's 'attr' parameter based on the:
570cd82a32eSJiri Olsa  * 1) users input - specified in terms parameter
571cd82a32eSJiri Olsa  * 2) pmu format definitions - specified by pmu parameter
572cd82a32eSJiri Olsa  */
573cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
574cd82a32eSJiri Olsa 		     struct list_head *head_terms)
575cd82a32eSJiri Olsa {
576cd82a32eSJiri Olsa 	attr->type = pmu->type;
577cff7f956SJiri Olsa 	return perf_pmu__config_terms(&pmu->format, attr, head_terms);
578cd82a32eSJiri Olsa }
579cd82a32eSJiri Olsa 
5805c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
5816cee6cd3SArnaldo Carvalho de Melo 					     struct parse_events_term *term)
582a6146d50SZheng Yan {
5835c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_alias *alias;
584a6146d50SZheng Yan 	char *name;
585a6146d50SZheng Yan 
586a6146d50SZheng Yan 	if (parse_events__is_hardcoded_term(term))
587a6146d50SZheng Yan 		return NULL;
588a6146d50SZheng Yan 
589a6146d50SZheng Yan 	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
590a6146d50SZheng Yan 		if (term->val.num != 1)
591a6146d50SZheng Yan 			return NULL;
592a6146d50SZheng Yan 		if (pmu_find_format(&pmu->format, term->config))
593a6146d50SZheng Yan 			return NULL;
594a6146d50SZheng Yan 		name = term->config;
595a6146d50SZheng Yan 	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
596a6146d50SZheng Yan 		if (strcasecmp(term->config, "event"))
597a6146d50SZheng Yan 			return NULL;
598a6146d50SZheng Yan 		name = term->val.str;
599a6146d50SZheng Yan 	} else {
600a6146d50SZheng Yan 		return NULL;
601a6146d50SZheng Yan 	}
602a6146d50SZheng Yan 
603a6146d50SZheng Yan 	list_for_each_entry(alias, &pmu->aliases, list) {
604a6146d50SZheng Yan 		if (!strcasecmp(alias->name, name))
605a6146d50SZheng Yan 			return alias;
606a6146d50SZheng Yan 	}
607a6146d50SZheng Yan 	return NULL;
608a6146d50SZheng Yan }
609a6146d50SZheng Yan 
610410136f5SStephane Eranian 
611410136f5SStephane Eranian static int check_unit_scale(struct perf_pmu_alias *alias,
612410136f5SStephane Eranian 			    char **unit, double *scale)
613410136f5SStephane Eranian {
614410136f5SStephane Eranian 	/*
615410136f5SStephane Eranian 	 * Only one term in event definition can
616410136f5SStephane Eranian 	 * define unit and scale, fail if there's
617410136f5SStephane Eranian 	 * more than one.
618410136f5SStephane Eranian 	 */
619410136f5SStephane Eranian 	if ((*unit && alias->unit) ||
620410136f5SStephane Eranian 	    (*scale && alias->scale))
621410136f5SStephane Eranian 		return -EINVAL;
622410136f5SStephane Eranian 
623410136f5SStephane Eranian 	if (alias->unit)
624410136f5SStephane Eranian 		*unit = alias->unit;
625410136f5SStephane Eranian 
626410136f5SStephane Eranian 	if (alias->scale)
627410136f5SStephane Eranian 		*scale = alias->scale;
628410136f5SStephane Eranian 
629410136f5SStephane Eranian 	return 0;
630410136f5SStephane Eranian }
631410136f5SStephane Eranian 
632a6146d50SZheng Yan /*
633a6146d50SZheng Yan  * Find alias in the terms list and replace it with the terms
634a6146d50SZheng Yan  * defined for the alias
635a6146d50SZheng Yan  */
636410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
637410136f5SStephane Eranian 			  char **unit, double *scale)
638a6146d50SZheng Yan {
6396cee6cd3SArnaldo Carvalho de Melo 	struct parse_events_term *term, *h;
6405c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_alias *alias;
641a6146d50SZheng Yan 	int ret;
642a6146d50SZheng Yan 
643410136f5SStephane Eranian 	*unit   = NULL;
644410136f5SStephane Eranian 	*scale  = 0;
645410136f5SStephane Eranian 
646a6146d50SZheng Yan 	list_for_each_entry_safe(term, h, head_terms, list) {
647a6146d50SZheng Yan 		alias = pmu_find_alias(pmu, term);
648a6146d50SZheng Yan 		if (!alias)
649a6146d50SZheng Yan 			continue;
650a6146d50SZheng Yan 		ret = pmu_alias_terms(alias, &term->list);
651a6146d50SZheng Yan 		if (ret)
652a6146d50SZheng Yan 			return ret;
653410136f5SStephane Eranian 
654410136f5SStephane Eranian 		ret = check_unit_scale(alias, unit, scale);
655410136f5SStephane Eranian 		if (ret)
656410136f5SStephane Eranian 			return ret;
657410136f5SStephane Eranian 
658a6146d50SZheng Yan 		list_del(&term->list);
659a6146d50SZheng Yan 		free(term);
660a6146d50SZheng Yan 	}
661a6146d50SZheng Yan 	return 0;
662a6146d50SZheng Yan }
663a6146d50SZheng Yan 
664cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name,
665cd82a32eSJiri Olsa 			 int config, unsigned long *bits)
666cd82a32eSJiri Olsa {
6675c6ccc37SArnaldo Carvalho de Melo 	struct perf_pmu_format *format;
668cd82a32eSJiri Olsa 
669cd82a32eSJiri Olsa 	format = zalloc(sizeof(*format));
670cd82a32eSJiri Olsa 	if (!format)
671cd82a32eSJiri Olsa 		return -ENOMEM;
672cd82a32eSJiri Olsa 
673cd82a32eSJiri Olsa 	format->name = strdup(name);
674cd82a32eSJiri Olsa 	format->value = config;
675cd82a32eSJiri Olsa 	memcpy(format->bits, bits, sizeof(format->bits));
676cd82a32eSJiri Olsa 
677cd82a32eSJiri Olsa 	list_add_tail(&format->list, list);
678cd82a32eSJiri Olsa 	return 0;
679cd82a32eSJiri Olsa }
680cd82a32eSJiri Olsa 
681cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to)
682cd82a32eSJiri Olsa {
683cd82a32eSJiri Olsa 	long b;
684cd82a32eSJiri Olsa 
685cd82a32eSJiri Olsa 	if (!to)
686cd82a32eSJiri Olsa 		to = from;
687cd82a32eSJiri Olsa 
68815268138SSukadev Bhattiprolu 	memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
689cd82a32eSJiri Olsa 	for (b = from; b <= to; b++)
690cd82a32eSJiri Olsa 		set_bit(b, bits);
691cd82a32eSJiri Olsa }
692dc098b35SAndi Kleen 
693dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
694dc098b35SAndi Kleen 			  struct perf_pmu_alias *alias)
695dc098b35SAndi Kleen {
696dc098b35SAndi Kleen 	snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
697dc098b35SAndi Kleen 	return buf;
698dc098b35SAndi Kleen }
699dc098b35SAndi Kleen 
700dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
701dc098b35SAndi Kleen 			     struct perf_pmu_alias *alias)
702dc098b35SAndi Kleen {
703dc098b35SAndi Kleen 	snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
704dc098b35SAndi Kleen 	return buf;
705dc098b35SAndi Kleen }
706dc098b35SAndi Kleen 
707dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b)
708dc098b35SAndi Kleen {
709dc098b35SAndi Kleen 	const char * const *as = a;
710dc098b35SAndi Kleen 	const char * const *bs = b;
711dc098b35SAndi Kleen 	return strcmp(*as, *bs);
712dc098b35SAndi Kleen }
713dc098b35SAndi Kleen 
714dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only)
715dc098b35SAndi Kleen {
716dc098b35SAndi Kleen 	struct perf_pmu *pmu;
717dc098b35SAndi Kleen 	struct perf_pmu_alias *alias;
718dc098b35SAndi Kleen 	char buf[1024];
719dc098b35SAndi Kleen 	int printed = 0;
720dc098b35SAndi Kleen 	int len, j;
721dc098b35SAndi Kleen 	char **aliases;
722dc098b35SAndi Kleen 
723dc098b35SAndi Kleen 	pmu = NULL;
724dc098b35SAndi Kleen 	len = 0;
725dc098b35SAndi Kleen 	while ((pmu = perf_pmu__scan(pmu)) != NULL)
726dc098b35SAndi Kleen 		list_for_each_entry(alias, &pmu->aliases, list)
727dc098b35SAndi Kleen 			len++;
728dc098b35SAndi Kleen 	aliases = malloc(sizeof(char *) * len);
729dc098b35SAndi Kleen 	if (!aliases)
730dc098b35SAndi Kleen 		return;
731dc098b35SAndi Kleen 	pmu = NULL;
732dc098b35SAndi Kleen 	j = 0;
733dc098b35SAndi Kleen 	while ((pmu = perf_pmu__scan(pmu)) != NULL)
734dc098b35SAndi Kleen 		list_for_each_entry(alias, &pmu->aliases, list) {
735dc098b35SAndi Kleen 			char *name = format_alias(buf, sizeof(buf), pmu, alias);
736dc098b35SAndi Kleen 			bool is_cpu = !strcmp(pmu->name, "cpu");
737dc098b35SAndi Kleen 
738dc098b35SAndi Kleen 			if (event_glob != NULL &&
739dc098b35SAndi Kleen 			    !(strglobmatch(name, event_glob) ||
740dc098b35SAndi Kleen 			      (!is_cpu && strglobmatch(alias->name,
741dc098b35SAndi Kleen 						       event_glob))))
742dc098b35SAndi Kleen 				continue;
743dc098b35SAndi Kleen 			aliases[j] = name;
744dc098b35SAndi Kleen 			if (is_cpu && !name_only)
745dc098b35SAndi Kleen 				aliases[j] = format_alias_or(buf, sizeof(buf),
746dc098b35SAndi Kleen 							      pmu, alias);
747dc098b35SAndi Kleen 			aliases[j] = strdup(aliases[j]);
748dc098b35SAndi Kleen 			j++;
749dc098b35SAndi Kleen 		}
750dc098b35SAndi Kleen 	len = j;
751dc098b35SAndi Kleen 	qsort(aliases, len, sizeof(char *), cmp_string);
752dc098b35SAndi Kleen 	for (j = 0; j < len; j++) {
753dc098b35SAndi Kleen 		if (name_only) {
754dc098b35SAndi Kleen 			printf("%s ", aliases[j]);
755dc098b35SAndi Kleen 			continue;
756dc098b35SAndi Kleen 		}
757dc098b35SAndi Kleen 		printf("  %-50s [Kernel PMU event]\n", aliases[j]);
75874cf249dSArnaldo Carvalho de Melo 		zfree(&aliases[j]);
759dc098b35SAndi Kleen 		printed++;
760dc098b35SAndi Kleen 	}
761dc098b35SAndi Kleen 	if (printed)
762dc098b35SAndi Kleen 		printf("\n");
763dc098b35SAndi Kleen 	free(aliases);
764dc098b35SAndi Kleen }
7654cabc3d1SAndi Kleen 
7664cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name)
7674cabc3d1SAndi Kleen {
7684cabc3d1SAndi Kleen 	struct perf_pmu *pmu;
7694cabc3d1SAndi Kleen 	struct perf_pmu_alias *alias;
7704cabc3d1SAndi Kleen 
7714cabc3d1SAndi Kleen 	pmu = NULL;
7724cabc3d1SAndi Kleen 	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
7734cabc3d1SAndi Kleen 		if (strcmp(pname, pmu->name))
7744cabc3d1SAndi Kleen 			continue;
7754cabc3d1SAndi Kleen 		list_for_each_entry(alias, &pmu->aliases, list)
7764cabc3d1SAndi Kleen 			if (!strcmp(alias->name, name))
7774cabc3d1SAndi Kleen 				return true;
7784cabc3d1SAndi Kleen 	}
7794cabc3d1SAndi Kleen 	return false;
7804cabc3d1SAndi Kleen }
781