1 #include <linux/list.h>
2 #include <sys/types.h>
3 #include <unistd.h>
4 #include <stdio.h>
5 #include <stdbool.h>
6 #include <stdarg.h>
7 #include <dirent.h>
8 #include <api/fs/fs.h>
9 #include <locale.h>
10 #include "util.h"
11 #include "pmu.h"
12 #include "parse-events.h"
13 #include "cpumap.h"
14
15 struct perf_pmu_format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20 };
21
22 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
23
24 int perf_pmu_parse(struct list_head *list, char *name);
25 extern FILE *perf_pmu_in;
26
27 static LIST_HEAD(pmus);
28
29 /*
30 * Parse & process all the sysfs attributes located under
31 * the directory specified in 'dir' parameter.
32 */
perf_pmu__format_parse(char * dir,struct list_head * head)33 int perf_pmu__format_parse(char *dir, struct list_head *head)
34 {
35 struct dirent *evt_ent;
36 DIR *format_dir;
37 int ret = 0;
38
39 format_dir = opendir(dir);
40 if (!format_dir)
41 return -EINVAL;
42
43 while (!ret && (evt_ent = readdir(format_dir))) {
44 char path[PATH_MAX];
45 char *name = evt_ent->d_name;
46 FILE *file;
47
48 if (!strcmp(name, ".") || !strcmp(name, ".."))
49 continue;
50
51 snprintf(path, PATH_MAX, "%s/%s", dir, name);
52
53 ret = -EINVAL;
54 file = fopen(path, "r");
55 if (!file)
56 break;
57
58 perf_pmu_in = file;
59 ret = perf_pmu_parse(head, name);
60 fclose(file);
61 }
62
63 closedir(format_dir);
64 return ret;
65 }
66
67 /*
68 * Reading/parsing the default pmu format definition, which should be
69 * located at:
70 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
71 */
pmu_format(const char * name,struct list_head * format)72 static int pmu_format(const char *name, struct list_head *format)
73 {
74 struct stat st;
75 char path[PATH_MAX];
76 const char *sysfs = sysfs__mountpoint();
77
78 if (!sysfs)
79 return -1;
80
81 snprintf(path, PATH_MAX,
82 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
83
84 if (stat(path, &st) < 0)
85 return 0; /* no error if format does not exist */
86
87 if (perf_pmu__format_parse(path, format))
88 return -1;
89
90 return 0;
91 }
92
perf_pmu__parse_scale(struct perf_pmu_alias * alias,char * dir,char * name)93 static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
94 {
95 struct stat st;
96 ssize_t sret;
97 char scale[128];
98 int fd, ret = -1;
99 char path[PATH_MAX];
100 const char *lc;
101
102 snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
103
104 fd = open(path, O_RDONLY);
105 if (fd == -1)
106 return -1;
107
108 if (fstat(fd, &st) < 0)
109 goto error;
110
111 sret = read(fd, scale, sizeof(scale)-1);
112 if (sret < 0)
113 goto error;
114
115 scale[sret] = '\0';
116 /*
117 * save current locale
118 */
119 lc = setlocale(LC_NUMERIC, NULL);
120
121 /*
122 * force to C locale to ensure kernel
123 * scale string is converted correctly.
124 * kernel uses default C locale.
125 */
126 setlocale(LC_NUMERIC, "C");
127
128 alias->scale = strtod(scale, NULL);
129
130 /* restore locale */
131 setlocale(LC_NUMERIC, lc);
132
133 ret = 0;
134 error:
135 close(fd);
136 return ret;
137 }
138
perf_pmu__parse_unit(struct perf_pmu_alias * alias,char * dir,char * name)139 static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
140 {
141 char path[PATH_MAX];
142 ssize_t sret;
143 int fd;
144
145 snprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
146
147 fd = open(path, O_RDONLY);
148 if (fd == -1)
149 return -1;
150
151 sret = read(fd, alias->unit, UNIT_MAX_LEN);
152 if (sret < 0)
153 goto error;
154
155 close(fd);
156
157 alias->unit[sret] = '\0';
158
159 return 0;
160 error:
161 close(fd);
162 alias->unit[0] = '\0';
163 return -1;
164 }
165
166 static int
perf_pmu__parse_per_pkg(struct perf_pmu_alias * alias,char * dir,char * name)167 perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name)
168 {
169 char path[PATH_MAX];
170 int fd;
171
172 snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name);
173
174 fd = open(path, O_RDONLY);
175 if (fd == -1)
176 return -1;
177
178 close(fd);
179
180 alias->per_pkg = true;
181 return 0;
182 }
183
perf_pmu__parse_snapshot(struct perf_pmu_alias * alias,char * dir,char * name)184 static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
185 char *dir, char *name)
186 {
187 char path[PATH_MAX];
188 int fd;
189
190 snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name);
191
192 fd = open(path, O_RDONLY);
193 if (fd == -1)
194 return -1;
195
196 alias->snapshot = true;
197 close(fd);
198 return 0;
199 }
200
perf_pmu__new_alias(struct list_head * list,char * dir,char * name,FILE * file)201 static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
202 {
203 struct perf_pmu_alias *alias;
204 char buf[256];
205 int ret;
206
207 ret = fread(buf, 1, sizeof(buf), file);
208 if (ret == 0)
209 return -EINVAL;
210 buf[ret] = 0;
211
212 alias = malloc(sizeof(*alias));
213 if (!alias)
214 return -ENOMEM;
215
216 INIT_LIST_HEAD(&alias->terms);
217 alias->scale = 1.0;
218 alias->unit[0] = '\0';
219 alias->per_pkg = false;
220
221 ret = parse_events_terms(&alias->terms, buf);
222 if (ret) {
223 free(alias);
224 return ret;
225 }
226
227 alias->name = strdup(name);
228 /*
229 * load unit name and scale if available
230 */
231 perf_pmu__parse_unit(alias, dir, name);
232 perf_pmu__parse_scale(alias, dir, name);
233 perf_pmu__parse_per_pkg(alias, dir, name);
234 perf_pmu__parse_snapshot(alias, dir, name);
235
236 list_add_tail(&alias->list, list);
237
238 return 0;
239 }
240
pmu_alias_info_file(char * name)241 static inline bool pmu_alias_info_file(char *name)
242 {
243 size_t len;
244
245 len = strlen(name);
246 if (len > 5 && !strcmp(name + len - 5, ".unit"))
247 return true;
248 if (len > 6 && !strcmp(name + len - 6, ".scale"))
249 return true;
250 if (len > 8 && !strcmp(name + len - 8, ".per-pkg"))
251 return true;
252 if (len > 9 && !strcmp(name + len - 9, ".snapshot"))
253 return true;
254
255 return false;
256 }
257
258 /*
259 * Process all the sysfs attributes located under the directory
260 * specified in 'dir' parameter.
261 */
pmu_aliases_parse(char * dir,struct list_head * head)262 static int pmu_aliases_parse(char *dir, struct list_head *head)
263 {
264 struct dirent *evt_ent;
265 DIR *event_dir;
266
267 event_dir = opendir(dir);
268 if (!event_dir)
269 return -EINVAL;
270
271 while ((evt_ent = readdir(event_dir))) {
272 char path[PATH_MAX];
273 char *name = evt_ent->d_name;
274 FILE *file;
275
276 if (!strcmp(name, ".") || !strcmp(name, ".."))
277 continue;
278
279 /*
280 * skip info files parsed in perf_pmu__new_alias()
281 */
282 if (pmu_alias_info_file(name))
283 continue;
284
285 snprintf(path, PATH_MAX, "%s/%s", dir, name);
286
287 file = fopen(path, "r");
288 if (!file) {
289 pr_debug("Cannot open %s\n", path);
290 continue;
291 }
292
293 if (perf_pmu__new_alias(head, dir, name, file) < 0)
294 pr_debug("Cannot set up %s\n", name);
295 fclose(file);
296 }
297
298 closedir(event_dir);
299 return 0;
300 }
301
302 /*
303 * Reading the pmu event aliases definition, which should be located at:
304 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
305 */
pmu_aliases(const char * name,struct list_head * head)306 static int pmu_aliases(const char *name, struct list_head *head)
307 {
308 struct stat st;
309 char path[PATH_MAX];
310 const char *sysfs = sysfs__mountpoint();
311
312 if (!sysfs)
313 return -1;
314
315 snprintf(path, PATH_MAX,
316 "%s/bus/event_source/devices/%s/events", sysfs, name);
317
318 if (stat(path, &st) < 0)
319 return 0; /* no error if 'events' does not exist */
320
321 if (pmu_aliases_parse(path, head))
322 return -1;
323
324 return 0;
325 }
326
pmu_alias_terms(struct perf_pmu_alias * alias,struct list_head * terms)327 static int pmu_alias_terms(struct perf_pmu_alias *alias,
328 struct list_head *terms)
329 {
330 struct parse_events_term *term, *cloned;
331 LIST_HEAD(list);
332 int ret;
333
334 list_for_each_entry(term, &alias->terms, list) {
335 ret = parse_events_term__clone(&cloned, term);
336 if (ret) {
337 parse_events__free_terms(&list);
338 return ret;
339 }
340 list_add_tail(&cloned->list, &list);
341 }
342 list_splice(&list, terms);
343 return 0;
344 }
345
346 /*
347 * Reading/parsing the default pmu type value, which should be
348 * located at:
349 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
350 */
pmu_type(const char * name,__u32 * type)351 static int pmu_type(const char *name, __u32 *type)
352 {
353 struct stat st;
354 char path[PATH_MAX];
355 FILE *file;
356 int ret = 0;
357 const char *sysfs = sysfs__mountpoint();
358
359 if (!sysfs)
360 return -1;
361
362 snprintf(path, PATH_MAX,
363 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
364
365 if (stat(path, &st) < 0)
366 return -1;
367
368 file = fopen(path, "r");
369 if (!file)
370 return -EINVAL;
371
372 if (1 != fscanf(file, "%u", type))
373 ret = -1;
374
375 fclose(file);
376 return ret;
377 }
378
379 /* Add all pmus in sysfs to pmu list: */
pmu_read_sysfs(void)380 static void pmu_read_sysfs(void)
381 {
382 char path[PATH_MAX];
383 DIR *dir;
384 struct dirent *dent;
385 const char *sysfs = sysfs__mountpoint();
386
387 if (!sysfs)
388 return;
389
390 snprintf(path, PATH_MAX,
391 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
392
393 dir = opendir(path);
394 if (!dir)
395 return;
396
397 while ((dent = readdir(dir))) {
398 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
399 continue;
400 /* add to static LIST_HEAD(pmus): */
401 perf_pmu__find(dent->d_name);
402 }
403
404 closedir(dir);
405 }
406
pmu_cpumask(const char * name)407 static struct cpu_map *pmu_cpumask(const char *name)
408 {
409 struct stat st;
410 char path[PATH_MAX];
411 FILE *file;
412 struct cpu_map *cpus;
413 const char *sysfs = sysfs__mountpoint();
414
415 if (!sysfs)
416 return NULL;
417
418 snprintf(path, PATH_MAX,
419 "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
420
421 if (stat(path, &st) < 0)
422 return NULL;
423
424 file = fopen(path, "r");
425 if (!file)
426 return NULL;
427
428 cpus = cpu_map__read(file);
429 fclose(file);
430 return cpus;
431 }
432
433 struct perf_event_attr *__attribute__((weak))
perf_pmu__get_default_config(struct perf_pmu * pmu __maybe_unused)434 perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
435 {
436 return NULL;
437 }
438
pmu_lookup(const char * name)439 static struct perf_pmu *pmu_lookup(const char *name)
440 {
441 struct perf_pmu *pmu;
442 LIST_HEAD(format);
443 LIST_HEAD(aliases);
444 __u32 type;
445
446 /*
447 * The pmu data we store & need consists of the pmu
448 * type value and format definitions. Load both right
449 * now.
450 */
451 if (pmu_format(name, &format))
452 return NULL;
453
454 if (pmu_aliases(name, &aliases))
455 return NULL;
456
457 if (pmu_type(name, &type))
458 return NULL;
459
460 pmu = zalloc(sizeof(*pmu));
461 if (!pmu)
462 return NULL;
463
464 pmu->cpus = pmu_cpumask(name);
465
466 INIT_LIST_HEAD(&pmu->format);
467 INIT_LIST_HEAD(&pmu->aliases);
468 list_splice(&format, &pmu->format);
469 list_splice(&aliases, &pmu->aliases);
470 pmu->name = strdup(name);
471 pmu->type = type;
472 list_add_tail(&pmu->list, &pmus);
473
474 pmu->default_config = perf_pmu__get_default_config(pmu);
475
476 return pmu;
477 }
478
pmu_find(const char * name)479 static struct perf_pmu *pmu_find(const char *name)
480 {
481 struct perf_pmu *pmu;
482
483 list_for_each_entry(pmu, &pmus, list)
484 if (!strcmp(pmu->name, name))
485 return pmu;
486
487 return NULL;
488 }
489
perf_pmu__scan(struct perf_pmu * pmu)490 struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
491 {
492 /*
493 * pmu iterator: If pmu is NULL, we start at the begin,
494 * otherwise return the next pmu. Returns NULL on end.
495 */
496 if (!pmu) {
497 pmu_read_sysfs();
498 pmu = list_prepare_entry(pmu, &pmus, list);
499 }
500 list_for_each_entry_continue(pmu, &pmus, list)
501 return pmu;
502 return NULL;
503 }
504
perf_pmu__find(const char * name)505 struct perf_pmu *perf_pmu__find(const char *name)
506 {
507 struct perf_pmu *pmu;
508
509 /*
510 * Once PMU is loaded it stays in the list,
511 * so we keep us from multiple reading/parsing
512 * the pmu format definitions.
513 */
514 pmu = pmu_find(name);
515 if (pmu)
516 return pmu;
517
518 return pmu_lookup(name);
519 }
520
521 static struct perf_pmu_format *
pmu_find_format(struct list_head * formats,char * name)522 pmu_find_format(struct list_head *formats, char *name)
523 {
524 struct perf_pmu_format *format;
525
526 list_for_each_entry(format, formats, list)
527 if (!strcmp(format->name, name))
528 return format;
529
530 return NULL;
531 }
532
533 /*
534 * Sets value based on the format definition (format parameter)
535 * and unformated value (value parameter).
536 */
pmu_format_value(unsigned long * format,__u64 value,__u64 * v,bool zero)537 static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
538 bool zero)
539 {
540 unsigned long fbit, vbit;
541
542 for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
543
544 if (!test_bit(fbit, format))
545 continue;
546
547 if (value & (1llu << vbit++))
548 *v |= (1llu << fbit);
549 else if (zero)
550 *v &= ~(1llu << fbit);
551 }
552 }
553
554 /*
555 * Term is a string term, and might be a param-term. Try to look up it's value
556 * in the remaining terms.
557 * - We have a term like "base-or-format-term=param-term",
558 * - We need to find the value supplied for "param-term" (with param-term named
559 * in a config string) later on in the term list.
560 */
pmu_resolve_param_term(struct parse_events_term * term,struct list_head * head_terms,__u64 * value)561 static int pmu_resolve_param_term(struct parse_events_term *term,
562 struct list_head *head_terms,
563 __u64 *value)
564 {
565 struct parse_events_term *t;
566
567 list_for_each_entry(t, head_terms, list) {
568 if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
569 if (!strcmp(t->config, term->config)) {
570 t->used = true;
571 *value = t->val.num;
572 return 0;
573 }
574 }
575 }
576
577 if (verbose)
578 printf("Required parameter '%s' not specified\n", term->config);
579
580 return -1;
581 }
582
583 /*
584 * Setup one of config[12] attr members based on the
585 * user input data - term parameter.
586 */
pmu_config_term(struct list_head * formats,struct perf_event_attr * attr,struct parse_events_term * term,struct list_head * head_terms,bool zero)587 static int pmu_config_term(struct list_head *formats,
588 struct perf_event_attr *attr,
589 struct parse_events_term *term,
590 struct list_head *head_terms,
591 bool zero)
592 {
593 struct perf_pmu_format *format;
594 __u64 *vp;
595 __u64 val;
596
597 /*
598 * If this is a parameter we've already used for parameterized-eval,
599 * skip it in normal eval.
600 */
601 if (term->used)
602 return 0;
603
604 /*
605 * Hardcoded terms should be already in, so nothing
606 * to be done for them.
607 */
608 if (parse_events__is_hardcoded_term(term))
609 return 0;
610
611 format = pmu_find_format(formats, term->config);
612 if (!format) {
613 if (verbose)
614 printf("Invalid event/parameter '%s'\n", term->config);
615 return -EINVAL;
616 }
617
618 switch (format->value) {
619 case PERF_PMU_FORMAT_VALUE_CONFIG:
620 vp = &attr->config;
621 break;
622 case PERF_PMU_FORMAT_VALUE_CONFIG1:
623 vp = &attr->config1;
624 break;
625 case PERF_PMU_FORMAT_VALUE_CONFIG2:
626 vp = &attr->config2;
627 break;
628 default:
629 return -EINVAL;
630 }
631
632 /*
633 * Either directly use a numeric term, or try to translate string terms
634 * using event parameters.
635 */
636 if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
637 val = term->val.num;
638 else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
639 if (strcmp(term->val.str, "?")) {
640 if (verbose)
641 pr_info("Invalid sysfs entry %s=%s\n",
642 term->config, term->val.str);
643 return -EINVAL;
644 }
645
646 if (pmu_resolve_param_term(term, head_terms, &val))
647 return -EINVAL;
648 } else
649 return -EINVAL;
650
651 pmu_format_value(format->bits, val, vp, zero);
652 return 0;
653 }
654
perf_pmu__config_terms(struct list_head * formats,struct perf_event_attr * attr,struct list_head * head_terms,bool zero)655 int perf_pmu__config_terms(struct list_head *formats,
656 struct perf_event_attr *attr,
657 struct list_head *head_terms,
658 bool zero)
659 {
660 struct parse_events_term *term;
661
662 list_for_each_entry(term, head_terms, list) {
663 if (pmu_config_term(formats, attr, term, head_terms, zero))
664 return -EINVAL;
665 }
666
667 return 0;
668 }
669
670 /*
671 * Configures event's 'attr' parameter based on the:
672 * 1) users input - specified in terms parameter
673 * 2) pmu format definitions - specified by pmu parameter
674 */
perf_pmu__config(struct perf_pmu * pmu,struct perf_event_attr * attr,struct list_head * head_terms)675 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
676 struct list_head *head_terms)
677 {
678 bool zero = !!pmu->default_config;
679
680 attr->type = pmu->type;
681 return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero);
682 }
683
pmu_find_alias(struct perf_pmu * pmu,struct parse_events_term * term)684 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
685 struct parse_events_term *term)
686 {
687 struct perf_pmu_alias *alias;
688 char *name;
689
690 if (parse_events__is_hardcoded_term(term))
691 return NULL;
692
693 if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
694 if (term->val.num != 1)
695 return NULL;
696 if (pmu_find_format(&pmu->format, term->config))
697 return NULL;
698 name = term->config;
699 } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
700 if (strcasecmp(term->config, "event"))
701 return NULL;
702 name = term->val.str;
703 } else {
704 return NULL;
705 }
706
707 list_for_each_entry(alias, &pmu->aliases, list) {
708 if (!strcasecmp(alias->name, name))
709 return alias;
710 }
711 return NULL;
712 }
713
714
check_info_data(struct perf_pmu_alias * alias,struct perf_pmu_info * info)715 static int check_info_data(struct perf_pmu_alias *alias,
716 struct perf_pmu_info *info)
717 {
718 /*
719 * Only one term in event definition can
720 * define unit, scale and snapshot, fail
721 * if there's more than one.
722 */
723 if ((info->unit && alias->unit) ||
724 (info->scale && alias->scale) ||
725 (info->snapshot && alias->snapshot))
726 return -EINVAL;
727
728 if (alias->unit)
729 info->unit = alias->unit;
730
731 if (alias->scale)
732 info->scale = alias->scale;
733
734 if (alias->snapshot)
735 info->snapshot = alias->snapshot;
736
737 return 0;
738 }
739
740 /*
741 * Find alias in the terms list and replace it with the terms
742 * defined for the alias
743 */
perf_pmu__check_alias(struct perf_pmu * pmu,struct list_head * head_terms,struct perf_pmu_info * info)744 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
745 struct perf_pmu_info *info)
746 {
747 struct parse_events_term *term, *h;
748 struct perf_pmu_alias *alias;
749 int ret;
750
751 info->per_pkg = false;
752
753 /*
754 * Mark unit and scale as not set
755 * (different from default values, see below)
756 */
757 info->unit = NULL;
758 info->scale = 0.0;
759 info->snapshot = false;
760
761 list_for_each_entry_safe(term, h, head_terms, list) {
762 alias = pmu_find_alias(pmu, term);
763 if (!alias)
764 continue;
765 ret = pmu_alias_terms(alias, &term->list);
766 if (ret)
767 return ret;
768
769 ret = check_info_data(alias, info);
770 if (ret)
771 return ret;
772
773 if (alias->per_pkg)
774 info->per_pkg = true;
775
776 list_del(&term->list);
777 free(term);
778 }
779
780 /*
781 * if no unit or scale foundin aliases, then
782 * set defaults as for evsel
783 * unit cannot left to NULL
784 */
785 if (info->unit == NULL)
786 info->unit = "";
787
788 if (info->scale == 0.0)
789 info->scale = 1.0;
790
791 return 0;
792 }
793
perf_pmu__new_format(struct list_head * list,char * name,int config,unsigned long * bits)794 int perf_pmu__new_format(struct list_head *list, char *name,
795 int config, unsigned long *bits)
796 {
797 struct perf_pmu_format *format;
798
799 format = zalloc(sizeof(*format));
800 if (!format)
801 return -ENOMEM;
802
803 format->name = strdup(name);
804 format->value = config;
805 memcpy(format->bits, bits, sizeof(format->bits));
806
807 list_add_tail(&format->list, list);
808 return 0;
809 }
810
perf_pmu__set_format(unsigned long * bits,long from,long to)811 void perf_pmu__set_format(unsigned long *bits, long from, long to)
812 {
813 long b;
814
815 if (!to)
816 to = from;
817
818 memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
819 for (b = from; b <= to; b++)
820 set_bit(b, bits);
821 }
822
sub_non_neg(int a,int b)823 static int sub_non_neg(int a, int b)
824 {
825 if (b > a)
826 return 0;
827 return a - b;
828 }
829
format_alias(char * buf,int len,struct perf_pmu * pmu,struct perf_pmu_alias * alias)830 static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
831 struct perf_pmu_alias *alias)
832 {
833 struct parse_events_term *term;
834 int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
835
836 list_for_each_entry(term, &alias->terms, list) {
837 if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
838 used += snprintf(buf + used, sub_non_neg(len, used),
839 ",%s=%s", term->config,
840 term->val.str);
841 }
842
843 if (sub_non_neg(len, used) > 0) {
844 buf[used] = '/';
845 used++;
846 }
847 if (sub_non_neg(len, used) > 0) {
848 buf[used] = '\0';
849 used++;
850 } else
851 buf[len - 1] = '\0';
852
853 return buf;
854 }
855
format_alias_or(char * buf,int len,struct perf_pmu * pmu,struct perf_pmu_alias * alias)856 static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
857 struct perf_pmu_alias *alias)
858 {
859 snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
860 return buf;
861 }
862
cmp_string(const void * a,const void * b)863 static int cmp_string(const void *a, const void *b)
864 {
865 const char * const *as = a;
866 const char * const *bs = b;
867 return strcmp(*as, *bs);
868 }
869
print_pmu_events(const char * event_glob,bool name_only)870 void print_pmu_events(const char *event_glob, bool name_only)
871 {
872 struct perf_pmu *pmu;
873 struct perf_pmu_alias *alias;
874 char buf[1024];
875 int printed = 0;
876 int len, j;
877 char **aliases;
878
879 pmu = NULL;
880 len = 0;
881 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
882 list_for_each_entry(alias, &pmu->aliases, list)
883 len++;
884 if (pmu->selectable)
885 len++;
886 }
887 aliases = zalloc(sizeof(char *) * len);
888 if (!aliases)
889 goto out_enomem;
890 pmu = NULL;
891 j = 0;
892 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
893 list_for_each_entry(alias, &pmu->aliases, list) {
894 char *name = format_alias(buf, sizeof(buf), pmu, alias);
895 bool is_cpu = !strcmp(pmu->name, "cpu");
896
897 if (event_glob != NULL &&
898 !(strglobmatch(name, event_glob) ||
899 (!is_cpu && strglobmatch(alias->name,
900 event_glob))))
901 continue;
902
903 if (is_cpu && !name_only)
904 name = format_alias_or(buf, sizeof(buf), pmu, alias);
905
906 aliases[j] = strdup(name);
907 if (aliases[j] == NULL)
908 goto out_enomem;
909 j++;
910 }
911 if (pmu->selectable) {
912 char *s;
913 if (asprintf(&s, "%s//", pmu->name) < 0)
914 goto out_enomem;
915 aliases[j] = s;
916 j++;
917 }
918 }
919 len = j;
920 qsort(aliases, len, sizeof(char *), cmp_string);
921 for (j = 0; j < len; j++) {
922 if (name_only) {
923 printf("%s ", aliases[j]);
924 continue;
925 }
926 printf(" %-50s [Kernel PMU event]\n", aliases[j]);
927 printed++;
928 }
929 if (printed)
930 printf("\n");
931 out_free:
932 for (j = 0; j < len; j++)
933 zfree(&aliases[j]);
934 zfree(&aliases);
935 return;
936
937 out_enomem:
938 printf("FATAL: not enough memory to print PMU events\n");
939 if (aliases)
940 goto out_free;
941 }
942
pmu_have_event(const char * pname,const char * name)943 bool pmu_have_event(const char *pname, const char *name)
944 {
945 struct perf_pmu *pmu;
946 struct perf_pmu_alias *alias;
947
948 pmu = NULL;
949 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
950 if (strcmp(pname, pmu->name))
951 continue;
952 list_for_each_entry(alias, &pmu->aliases, list)
953 if (!strcmp(alias->name, name))
954 return true;
955 }
956 return false;
957 }
958
perf_pmu__open_file(struct perf_pmu * pmu,const char * name)959 static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
960 {
961 struct stat st;
962 char path[PATH_MAX];
963 const char *sysfs;
964
965 sysfs = sysfs__mountpoint();
966 if (!sysfs)
967 return NULL;
968
969 snprintf(path, PATH_MAX,
970 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
971
972 if (stat(path, &st) < 0)
973 return NULL;
974
975 return fopen(path, "r");
976 }
977
perf_pmu__scan_file(struct perf_pmu * pmu,const char * name,const char * fmt,...)978 int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
979 ...)
980 {
981 va_list args;
982 FILE *file;
983 int ret = EOF;
984
985 va_start(args, fmt);
986 file = perf_pmu__open_file(pmu, name);
987 if (file) {
988 ret = vfscanf(file, fmt, args);
989 fclose(file);
990 }
991 va_end(args);
992 return ret;
993 }
994