xref: /linux/tools/perf/util/pmu.c (revision d0b73b488c55df905ea8faaad079f8535629ed26)
1 
2 #include <linux/list.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <dirent.h>
8 #include "sysfs.h"
9 #include "util.h"
10 #include "pmu.h"
11 #include "parse-events.h"
12 #include "cpumap.h"
13 
14 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
15 
16 int perf_pmu_parse(struct list_head *list, char *name);
17 extern FILE *perf_pmu_in;
18 
19 static LIST_HEAD(pmus);
20 
21 /*
22  * Parse & process all the sysfs attributes located under
23  * the directory specified in 'dir' parameter.
24  */
25 int perf_pmu__format_parse(char *dir, struct list_head *head)
26 {
27 	struct dirent *evt_ent;
28 	DIR *format_dir;
29 	int ret = 0;
30 
31 	format_dir = opendir(dir);
32 	if (!format_dir)
33 		return -EINVAL;
34 
35 	while (!ret && (evt_ent = readdir(format_dir))) {
36 		char path[PATH_MAX];
37 		char *name = evt_ent->d_name;
38 		FILE *file;
39 
40 		if (!strcmp(name, ".") || !strcmp(name, ".."))
41 			continue;
42 
43 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
44 
45 		ret = -EINVAL;
46 		file = fopen(path, "r");
47 		if (!file)
48 			break;
49 
50 		perf_pmu_in = file;
51 		ret = perf_pmu_parse(head, name);
52 		fclose(file);
53 	}
54 
55 	closedir(format_dir);
56 	return ret;
57 }
58 
59 /*
60  * Reading/parsing the default pmu format definition, which should be
61  * located at:
62  * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
63  */
64 static int pmu_format(char *name, struct list_head *format)
65 {
66 	struct stat st;
67 	char path[PATH_MAX];
68 	const char *sysfs;
69 
70 	sysfs = sysfs_find_mountpoint();
71 	if (!sysfs)
72 		return -1;
73 
74 	snprintf(path, PATH_MAX,
75 		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
76 
77 	if (stat(path, &st) < 0)
78 		return 0;	/* no error if format does not exist */
79 
80 	if (perf_pmu__format_parse(path, format))
81 		return -1;
82 
83 	return 0;
84 }
85 
86 static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
87 {
88 	struct perf_pmu__alias *alias;
89 	char buf[256];
90 	int ret;
91 
92 	ret = fread(buf, 1, sizeof(buf), file);
93 	if (ret == 0)
94 		return -EINVAL;
95 	buf[ret] = 0;
96 
97 	alias = malloc(sizeof(*alias));
98 	if (!alias)
99 		return -ENOMEM;
100 
101 	INIT_LIST_HEAD(&alias->terms);
102 	ret = parse_events_terms(&alias->terms, buf);
103 	if (ret) {
104 		free(alias);
105 		return ret;
106 	}
107 
108 	alias->name = strdup(name);
109 	list_add_tail(&alias->list, list);
110 	return 0;
111 }
112 
113 /*
114  * Process all the sysfs attributes located under the directory
115  * specified in 'dir' parameter.
116  */
117 static int pmu_aliases_parse(char *dir, struct list_head *head)
118 {
119 	struct dirent *evt_ent;
120 	DIR *event_dir;
121 	int ret = 0;
122 
123 	event_dir = opendir(dir);
124 	if (!event_dir)
125 		return -EINVAL;
126 
127 	while (!ret && (evt_ent = readdir(event_dir))) {
128 		char path[PATH_MAX];
129 		char *name = evt_ent->d_name;
130 		FILE *file;
131 
132 		if (!strcmp(name, ".") || !strcmp(name, ".."))
133 			continue;
134 
135 		snprintf(path, PATH_MAX, "%s/%s", dir, name);
136 
137 		ret = -EINVAL;
138 		file = fopen(path, "r");
139 		if (!file)
140 			break;
141 		ret = perf_pmu__new_alias(head, name, file);
142 		fclose(file);
143 	}
144 
145 	closedir(event_dir);
146 	return ret;
147 }
148 
149 /*
150  * Reading the pmu event aliases definition, which should be located at:
151  * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
152  */
153 static int pmu_aliases(char *name, struct list_head *head)
154 {
155 	struct stat st;
156 	char path[PATH_MAX];
157 	const char *sysfs;
158 
159 	sysfs = sysfs_find_mountpoint();
160 	if (!sysfs)
161 		return -1;
162 
163 	snprintf(path, PATH_MAX,
164 		 "%s/bus/event_source/devices/%s/events", sysfs, name);
165 
166 	if (stat(path, &st) < 0)
167 		return 0;	 /* no error if 'events' does not exist */
168 
169 	if (pmu_aliases_parse(path, head))
170 		return -1;
171 
172 	return 0;
173 }
174 
175 static int pmu_alias_terms(struct perf_pmu__alias *alias,
176 			   struct list_head *terms)
177 {
178 	struct parse_events__term *term, *clone;
179 	LIST_HEAD(list);
180 	int ret;
181 
182 	list_for_each_entry(term, &alias->terms, list) {
183 		ret = parse_events__term_clone(&clone, term);
184 		if (ret) {
185 			parse_events__free_terms(&list);
186 			return ret;
187 		}
188 		list_add_tail(&clone->list, &list);
189 	}
190 	list_splice(&list, terms);
191 	return 0;
192 }
193 
194 /*
195  * Reading/parsing the default pmu type value, which should be
196  * located at:
197  * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
198  */
199 static int pmu_type(char *name, __u32 *type)
200 {
201 	struct stat st;
202 	char path[PATH_MAX];
203 	const char *sysfs;
204 	FILE *file;
205 	int ret = 0;
206 
207 	sysfs = sysfs_find_mountpoint();
208 	if (!sysfs)
209 		return -1;
210 
211 	snprintf(path, PATH_MAX,
212 		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
213 
214 	if (stat(path, &st) < 0)
215 		return -1;
216 
217 	file = fopen(path, "r");
218 	if (!file)
219 		return -EINVAL;
220 
221 	if (1 != fscanf(file, "%u", type))
222 		ret = -1;
223 
224 	fclose(file);
225 	return ret;
226 }
227 
228 /* Add all pmus in sysfs to pmu list: */
229 static void pmu_read_sysfs(void)
230 {
231 	char path[PATH_MAX];
232 	const char *sysfs;
233 	DIR *dir;
234 	struct dirent *dent;
235 
236 	sysfs = sysfs_find_mountpoint();
237 	if (!sysfs)
238 		return;
239 
240 	snprintf(path, PATH_MAX,
241 		 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
242 
243 	dir = opendir(path);
244 	if (!dir)
245 		return;
246 
247 	while ((dent = readdir(dir))) {
248 		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
249 			continue;
250 		/* add to static LIST_HEAD(pmus): */
251 		perf_pmu__find(dent->d_name);
252 	}
253 
254 	closedir(dir);
255 }
256 
257 static struct cpu_map *pmu_cpumask(char *name)
258 {
259 	struct stat st;
260 	char path[PATH_MAX];
261 	const char *sysfs;
262 	FILE *file;
263 	struct cpu_map *cpus;
264 
265 	sysfs = sysfs_find_mountpoint();
266 	if (!sysfs)
267 		return NULL;
268 
269 	snprintf(path, PATH_MAX,
270 		 "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
271 
272 	if (stat(path, &st) < 0)
273 		return NULL;
274 
275 	file = fopen(path, "r");
276 	if (!file)
277 		return NULL;
278 
279 	cpus = cpu_map__read(file);
280 	fclose(file);
281 	return cpus;
282 }
283 
284 static struct perf_pmu *pmu_lookup(char *name)
285 {
286 	struct perf_pmu *pmu;
287 	LIST_HEAD(format);
288 	LIST_HEAD(aliases);
289 	__u32 type;
290 
291 	/*
292 	 * The pmu data we store & need consists of the pmu
293 	 * type value and format definitions. Load both right
294 	 * now.
295 	 */
296 	if (pmu_format(name, &format))
297 		return NULL;
298 
299 	if (pmu_aliases(name, &aliases))
300 		return NULL;
301 
302 	if (pmu_type(name, &type))
303 		return NULL;
304 
305 	pmu = zalloc(sizeof(*pmu));
306 	if (!pmu)
307 		return NULL;
308 
309 	pmu->cpus = pmu_cpumask(name);
310 
311 	INIT_LIST_HEAD(&pmu->format);
312 	INIT_LIST_HEAD(&pmu->aliases);
313 	list_splice(&format, &pmu->format);
314 	list_splice(&aliases, &pmu->aliases);
315 	pmu->name = strdup(name);
316 	pmu->type = type;
317 	list_add_tail(&pmu->list, &pmus);
318 	return pmu;
319 }
320 
321 static struct perf_pmu *pmu_find(char *name)
322 {
323 	struct perf_pmu *pmu;
324 
325 	list_for_each_entry(pmu, &pmus, list)
326 		if (!strcmp(pmu->name, name))
327 			return pmu;
328 
329 	return NULL;
330 }
331 
332 struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
333 {
334 	/*
335 	 * pmu iterator: If pmu is NULL, we start at the begin,
336 	 * otherwise return the next pmu. Returns NULL on end.
337 	 */
338 	if (!pmu) {
339 		pmu_read_sysfs();
340 		pmu = list_prepare_entry(pmu, &pmus, list);
341 	}
342 	list_for_each_entry_continue(pmu, &pmus, list)
343 		return pmu;
344 	return NULL;
345 }
346 
347 struct perf_pmu *perf_pmu__find(char *name)
348 {
349 	struct perf_pmu *pmu;
350 
351 	/*
352 	 * Once PMU is loaded it stays in the list,
353 	 * so we keep us from multiple reading/parsing
354 	 * the pmu format definitions.
355 	 */
356 	pmu = pmu_find(name);
357 	if (pmu)
358 		return pmu;
359 
360 	return pmu_lookup(name);
361 }
362 
363 static struct perf_pmu__format*
364 pmu_find_format(struct list_head *formats, char *name)
365 {
366 	struct perf_pmu__format *format;
367 
368 	list_for_each_entry(format, formats, list)
369 		if (!strcmp(format->name, name))
370 			return format;
371 
372 	return NULL;
373 }
374 
375 /*
376  * Returns value based on the format definition (format parameter)
377  * and unformated value (value parameter).
378  *
379  * TODO maybe optimize a little ;)
380  */
381 static __u64 pmu_format_value(unsigned long *format, __u64 value)
382 {
383 	unsigned long fbit, vbit;
384 	__u64 v = 0;
385 
386 	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
387 
388 		if (!test_bit(fbit, format))
389 			continue;
390 
391 		if (!(value & (1llu << vbit++)))
392 			continue;
393 
394 		v |= (1llu << fbit);
395 	}
396 
397 	return v;
398 }
399 
400 /*
401  * Setup one of config[12] attr members based on the
402  * user input data - temr parameter.
403  */
404 static int pmu_config_term(struct list_head *formats,
405 			   struct perf_event_attr *attr,
406 			   struct parse_events__term *term)
407 {
408 	struct perf_pmu__format *format;
409 	__u64 *vp;
410 
411 	/*
412 	 * Support only for hardcoded and numnerial terms.
413 	 * Hardcoded terms should be already in, so nothing
414 	 * to be done for them.
415 	 */
416 	if (parse_events__is_hardcoded_term(term))
417 		return 0;
418 
419 	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
420 		return -EINVAL;
421 
422 	format = pmu_find_format(formats, term->config);
423 	if (!format)
424 		return -EINVAL;
425 
426 	switch (format->value) {
427 	case PERF_PMU_FORMAT_VALUE_CONFIG:
428 		vp = &attr->config;
429 		break;
430 	case PERF_PMU_FORMAT_VALUE_CONFIG1:
431 		vp = &attr->config1;
432 		break;
433 	case PERF_PMU_FORMAT_VALUE_CONFIG2:
434 		vp = &attr->config2;
435 		break;
436 	default:
437 		return -EINVAL;
438 	}
439 
440 	/*
441 	 * XXX If we ever decide to go with string values for
442 	 * non-hardcoded terms, here's the place to translate
443 	 * them into value.
444 	 */
445 	*vp |= pmu_format_value(format->bits, term->val.num);
446 	return 0;
447 }
448 
449 int perf_pmu__config_terms(struct list_head *formats,
450 			   struct perf_event_attr *attr,
451 			   struct list_head *head_terms)
452 {
453 	struct parse_events__term *term;
454 
455 	list_for_each_entry(term, head_terms, list)
456 		if (pmu_config_term(formats, attr, term))
457 			return -EINVAL;
458 
459 	return 0;
460 }
461 
462 /*
463  * Configures event's 'attr' parameter based on the:
464  * 1) users input - specified in terms parameter
465  * 2) pmu format definitions - specified by pmu parameter
466  */
467 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
468 		     struct list_head *head_terms)
469 {
470 	attr->type = pmu->type;
471 	return perf_pmu__config_terms(&pmu->format, attr, head_terms);
472 }
473 
474 static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
475 					      struct parse_events__term *term)
476 {
477 	struct perf_pmu__alias *alias;
478 	char *name;
479 
480 	if (parse_events__is_hardcoded_term(term))
481 		return NULL;
482 
483 	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
484 		if (term->val.num != 1)
485 			return NULL;
486 		if (pmu_find_format(&pmu->format, term->config))
487 			return NULL;
488 		name = term->config;
489 	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
490 		if (strcasecmp(term->config, "event"))
491 			return NULL;
492 		name = term->val.str;
493 	} else {
494 		return NULL;
495 	}
496 
497 	list_for_each_entry(alias, &pmu->aliases, list) {
498 		if (!strcasecmp(alias->name, name))
499 			return alias;
500 	}
501 	return NULL;
502 }
503 
504 /*
505  * Find alias in the terms list and replace it with the terms
506  * defined for the alias
507  */
508 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
509 {
510 	struct parse_events__term *term, *h;
511 	struct perf_pmu__alias *alias;
512 	int ret;
513 
514 	list_for_each_entry_safe(term, h, head_terms, list) {
515 		alias = pmu_find_alias(pmu, term);
516 		if (!alias)
517 			continue;
518 		ret = pmu_alias_terms(alias, &term->list);
519 		if (ret)
520 			return ret;
521 		list_del(&term->list);
522 		free(term);
523 	}
524 	return 0;
525 }
526 
527 int perf_pmu__new_format(struct list_head *list, char *name,
528 			 int config, unsigned long *bits)
529 {
530 	struct perf_pmu__format *format;
531 
532 	format = zalloc(sizeof(*format));
533 	if (!format)
534 		return -ENOMEM;
535 
536 	format->name = strdup(name);
537 	format->value = config;
538 	memcpy(format->bits, bits, sizeof(format->bits));
539 
540 	list_add_tail(&format->list, list);
541 	return 0;
542 }
543 
544 void perf_pmu__set_format(unsigned long *bits, long from, long to)
545 {
546 	long b;
547 
548 	if (!to)
549 		to = from;
550 
551 	memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
552 	for (b = from; b <= to; b++)
553 		set_bit(b, bits);
554 }
555