xref: /openbmc/linux/tools/perf/util/pmu.c (revision a6146d50)
1cd82a32eSJiri Olsa 
2cd82a32eSJiri Olsa #include <linux/list.h>
3cd82a32eSJiri Olsa #include <sys/types.h>
4cd82a32eSJiri Olsa #include <sys/stat.h>
5cd82a32eSJiri Olsa #include <unistd.h>
6cd82a32eSJiri Olsa #include <stdio.h>
7cd82a32eSJiri Olsa #include <dirent.h>
8cd82a32eSJiri Olsa #include "sysfs.h"
9cd82a32eSJiri Olsa #include "util.h"
10cd82a32eSJiri Olsa #include "pmu.h"
11cd82a32eSJiri Olsa #include "parse-events.h"
12cd82a32eSJiri Olsa 
13cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name);
14cd82a32eSJiri Olsa extern FILE *perf_pmu_in;
15cd82a32eSJiri Olsa 
16cd82a32eSJiri Olsa static LIST_HEAD(pmus);
17cd82a32eSJiri Olsa 
18cd82a32eSJiri Olsa /*
19cd82a32eSJiri Olsa  * Parse & process all the sysfs attributes located under
20cd82a32eSJiri Olsa  * the directory specified in 'dir' parameter.
21cd82a32eSJiri Olsa  */
22cd82a32eSJiri Olsa static int pmu_format_parse(char *dir, struct list_head *head)
23cd82a32eSJiri Olsa {
24cd82a32eSJiri Olsa 	struct dirent *evt_ent;
25cd82a32eSJiri Olsa 	DIR *format_dir;
26cd82a32eSJiri Olsa 	int ret = 0;
27cd82a32eSJiri Olsa 
28cd82a32eSJiri Olsa 	format_dir = opendir(dir);
29cd82a32eSJiri Olsa 	if (!format_dir)
30cd82a32eSJiri Olsa 		return -EINVAL;
31cd82a32eSJiri Olsa 
32cd82a32eSJiri Olsa 	while (!ret && (evt_ent = readdir(format_dir))) {
33cd82a32eSJiri Olsa 		char path[PATH_MAX];
34cd82a32eSJiri Olsa 		char *name = evt_ent->d_name;
35cd82a32eSJiri Olsa 		FILE *file;
36cd82a32eSJiri Olsa 
37cd82a32eSJiri Olsa 		if (!strcmp(name, ".") || !strcmp(name, ".."))
38cd82a32eSJiri Olsa 			continue;
39cd82a32eSJiri Olsa 
40cd82a32eSJiri Olsa 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
41cd82a32eSJiri Olsa 
42cd82a32eSJiri Olsa 		ret = -EINVAL;
43cd82a32eSJiri Olsa 		file = fopen(path, "r");
44cd82a32eSJiri Olsa 		if (!file)
45cd82a32eSJiri Olsa 			break;
46cd82a32eSJiri Olsa 
47cd82a32eSJiri Olsa 		perf_pmu_in = file;
48cd82a32eSJiri Olsa 		ret = perf_pmu_parse(head, name);
49cd82a32eSJiri Olsa 		fclose(file);
50cd82a32eSJiri Olsa 	}
51cd82a32eSJiri Olsa 
52cd82a32eSJiri Olsa 	closedir(format_dir);
53cd82a32eSJiri Olsa 	return ret;
54cd82a32eSJiri Olsa }
55cd82a32eSJiri Olsa 
56cd82a32eSJiri Olsa /*
57cd82a32eSJiri Olsa  * Reading/parsing the default pmu format definition, which should be
58cd82a32eSJiri Olsa  * located at:
59cd82a32eSJiri Olsa  * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
60cd82a32eSJiri Olsa  */
61cd82a32eSJiri Olsa static int pmu_format(char *name, struct list_head *format)
62cd82a32eSJiri Olsa {
63cd82a32eSJiri Olsa 	struct stat st;
64cd82a32eSJiri Olsa 	char path[PATH_MAX];
65cd82a32eSJiri Olsa 	const char *sysfs;
66cd82a32eSJiri Olsa 
67cd82a32eSJiri Olsa 	sysfs = sysfs_find_mountpoint();
68cd82a32eSJiri Olsa 	if (!sysfs)
69cd82a32eSJiri Olsa 		return -1;
70cd82a32eSJiri Olsa 
71cd82a32eSJiri Olsa 	snprintf(path, PATH_MAX,
72cd82a32eSJiri Olsa 		 "%s/bus/event_source/devices/%s/format", sysfs, name);
73cd82a32eSJiri Olsa 
74cd82a32eSJiri Olsa 	if (stat(path, &st) < 0)
75cd82a32eSJiri Olsa 		return -1;
76cd82a32eSJiri Olsa 
77cd82a32eSJiri Olsa 	if (pmu_format_parse(path, format))
78cd82a32eSJiri Olsa 		return -1;
79cd82a32eSJiri Olsa 
80cd82a32eSJiri Olsa 	return 0;
81cd82a32eSJiri Olsa }
82cd82a32eSJiri Olsa 
83a6146d50SZheng Yan static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
84a6146d50SZheng Yan {
85a6146d50SZheng Yan 	struct perf_pmu__alias *alias;
86a6146d50SZheng Yan 	char buf[256];
87a6146d50SZheng Yan 	int ret;
88a6146d50SZheng Yan 
89a6146d50SZheng Yan 	ret = fread(buf, 1, sizeof(buf), file);
90a6146d50SZheng Yan 	if (ret == 0)
91a6146d50SZheng Yan 		return -EINVAL;
92a6146d50SZheng Yan 	buf[ret] = 0;
93a6146d50SZheng Yan 
94a6146d50SZheng Yan 	alias = malloc(sizeof(*alias));
95a6146d50SZheng Yan 	if (!alias)
96a6146d50SZheng Yan 		return -ENOMEM;
97a6146d50SZheng Yan 
98a6146d50SZheng Yan 	INIT_LIST_HEAD(&alias->terms);
99a6146d50SZheng Yan 	ret = parse_events_terms(&alias->terms, buf);
100a6146d50SZheng Yan 	if (ret) {
101a6146d50SZheng Yan 		free(alias);
102a6146d50SZheng Yan 		return ret;
103a6146d50SZheng Yan 	}
104a6146d50SZheng Yan 
105a6146d50SZheng Yan 	alias->name = strdup(name);
106a6146d50SZheng Yan 	list_add_tail(&alias->list, list);
107a6146d50SZheng Yan 	return 0;
108a6146d50SZheng Yan }
109a6146d50SZheng Yan 
110a6146d50SZheng Yan /*
111a6146d50SZheng Yan  * Process all the sysfs attributes located under the directory
112a6146d50SZheng Yan  * specified in 'dir' parameter.
113a6146d50SZheng Yan  */
114a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head)
115a6146d50SZheng Yan {
116a6146d50SZheng Yan 	struct dirent *evt_ent;
117a6146d50SZheng Yan 	DIR *event_dir;
118a6146d50SZheng Yan 	int ret = 0;
119a6146d50SZheng Yan 
120a6146d50SZheng Yan 	event_dir = opendir(dir);
121a6146d50SZheng Yan 	if (!event_dir)
122a6146d50SZheng Yan 		return -EINVAL;
123a6146d50SZheng Yan 
124a6146d50SZheng Yan 	while (!ret && (evt_ent = readdir(event_dir))) {
125a6146d50SZheng Yan 		char path[PATH_MAX];
126a6146d50SZheng Yan 		char *name = evt_ent->d_name;
127a6146d50SZheng Yan 		FILE *file;
128a6146d50SZheng Yan 
129a6146d50SZheng Yan 		if (!strcmp(name, ".") || !strcmp(name, ".."))
130a6146d50SZheng Yan 			continue;
131a6146d50SZheng Yan 
132a6146d50SZheng Yan 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
133a6146d50SZheng Yan 
134a6146d50SZheng Yan 		ret = -EINVAL;
135a6146d50SZheng Yan 		file = fopen(path, "r");
136a6146d50SZheng Yan 		if (!file)
137a6146d50SZheng Yan 			break;
138a6146d50SZheng Yan 		ret = perf_pmu__new_alias(head, name, file);
139a6146d50SZheng Yan 		fclose(file);
140a6146d50SZheng Yan 	}
141a6146d50SZheng Yan 
142a6146d50SZheng Yan 	closedir(event_dir);
143a6146d50SZheng Yan 	return ret;
144a6146d50SZheng Yan }
145a6146d50SZheng Yan 
146a6146d50SZheng Yan /*
147a6146d50SZheng Yan  * Reading the pmu event aliases definition, which should be located at:
148a6146d50SZheng Yan  * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
149a6146d50SZheng Yan  */
150a6146d50SZheng Yan static int pmu_aliases(char *name, struct list_head *head)
151a6146d50SZheng Yan {
152a6146d50SZheng Yan 	struct stat st;
153a6146d50SZheng Yan 	char path[PATH_MAX];
154a6146d50SZheng Yan 	const char *sysfs;
155a6146d50SZheng Yan 
156a6146d50SZheng Yan 	sysfs = sysfs_find_mountpoint();
157a6146d50SZheng Yan 	if (!sysfs)
158a6146d50SZheng Yan 		return -1;
159a6146d50SZheng Yan 
160a6146d50SZheng Yan 	snprintf(path, PATH_MAX,
161a6146d50SZheng Yan 		 "%s/bus/event_source/devices/%s/events", sysfs, name);
162a6146d50SZheng Yan 
163a6146d50SZheng Yan 	if (stat(path, &st) < 0)
164a6146d50SZheng Yan 		return -1;
165a6146d50SZheng Yan 
166a6146d50SZheng Yan 	if (pmu_aliases_parse(path, head))
167a6146d50SZheng Yan 		return -1;
168a6146d50SZheng Yan 
169a6146d50SZheng Yan 	return 0;
170a6146d50SZheng Yan }
171a6146d50SZheng Yan 
172a6146d50SZheng Yan static int pmu_alias_terms(struct perf_pmu__alias *alias,
173a6146d50SZheng Yan 			   struct list_head *terms)
174a6146d50SZheng Yan {
175a6146d50SZheng Yan 	struct parse_events__term *term, *clone;
176a6146d50SZheng Yan 	LIST_HEAD(list);
177a6146d50SZheng Yan 	int ret;
178a6146d50SZheng Yan 
179a6146d50SZheng Yan 	list_for_each_entry(term, &alias->terms, list) {
180a6146d50SZheng Yan 		ret = parse_events__term_clone(&clone, term);
181a6146d50SZheng Yan 		if (ret) {
182a6146d50SZheng Yan 			parse_events__free_terms(&list);
183a6146d50SZheng Yan 			return ret;
184a6146d50SZheng Yan 		}
185a6146d50SZheng Yan 		list_add_tail(&clone->list, &list);
186a6146d50SZheng Yan 	}
187a6146d50SZheng Yan 	list_splice(&list, terms);
188a6146d50SZheng Yan 	return 0;
189a6146d50SZheng Yan }
190a6146d50SZheng Yan 
191cd82a32eSJiri Olsa /*
192cd82a32eSJiri Olsa  * Reading/parsing the default pmu type value, which should be
193cd82a32eSJiri Olsa  * located at:
194cd82a32eSJiri Olsa  * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
195cd82a32eSJiri Olsa  */
196cd82a32eSJiri Olsa static int pmu_type(char *name, __u32 *type)
197cd82a32eSJiri Olsa {
198cd82a32eSJiri Olsa 	struct stat st;
199cd82a32eSJiri Olsa 	char path[PATH_MAX];
200cd82a32eSJiri Olsa 	const char *sysfs;
201cd82a32eSJiri Olsa 	FILE *file;
202cd82a32eSJiri Olsa 	int ret = 0;
203cd82a32eSJiri Olsa 
204cd82a32eSJiri Olsa 	sysfs = sysfs_find_mountpoint();
205cd82a32eSJiri Olsa 	if (!sysfs)
206cd82a32eSJiri Olsa 		return -1;
207cd82a32eSJiri Olsa 
208cd82a32eSJiri Olsa 	snprintf(path, PATH_MAX,
209cd82a32eSJiri Olsa 		 "%s/bus/event_source/devices/%s/type", sysfs, name);
210cd82a32eSJiri Olsa 
211cd82a32eSJiri Olsa 	if (stat(path, &st) < 0)
212cd82a32eSJiri Olsa 		return -1;
213cd82a32eSJiri Olsa 
214cd82a32eSJiri Olsa 	file = fopen(path, "r");
215cd82a32eSJiri Olsa 	if (!file)
216cd82a32eSJiri Olsa 		return -EINVAL;
217cd82a32eSJiri Olsa 
218cd82a32eSJiri Olsa 	if (1 != fscanf(file, "%u", type))
219cd82a32eSJiri Olsa 		ret = -1;
220cd82a32eSJiri Olsa 
221cd82a32eSJiri Olsa 	fclose(file);
222cd82a32eSJiri Olsa 	return ret;
223cd82a32eSJiri Olsa }
224cd82a32eSJiri Olsa 
225cd82a32eSJiri Olsa static struct perf_pmu *pmu_lookup(char *name)
226cd82a32eSJiri Olsa {
227cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
228cd82a32eSJiri Olsa 	LIST_HEAD(format);
229a6146d50SZheng Yan 	LIST_HEAD(aliases);
230cd82a32eSJiri Olsa 	__u32 type;
231cd82a32eSJiri Olsa 
232cd82a32eSJiri Olsa 	/*
233cd82a32eSJiri Olsa 	 * The pmu data we store & need consists of the pmu
234cd82a32eSJiri Olsa 	 * type value and format definitions. Load both right
235cd82a32eSJiri Olsa 	 * now.
236cd82a32eSJiri Olsa 	 */
237cd82a32eSJiri Olsa 	if (pmu_format(name, &format))
238cd82a32eSJiri Olsa 		return NULL;
239cd82a32eSJiri Olsa 
240cd82a32eSJiri Olsa 	if (pmu_type(name, &type))
241cd82a32eSJiri Olsa 		return NULL;
242cd82a32eSJiri Olsa 
243cd82a32eSJiri Olsa 	pmu = zalloc(sizeof(*pmu));
244cd82a32eSJiri Olsa 	if (!pmu)
245cd82a32eSJiri Olsa 		return NULL;
246cd82a32eSJiri Olsa 
247a6146d50SZheng Yan 	pmu_aliases(name, &aliases);
248a6146d50SZheng Yan 
249cd82a32eSJiri Olsa 	INIT_LIST_HEAD(&pmu->format);
250a6146d50SZheng Yan 	INIT_LIST_HEAD(&pmu->aliases);
251cd82a32eSJiri Olsa 	list_splice(&format, &pmu->format);
252a6146d50SZheng Yan 	list_splice(&aliases, &pmu->aliases);
253cd82a32eSJiri Olsa 	pmu->name = strdup(name);
254cd82a32eSJiri Olsa 	pmu->type = type;
255cd82a32eSJiri Olsa 	return pmu;
256cd82a32eSJiri Olsa }
257cd82a32eSJiri Olsa 
258cd82a32eSJiri Olsa static struct perf_pmu *pmu_find(char *name)
259cd82a32eSJiri Olsa {
260cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
261cd82a32eSJiri Olsa 
262cd82a32eSJiri Olsa 	list_for_each_entry(pmu, &pmus, list)
263cd82a32eSJiri Olsa 		if (!strcmp(pmu->name, name))
264cd82a32eSJiri Olsa 			return pmu;
265cd82a32eSJiri Olsa 
266cd82a32eSJiri Olsa 	return NULL;
267cd82a32eSJiri Olsa }
268cd82a32eSJiri Olsa 
269cd82a32eSJiri Olsa struct perf_pmu *perf_pmu__find(char *name)
270cd82a32eSJiri Olsa {
271cd82a32eSJiri Olsa 	struct perf_pmu *pmu;
272cd82a32eSJiri Olsa 
273cd82a32eSJiri Olsa 	/*
274cd82a32eSJiri Olsa 	 * Once PMU is loaded it stays in the list,
275cd82a32eSJiri Olsa 	 * so we keep us from multiple reading/parsing
276cd82a32eSJiri Olsa 	 * the pmu format definitions.
277cd82a32eSJiri Olsa 	 */
278cd82a32eSJiri Olsa 	pmu = pmu_find(name);
279cd82a32eSJiri Olsa 	if (pmu)
280cd82a32eSJiri Olsa 		return pmu;
281cd82a32eSJiri Olsa 
282cd82a32eSJiri Olsa 	return pmu_lookup(name);
283cd82a32eSJiri Olsa }
284cd82a32eSJiri Olsa 
285cd82a32eSJiri Olsa static struct perf_pmu__format*
286cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name)
287cd82a32eSJiri Olsa {
288cd82a32eSJiri Olsa 	struct perf_pmu__format *format;
289cd82a32eSJiri Olsa 
290cd82a32eSJiri Olsa 	list_for_each_entry(format, formats, list)
291cd82a32eSJiri Olsa 		if (!strcmp(format->name, name))
292cd82a32eSJiri Olsa 			return format;
293cd82a32eSJiri Olsa 
294cd82a32eSJiri Olsa 	return NULL;
295cd82a32eSJiri Olsa }
296cd82a32eSJiri Olsa 
297cd82a32eSJiri Olsa /*
298cd82a32eSJiri Olsa  * Returns value based on the format definition (format parameter)
299cd82a32eSJiri Olsa  * and unformated value (value parameter).
300cd82a32eSJiri Olsa  *
301cd82a32eSJiri Olsa  * TODO maybe optimize a little ;)
302cd82a32eSJiri Olsa  */
303cd82a32eSJiri Olsa static __u64 pmu_format_value(unsigned long *format, __u64 value)
304cd82a32eSJiri Olsa {
305cd82a32eSJiri Olsa 	unsigned long fbit, vbit;
306cd82a32eSJiri Olsa 	__u64 v = 0;
307cd82a32eSJiri Olsa 
308cd82a32eSJiri Olsa 	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
309cd82a32eSJiri Olsa 
310cd82a32eSJiri Olsa 		if (!test_bit(fbit, format))
311cd82a32eSJiri Olsa 			continue;
312cd82a32eSJiri Olsa 
313cd82a32eSJiri Olsa 		if (!(value & (1llu << vbit++)))
314cd82a32eSJiri Olsa 			continue;
315cd82a32eSJiri Olsa 
316cd82a32eSJiri Olsa 		v |= (1llu << fbit);
317cd82a32eSJiri Olsa 	}
318cd82a32eSJiri Olsa 
319cd82a32eSJiri Olsa 	return v;
320cd82a32eSJiri Olsa }
321cd82a32eSJiri Olsa 
322cd82a32eSJiri Olsa /*
323cd82a32eSJiri Olsa  * Setup one of config[12] attr members based on the
324cd82a32eSJiri Olsa  * user input data - temr parameter.
325cd82a32eSJiri Olsa  */
326cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats,
327cd82a32eSJiri Olsa 			   struct perf_event_attr *attr,
328cd82a32eSJiri Olsa 			   struct parse_events__term *term)
329cd82a32eSJiri Olsa {
330cd82a32eSJiri Olsa 	struct perf_pmu__format *format;
331cd82a32eSJiri Olsa 	__u64 *vp;
332cd82a32eSJiri Olsa 
333cd82a32eSJiri Olsa 	/*
334cd82a32eSJiri Olsa 	 * Support only for hardcoded and numnerial terms.
335cd82a32eSJiri Olsa 	 * Hardcoded terms should be already in, so nothing
336cd82a32eSJiri Olsa 	 * to be done for them.
337cd82a32eSJiri Olsa 	 */
338cd82a32eSJiri Olsa 	if (parse_events__is_hardcoded_term(term))
339cd82a32eSJiri Olsa 		return 0;
340cd82a32eSJiri Olsa 
34116fa7e82SJiri Olsa 	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
342cd82a32eSJiri Olsa 		return -EINVAL;
343cd82a32eSJiri Olsa 
344cd82a32eSJiri Olsa 	format = pmu_find_format(formats, term->config);
345cd82a32eSJiri Olsa 	if (!format)
346cd82a32eSJiri Olsa 		return -EINVAL;
347cd82a32eSJiri Olsa 
348cd82a32eSJiri Olsa 	switch (format->value) {
349cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG:
350cd82a32eSJiri Olsa 		vp = &attr->config;
351cd82a32eSJiri Olsa 		break;
352cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG1:
353cd82a32eSJiri Olsa 		vp = &attr->config1;
354cd82a32eSJiri Olsa 		break;
355cd82a32eSJiri Olsa 	case PERF_PMU_FORMAT_VALUE_CONFIG2:
356cd82a32eSJiri Olsa 		vp = &attr->config2;
357cd82a32eSJiri Olsa 		break;
358cd82a32eSJiri Olsa 	default:
359cd82a32eSJiri Olsa 		return -EINVAL;
360cd82a32eSJiri Olsa 	}
361cd82a32eSJiri Olsa 
36216fa7e82SJiri Olsa 	/*
36316fa7e82SJiri Olsa 	 * XXX If we ever decide to go with string values for
36416fa7e82SJiri Olsa 	 * non-hardcoded terms, here's the place to translate
36516fa7e82SJiri Olsa 	 * them into value.
36616fa7e82SJiri Olsa 	 */
367cd82a32eSJiri Olsa 	*vp |= pmu_format_value(format->bits, term->val.num);
368cd82a32eSJiri Olsa 	return 0;
369cd82a32eSJiri Olsa }
370cd82a32eSJiri Olsa 
371cd82a32eSJiri Olsa static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
372cd82a32eSJiri Olsa 		      struct list_head *head_terms)
373cd82a32eSJiri Olsa {
3746b5fc39bSJiri Olsa 	struct parse_events__term *term;
375cd82a32eSJiri Olsa 
3766b5fc39bSJiri Olsa 	list_for_each_entry(term, head_terms, list)
377cd82a32eSJiri Olsa 		if (pmu_config_term(formats, attr, term))
378cd82a32eSJiri Olsa 			return -EINVAL;
379cd82a32eSJiri Olsa 
380cd82a32eSJiri Olsa 	return 0;
381cd82a32eSJiri Olsa }
382cd82a32eSJiri Olsa 
383cd82a32eSJiri Olsa /*
384cd82a32eSJiri Olsa  * Configures event's 'attr' parameter based on the:
385cd82a32eSJiri Olsa  * 1) users input - specified in terms parameter
386cd82a32eSJiri Olsa  * 2) pmu format definitions - specified by pmu parameter
387cd82a32eSJiri Olsa  */
388cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
389cd82a32eSJiri Olsa 		     struct list_head *head_terms)
390cd82a32eSJiri Olsa {
391cd82a32eSJiri Olsa 	attr->type = pmu->type;
392cd82a32eSJiri Olsa 	return pmu_config(&pmu->format, attr, head_terms);
393cd82a32eSJiri Olsa }
394cd82a32eSJiri Olsa 
395a6146d50SZheng Yan static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
396a6146d50SZheng Yan 					      struct parse_events__term *term)
397a6146d50SZheng Yan {
398a6146d50SZheng Yan 	struct perf_pmu__alias *alias;
399a6146d50SZheng Yan 	char *name;
400a6146d50SZheng Yan 
401a6146d50SZheng Yan 	if (parse_events__is_hardcoded_term(term))
402a6146d50SZheng Yan 		return NULL;
403a6146d50SZheng Yan 
404a6146d50SZheng Yan 	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
405a6146d50SZheng Yan 		if (term->val.num != 1)
406a6146d50SZheng Yan 			return NULL;
407a6146d50SZheng Yan 		if (pmu_find_format(&pmu->format, term->config))
408a6146d50SZheng Yan 			return NULL;
409a6146d50SZheng Yan 		name = term->config;
410a6146d50SZheng Yan 	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
411a6146d50SZheng Yan 		if (strcasecmp(term->config, "event"))
412a6146d50SZheng Yan 			return NULL;
413a6146d50SZheng Yan 		name = term->val.str;
414a6146d50SZheng Yan 	} else {
415a6146d50SZheng Yan 		return NULL;
416a6146d50SZheng Yan 	}
417a6146d50SZheng Yan 
418a6146d50SZheng Yan 	list_for_each_entry(alias, &pmu->aliases, list) {
419a6146d50SZheng Yan 		if (!strcasecmp(alias->name, name))
420a6146d50SZheng Yan 			return alias;
421a6146d50SZheng Yan 	}
422a6146d50SZheng Yan 	return NULL;
423a6146d50SZheng Yan }
424a6146d50SZheng Yan 
425a6146d50SZheng Yan /*
426a6146d50SZheng Yan  * Find alias in the terms list and replace it with the terms
427a6146d50SZheng Yan  * defined for the alias
428a6146d50SZheng Yan  */
429a6146d50SZheng Yan int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
430a6146d50SZheng Yan {
431a6146d50SZheng Yan 	struct parse_events__term *term, *h;
432a6146d50SZheng Yan 	struct perf_pmu__alias *alias;
433a6146d50SZheng Yan 	int ret;
434a6146d50SZheng Yan 
435a6146d50SZheng Yan 	list_for_each_entry_safe(term, h, head_terms, list) {
436a6146d50SZheng Yan 		alias = pmu_find_alias(pmu, term);
437a6146d50SZheng Yan 		if (!alias)
438a6146d50SZheng Yan 			continue;
439a6146d50SZheng Yan 		ret = pmu_alias_terms(alias, &term->list);
440a6146d50SZheng Yan 		if (ret)
441a6146d50SZheng Yan 			return ret;
442a6146d50SZheng Yan 		list_del(&term->list);
443a6146d50SZheng Yan 		free(term);
444a6146d50SZheng Yan 	}
445a6146d50SZheng Yan 	return 0;
446a6146d50SZheng Yan }
447a6146d50SZheng Yan 
448cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name,
449cd82a32eSJiri Olsa 			 int config, unsigned long *bits)
450cd82a32eSJiri Olsa {
451cd82a32eSJiri Olsa 	struct perf_pmu__format *format;
452cd82a32eSJiri Olsa 
453cd82a32eSJiri Olsa 	format = zalloc(sizeof(*format));
454cd82a32eSJiri Olsa 	if (!format)
455cd82a32eSJiri Olsa 		return -ENOMEM;
456cd82a32eSJiri Olsa 
457cd82a32eSJiri Olsa 	format->name = strdup(name);
458cd82a32eSJiri Olsa 	format->value = config;
459cd82a32eSJiri Olsa 	memcpy(format->bits, bits, sizeof(format->bits));
460cd82a32eSJiri Olsa 
461cd82a32eSJiri Olsa 	list_add_tail(&format->list, list);
462cd82a32eSJiri Olsa 	return 0;
463cd82a32eSJiri Olsa }
464cd82a32eSJiri Olsa 
465cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to)
466cd82a32eSJiri Olsa {
467cd82a32eSJiri Olsa 	long b;
468cd82a32eSJiri Olsa 
469cd82a32eSJiri Olsa 	if (!to)
470cd82a32eSJiri Olsa 		to = from;
471cd82a32eSJiri Olsa 
472cd82a32eSJiri Olsa 	memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
473cd82a32eSJiri Olsa 	for (b = from; b <= to; b++)
474cd82a32eSJiri Olsa 		set_bit(b, bits);
475cd82a32eSJiri Olsa }
476cd82a32eSJiri Olsa 
477cd82a32eSJiri Olsa /* Simulated format definitions. */
478cd82a32eSJiri Olsa static struct test_format {
479cd82a32eSJiri Olsa 	const char *name;
480cd82a32eSJiri Olsa 	const char *value;
481cd82a32eSJiri Olsa } test_formats[] = {
482cd82a32eSJiri Olsa 	{ "krava01", "config:0-1,62-63\n", },
483cd82a32eSJiri Olsa 	{ "krava02", "config:10-17\n", },
484cd82a32eSJiri Olsa 	{ "krava03", "config:5\n", },
485cd82a32eSJiri Olsa 	{ "krava11", "config1:0,2,4,6,8,20-28\n", },
486cd82a32eSJiri Olsa 	{ "krava12", "config1:63\n", },
487cd82a32eSJiri Olsa 	{ "krava13", "config1:45-47\n", },
488cd82a32eSJiri Olsa 	{ "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
489cd82a32eSJiri Olsa 	{ "krava22", "config2:8,18,48,58\n", },
490cd82a32eSJiri Olsa 	{ "krava23", "config2:28-29,38\n", },
491cd82a32eSJiri Olsa };
492cd82a32eSJiri Olsa 
493cd82a32eSJiri Olsa #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
494cd82a32eSJiri Olsa 
495cd82a32eSJiri Olsa /* Simulated users input. */
496cd82a32eSJiri Olsa static struct parse_events__term test_terms[] = {
497cd82a32eSJiri Olsa 	{
498cd82a32eSJiri Olsa 		.config    = (char *) "krava01",
499cd82a32eSJiri Olsa 		.val.num   = 15,
50016fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
50116fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
502cd82a32eSJiri Olsa 	},
503cd82a32eSJiri Olsa 	{
504cd82a32eSJiri Olsa 		.config    = (char *) "krava02",
505cd82a32eSJiri Olsa 		.val.num   = 170,
50616fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
50716fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
508cd82a32eSJiri Olsa 	},
509cd82a32eSJiri Olsa 	{
510cd82a32eSJiri Olsa 		.config    = (char *) "krava03",
511cd82a32eSJiri Olsa 		.val.num   = 1,
51216fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
51316fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
514cd82a32eSJiri Olsa 	},
515cd82a32eSJiri Olsa 	{
516cd82a32eSJiri Olsa 		.config    = (char *) "krava11",
517cd82a32eSJiri Olsa 		.val.num   = 27,
51816fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
51916fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
520cd82a32eSJiri Olsa 	},
521cd82a32eSJiri Olsa 	{
522cd82a32eSJiri Olsa 		.config    = (char *) "krava12",
523cd82a32eSJiri Olsa 		.val.num   = 1,
52416fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
52516fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
526cd82a32eSJiri Olsa 	},
527cd82a32eSJiri Olsa 	{
528cd82a32eSJiri Olsa 		.config    = (char *) "krava13",
529cd82a32eSJiri Olsa 		.val.num   = 2,
53016fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
53116fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
532cd82a32eSJiri Olsa 	},
533cd82a32eSJiri Olsa 	{
534cd82a32eSJiri Olsa 		.config    = (char *) "krava21",
535cd82a32eSJiri Olsa 		.val.num   = 119,
53616fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
53716fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
538cd82a32eSJiri Olsa 	},
539cd82a32eSJiri Olsa 	{
540cd82a32eSJiri Olsa 		.config    = (char *) "krava22",
541cd82a32eSJiri Olsa 		.val.num   = 11,
54216fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
54316fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
544cd82a32eSJiri Olsa 	},
545cd82a32eSJiri Olsa 	{
546cd82a32eSJiri Olsa 		.config    = (char *) "krava23",
547cd82a32eSJiri Olsa 		.val.num   = 2,
54816fa7e82SJiri Olsa 		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
54916fa7e82SJiri Olsa 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
550cd82a32eSJiri Olsa 	},
551cd82a32eSJiri Olsa };
552cd82a32eSJiri Olsa #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
553cd82a32eSJiri Olsa 
554cd82a32eSJiri Olsa /*
555cd82a32eSJiri Olsa  * Prepare format directory data, exported by kernel
556cd82a32eSJiri Olsa  * at /sys/bus/event_source/devices/<dev>/format.
557cd82a32eSJiri Olsa  */
558cd82a32eSJiri Olsa static char *test_format_dir_get(void)
559cd82a32eSJiri Olsa {
560cd82a32eSJiri Olsa 	static char dir[PATH_MAX];
561cd82a32eSJiri Olsa 	unsigned int i;
562cd82a32eSJiri Olsa 
563cd82a32eSJiri Olsa 	snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
564cd82a32eSJiri Olsa 	if (!mkdtemp(dir))
565cd82a32eSJiri Olsa 		return NULL;
566cd82a32eSJiri Olsa 
567cd82a32eSJiri Olsa 	for (i = 0; i < TEST_FORMATS_CNT; i++) {
568cd82a32eSJiri Olsa 		static char name[PATH_MAX];
569cd82a32eSJiri Olsa 		struct test_format *format = &test_formats[i];
570cd82a32eSJiri Olsa 		FILE *file;
571cd82a32eSJiri Olsa 
572cd82a32eSJiri Olsa 		snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
573cd82a32eSJiri Olsa 
574cd82a32eSJiri Olsa 		file = fopen(name, "w");
575cd82a32eSJiri Olsa 		if (!file)
576cd82a32eSJiri Olsa 			return NULL;
577cd82a32eSJiri Olsa 
578cd82a32eSJiri Olsa 		if (1 != fwrite(format->value, strlen(format->value), 1, file))
579cd82a32eSJiri Olsa 			break;
580cd82a32eSJiri Olsa 
581cd82a32eSJiri Olsa 		fclose(file);
582cd82a32eSJiri Olsa 	}
583cd82a32eSJiri Olsa 
584cd82a32eSJiri Olsa 	return dir;
585cd82a32eSJiri Olsa }
586cd82a32eSJiri Olsa 
587cd82a32eSJiri Olsa /* Cleanup format directory. */
588cd82a32eSJiri Olsa static int test_format_dir_put(char *dir)
589cd82a32eSJiri Olsa {
590cd82a32eSJiri Olsa 	char buf[PATH_MAX];
591cd82a32eSJiri Olsa 	snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
592cd82a32eSJiri Olsa 	if (system(buf))
593cd82a32eSJiri Olsa 		return -1;
594cd82a32eSJiri Olsa 
595cd82a32eSJiri Olsa 	snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
596cd82a32eSJiri Olsa 	return system(buf);
597cd82a32eSJiri Olsa }
598cd82a32eSJiri Olsa 
599cd82a32eSJiri Olsa static struct list_head *test_terms_list(void)
600cd82a32eSJiri Olsa {
601cd82a32eSJiri Olsa 	static LIST_HEAD(terms);
602cd82a32eSJiri Olsa 	unsigned int i;
603cd82a32eSJiri Olsa 
604cd82a32eSJiri Olsa 	for (i = 0; i < TERMS_CNT; i++)
605cd82a32eSJiri Olsa 		list_add_tail(&test_terms[i].list, &terms);
606cd82a32eSJiri Olsa 
607cd82a32eSJiri Olsa 	return &terms;
608cd82a32eSJiri Olsa }
609cd82a32eSJiri Olsa 
610cd82a32eSJiri Olsa #undef TERMS_CNT
611cd82a32eSJiri Olsa 
612cd82a32eSJiri Olsa int perf_pmu__test(void)
613cd82a32eSJiri Olsa {
614cd82a32eSJiri Olsa 	char *format = test_format_dir_get();
615cd82a32eSJiri Olsa 	LIST_HEAD(formats);
616cd82a32eSJiri Olsa 	struct list_head *terms = test_terms_list();
617cd82a32eSJiri Olsa 	int ret;
618cd82a32eSJiri Olsa 
619cd82a32eSJiri Olsa 	if (!format)
620cd82a32eSJiri Olsa 		return -EINVAL;
621cd82a32eSJiri Olsa 
622cd82a32eSJiri Olsa 	do {
623cd82a32eSJiri Olsa 		struct perf_event_attr attr;
624cd82a32eSJiri Olsa 
625cd82a32eSJiri Olsa 		memset(&attr, 0, sizeof(attr));
626cd82a32eSJiri Olsa 
627cd82a32eSJiri Olsa 		ret = pmu_format_parse(format, &formats);
628cd82a32eSJiri Olsa 		if (ret)
629cd82a32eSJiri Olsa 			break;
630cd82a32eSJiri Olsa 
631cd82a32eSJiri Olsa 		ret = pmu_config(&formats, &attr, terms);
632cd82a32eSJiri Olsa 		if (ret)
633cd82a32eSJiri Olsa 			break;
634cd82a32eSJiri Olsa 
635cd82a32eSJiri Olsa 		ret = -EINVAL;
636cd82a32eSJiri Olsa 
637cd82a32eSJiri Olsa 		if (attr.config  != 0xc00000000002a823)
638cd82a32eSJiri Olsa 			break;
639cd82a32eSJiri Olsa 		if (attr.config1 != 0x8000400000000145)
640cd82a32eSJiri Olsa 			break;
641cd82a32eSJiri Olsa 		if (attr.config2 != 0x0400000020041d07)
642cd82a32eSJiri Olsa 			break;
643cd82a32eSJiri Olsa 
644cd82a32eSJiri Olsa 		ret = 0;
645cd82a32eSJiri Olsa 	} while (0);
646cd82a32eSJiri Olsa 
647cd82a32eSJiri Olsa 	test_format_dir_put(format);
648cd82a32eSJiri Olsa 	return ret;
649cd82a32eSJiri Olsa }
650