1 #include <linux/list.h>
10 #include "parse-events.h"
13 struct perf_pmu_alias
{
15 struct list_head terms
;
16 struct list_head list
;
19 struct perf_pmu_format
{
22 DECLARE_BITMAP(bits
, PERF_PMU_FORMAT_BITS
);
23 struct list_head list
;
26 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
28 int perf_pmu_parse(struct list_head
*list
, char *name
);
29 extern FILE *perf_pmu_in
;
31 static LIST_HEAD(pmus
);
34 * Parse & process all the sysfs attributes located under
35 * the directory specified in 'dir' parameter.
37 int perf_pmu__format_parse(char *dir
, struct list_head
*head
)
39 struct dirent
*evt_ent
;
43 format_dir
= opendir(dir
);
47 while (!ret
&& (evt_ent
= readdir(format_dir
))) {
49 char *name
= evt_ent
->d_name
;
52 if (!strcmp(name
, ".") || !strcmp(name
, ".."))
55 snprintf(path
, PATH_MAX
, "%s/%s", dir
, name
);
58 file
= fopen(path
, "r");
63 ret
= perf_pmu_parse(head
, name
);
72 * Reading/parsing the default pmu format definition, which should be
74 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
76 static int pmu_format(const char *name
, struct list_head
*format
)
82 sysfs
= sysfs_find_mountpoint();
86 snprintf(path
, PATH_MAX
,
87 "%s" EVENT_SOURCE_DEVICE_PATH
"%s/format", sysfs
, name
);
89 if (stat(path
, &st
) < 0)
90 return 0; /* no error if format does not exist */
92 if (perf_pmu__format_parse(path
, format
))
98 static int perf_pmu__new_alias(struct list_head
*list
, char *name
, FILE *file
)
100 struct perf_pmu_alias
*alias
;
104 ret
= fread(buf
, 1, sizeof(buf
), file
);
109 alias
= malloc(sizeof(*alias
));
113 INIT_LIST_HEAD(&alias
->terms
);
114 ret
= parse_events_terms(&alias
->terms
, buf
);
120 alias
->name
= strdup(name
);
121 list_add_tail(&alias
->list
, list
);
126 * Process all the sysfs attributes located under the directory
127 * specified in 'dir' parameter.
129 static int pmu_aliases_parse(char *dir
, struct list_head
*head
)
131 struct dirent
*evt_ent
;
135 event_dir
= opendir(dir
);
139 while (!ret
&& (evt_ent
= readdir(event_dir
))) {
141 char *name
= evt_ent
->d_name
;
144 if (!strcmp(name
, ".") || !strcmp(name
, ".."))
147 snprintf(path
, PATH_MAX
, "%s/%s", dir
, name
);
150 file
= fopen(path
, "r");
153 ret
= perf_pmu__new_alias(head
, name
, file
);
162 * Reading the pmu event aliases definition, which should be located at:
163 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
165 static int pmu_aliases(const char *name
, struct list_head
*head
)
171 sysfs
= sysfs_find_mountpoint();
175 snprintf(path
, PATH_MAX
,
176 "%s/bus/event_source/devices/%s/events", sysfs
, name
);
178 if (stat(path
, &st
) < 0)
179 return 0; /* no error if 'events' does not exist */
181 if (pmu_aliases_parse(path
, head
))
187 static int pmu_alias_terms(struct perf_pmu_alias
*alias
,
188 struct list_head
*terms
)
190 struct parse_events_term
*term
, *clone
;
194 list_for_each_entry(term
, &alias
->terms
, list
) {
195 ret
= parse_events_term__clone(&clone
, term
);
197 parse_events__free_terms(&list
);
200 list_add_tail(&clone
->list
, &list
);
202 list_splice(&list
, terms
);
207 * Reading/parsing the default pmu type value, which should be
209 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
211 static int pmu_type(const char *name
, __u32
*type
)
219 sysfs
= sysfs_find_mountpoint();
223 snprintf(path
, PATH_MAX
,
224 "%s" EVENT_SOURCE_DEVICE_PATH
"%s/type", sysfs
, name
);
226 if (stat(path
, &st
) < 0)
229 file
= fopen(path
, "r");
233 if (1 != fscanf(file
, "%u", type
))
240 /* Add all pmus in sysfs to pmu list: */
241 static void pmu_read_sysfs(void)
248 sysfs
= sysfs_find_mountpoint();
252 snprintf(path
, PATH_MAX
,
253 "%s" EVENT_SOURCE_DEVICE_PATH
, sysfs
);
259 while ((dent
= readdir(dir
))) {
260 if (!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
262 /* add to static LIST_HEAD(pmus): */
263 perf_pmu__find(dent
->d_name
);
269 static struct cpu_map
*pmu_cpumask(const char *name
)
275 struct cpu_map
*cpus
;
277 sysfs
= sysfs_find_mountpoint();
281 snprintf(path
, PATH_MAX
,
282 "%s/bus/event_source/devices/%s/cpumask", sysfs
, name
);
284 if (stat(path
, &st
) < 0)
287 file
= fopen(path
, "r");
291 cpus
= cpu_map__read(file
);
296 static struct perf_pmu
*pmu_lookup(const char *name
)
298 struct perf_pmu
*pmu
;
304 * The pmu data we store & need consists of the pmu
305 * type value and format definitions. Load both right
308 if (pmu_format(name
, &format
))
311 if (pmu_aliases(name
, &aliases
))
314 if (pmu_type(name
, &type
))
317 pmu
= zalloc(sizeof(*pmu
));
321 pmu
->cpus
= pmu_cpumask(name
);
323 INIT_LIST_HEAD(&pmu
->format
);
324 INIT_LIST_HEAD(&pmu
->aliases
);
325 list_splice(&format
, &pmu
->format
);
326 list_splice(&aliases
, &pmu
->aliases
);
327 pmu
->name
= strdup(name
);
329 list_add_tail(&pmu
->list
, &pmus
);
333 static struct perf_pmu
*pmu_find(const char *name
)
335 struct perf_pmu
*pmu
;
337 list_for_each_entry(pmu
, &pmus
, list
)
338 if (!strcmp(pmu
->name
, name
))
344 struct perf_pmu
*perf_pmu__scan(struct perf_pmu
*pmu
)
347 * pmu iterator: If pmu is NULL, we start at the begin,
348 * otherwise return the next pmu. Returns NULL on end.
352 pmu
= list_prepare_entry(pmu
, &pmus
, list
);
354 list_for_each_entry_continue(pmu
, &pmus
, list
)
359 struct perf_pmu
*perf_pmu__find(const char *name
)
361 struct perf_pmu
*pmu
;
364 * Once PMU is loaded it stays in the list,
365 * so we keep us from multiple reading/parsing
366 * the pmu format definitions.
368 pmu
= pmu_find(name
);
372 return pmu_lookup(name
);
375 static struct perf_pmu_format
*
376 pmu_find_format(struct list_head
*formats
, char *name
)
378 struct perf_pmu_format
*format
;
380 list_for_each_entry(format
, formats
, list
)
381 if (!strcmp(format
->name
, name
))
388 * Returns value based on the format definition (format parameter)
389 * and unformated value (value parameter).
391 * TODO maybe optimize a little ;)
393 static __u64
pmu_format_value(unsigned long *format
, __u64 value
)
395 unsigned long fbit
, vbit
;
398 for (fbit
= 0, vbit
= 0; fbit
< PERF_PMU_FORMAT_BITS
; fbit
++) {
400 if (!test_bit(fbit
, format
))
403 if (!(value
& (1llu << vbit
++)))
413 * Setup one of config[12] attr members based on the
414 * user input data - temr parameter.
416 static int pmu_config_term(struct list_head
*formats
,
417 struct perf_event_attr
*attr
,
418 struct parse_events_term
*term
)
420 struct perf_pmu_format
*format
;
424 * Support only for hardcoded and numnerial terms.
425 * Hardcoded terms should be already in, so nothing
426 * to be done for them.
428 if (parse_events__is_hardcoded_term(term
))
431 if (term
->type_val
!= PARSE_EVENTS__TERM_TYPE_NUM
)
434 format
= pmu_find_format(formats
, term
->config
);
438 switch (format
->value
) {
439 case PERF_PMU_FORMAT_VALUE_CONFIG
:
442 case PERF_PMU_FORMAT_VALUE_CONFIG1
:
445 case PERF_PMU_FORMAT_VALUE_CONFIG2
:
453 * XXX If we ever decide to go with string values for
454 * non-hardcoded terms, here's the place to translate
457 *vp
|= pmu_format_value(format
->bits
, term
->val
.num
);
461 int perf_pmu__config_terms(struct list_head
*formats
,
462 struct perf_event_attr
*attr
,
463 struct list_head
*head_terms
)
465 struct parse_events_term
*term
;
467 list_for_each_entry(term
, head_terms
, list
)
468 if (pmu_config_term(formats
, attr
, term
))
475 * Configures event's 'attr' parameter based on the:
476 * 1) users input - specified in terms parameter
477 * 2) pmu format definitions - specified by pmu parameter
479 int perf_pmu__config(struct perf_pmu
*pmu
, struct perf_event_attr
*attr
,
480 struct list_head
*head_terms
)
482 attr
->type
= pmu
->type
;
483 return perf_pmu__config_terms(&pmu
->format
, attr
, head_terms
);
486 static struct perf_pmu_alias
*pmu_find_alias(struct perf_pmu
*pmu
,
487 struct parse_events_term
*term
)
489 struct perf_pmu_alias
*alias
;
492 if (parse_events__is_hardcoded_term(term
))
495 if (term
->type_val
== PARSE_EVENTS__TERM_TYPE_NUM
) {
496 if (term
->val
.num
!= 1)
498 if (pmu_find_format(&pmu
->format
, term
->config
))
501 } else if (term
->type_val
== PARSE_EVENTS__TERM_TYPE_STR
) {
502 if (strcasecmp(term
->config
, "event"))
504 name
= term
->val
.str
;
509 list_for_each_entry(alias
, &pmu
->aliases
, list
) {
510 if (!strcasecmp(alias
->name
, name
))
517 * Find alias in the terms list and replace it with the terms
518 * defined for the alias
520 int perf_pmu__check_alias(struct perf_pmu
*pmu
, struct list_head
*head_terms
)
522 struct parse_events_term
*term
, *h
;
523 struct perf_pmu_alias
*alias
;
526 list_for_each_entry_safe(term
, h
, head_terms
, list
) {
527 alias
= pmu_find_alias(pmu
, term
);
530 ret
= pmu_alias_terms(alias
, &term
->list
);
533 list_del(&term
->list
);
539 int perf_pmu__new_format(struct list_head
*list
, char *name
,
540 int config
, unsigned long *bits
)
542 struct perf_pmu_format
*format
;
544 format
= zalloc(sizeof(*format
));
548 format
->name
= strdup(name
);
549 format
->value
= config
;
550 memcpy(format
->bits
, bits
, sizeof(format
->bits
));
552 list_add_tail(&format
->list
, list
);
556 void perf_pmu__set_format(unsigned long *bits
, long from
, long to
)
563 memset(bits
, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS
));
564 for (b
= from
; b
<= to
; b
++)
568 static char *format_alias(char *buf
, int len
, struct perf_pmu
*pmu
,
569 struct perf_pmu_alias
*alias
)
571 snprintf(buf
, len
, "%s/%s/", pmu
->name
, alias
->name
);
575 static char *format_alias_or(char *buf
, int len
, struct perf_pmu
*pmu
,
576 struct perf_pmu_alias
*alias
)
578 snprintf(buf
, len
, "%s OR %s/%s/", alias
->name
, pmu
->name
, alias
->name
);
582 static int cmp_string(const void *a
, const void *b
)
584 const char * const *as
= a
;
585 const char * const *bs
= b
;
586 return strcmp(*as
, *bs
);
589 void print_pmu_events(const char *event_glob
, bool name_only
)
591 struct perf_pmu
*pmu
;
592 struct perf_pmu_alias
*alias
;
600 while ((pmu
= perf_pmu__scan(pmu
)) != NULL
)
601 list_for_each_entry(alias
, &pmu
->aliases
, list
)
603 aliases
= malloc(sizeof(char *) * len
);
608 while ((pmu
= perf_pmu__scan(pmu
)) != NULL
)
609 list_for_each_entry(alias
, &pmu
->aliases
, list
) {
610 char *name
= format_alias(buf
, sizeof(buf
), pmu
, alias
);
611 bool is_cpu
= !strcmp(pmu
->name
, "cpu");
613 if (event_glob
!= NULL
&&
614 !(strglobmatch(name
, event_glob
) ||
615 (!is_cpu
&& strglobmatch(alias
->name
,
619 if (is_cpu
&& !name_only
)
620 aliases
[j
] = format_alias_or(buf
, sizeof(buf
),
622 aliases
[j
] = strdup(aliases
[j
]);
626 qsort(aliases
, len
, sizeof(char *), cmp_string
);
627 for (j
= 0; j
< len
; j
++) {
629 printf("%s ", aliases
[j
]);
632 printf(" %-50s [Kernel PMU event]\n", aliases
[j
]);