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