xref: /linux/tools/perf/util/pmus.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/list.h>
3 #include <linux/list_sort.h>
4 #include <linux/string.h>
5 #include <linux/zalloc.h>
6 #include <subcmd/pager.h>
7 #include <sys/types.h>
8 #include <ctype.h>
9 #include <dirent.h>
10 #include <pthread.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include "cpumap.h"
14 #include "debug.h"
15 #include "evsel.h"
16 #include "pmus.h"
17 #include "pmu.h"
18 #include "print-events.h"
19 #include "strbuf.h"
20 
21 /*
22  * core_pmus:  A PMU belongs to core_pmus if it's name is "cpu" or it's sysfs
23  *             directory contains "cpus" file. All PMUs belonging to core_pmus
24  *             must have pmu->is_core=1. If there are more than one PMU in
25  *             this list, perf interprets it as a heterogeneous platform.
26  *             (FWIW, certain ARM platforms having heterogeneous cores uses
27  *             homogeneous PMU, and thus they are treated as homogeneous
28  *             platform by perf because core_pmus will have only one entry)
29  * other_pmus: All other PMUs which are not part of core_pmus list. It doesn't
30  *             matter whether PMU is present per SMT-thread or outside of the
31  *             core in the hw. For e.g., an instance of AMD ibs_fetch// and
32  *             ibs_op// PMUs is present in each hw SMT thread, however they
33  *             are captured under other_pmus. PMUs belonging to other_pmus
34  *             must have pmu->is_core=0 but pmu->is_uncore could be 0 or 1.
35  */
36 static LIST_HEAD(core_pmus);
37 static LIST_HEAD(other_pmus);
38 static bool read_sysfs_core_pmus;
39 static bool read_sysfs_all_pmus;
40 
41 static void pmu_read_sysfs(bool core_only);
42 
pmu_name_len_no_suffix(const char * str)43 size_t pmu_name_len_no_suffix(const char *str)
44 {
45 	int orig_len, len;
46 	bool has_hex_digits = false;
47 
48 	orig_len = len = strlen(str);
49 
50 	/* Count trailing digits. */
51 	while (len > 0 && isxdigit(str[len - 1])) {
52 		if (!isdigit(str[len - 1]))
53 			has_hex_digits = true;
54 		len--;
55 	}
56 
57 	if (len > 0 && len != orig_len && str[len - 1] == '_') {
58 		/*
59 		 * There is a '_{num}' suffix. For decimal suffixes any length
60 		 * will do, for hexadecimal ensure more than 2 hex digits so
61 		 * that S390's cpum_cf PMU doesn't match.
62 		 */
63 		if (!has_hex_digits || (orig_len - len) > 2)
64 			return len - 1;
65 	}
66 	/* Use the full length. */
67 	return orig_len;
68 }
69 
pmu_name_cmp(const char * lhs_pmu_name,const char * rhs_pmu_name)70 int pmu_name_cmp(const char *lhs_pmu_name, const char *rhs_pmu_name)
71 {
72 	unsigned long lhs_num = 0, rhs_num = 0;
73 	size_t lhs_pmu_name_len = pmu_name_len_no_suffix(lhs_pmu_name);
74 	size_t rhs_pmu_name_len = pmu_name_len_no_suffix(rhs_pmu_name);
75 	int ret = strncmp(lhs_pmu_name, rhs_pmu_name,
76 			lhs_pmu_name_len < rhs_pmu_name_len ? lhs_pmu_name_len : rhs_pmu_name_len);
77 
78 	if (lhs_pmu_name_len != rhs_pmu_name_len || ret != 0 || lhs_pmu_name_len == 0)
79 		return ret;
80 
81 	if (lhs_pmu_name_len + 1 < strlen(lhs_pmu_name))
82 		lhs_num = strtoul(&lhs_pmu_name[lhs_pmu_name_len + 1], NULL, 16);
83 	if (rhs_pmu_name_len + 1 < strlen(rhs_pmu_name))
84 		rhs_num = strtoul(&rhs_pmu_name[rhs_pmu_name_len + 1], NULL, 16);
85 
86 	return lhs_num < rhs_num ? -1 : (lhs_num > rhs_num ? 1 : 0);
87 }
88 
perf_pmus__destroy(void)89 void perf_pmus__destroy(void)
90 {
91 	struct perf_pmu *pmu, *tmp;
92 
93 	list_for_each_entry_safe(pmu, tmp, &core_pmus, list) {
94 		list_del(&pmu->list);
95 
96 		perf_pmu__delete(pmu);
97 	}
98 	list_for_each_entry_safe(pmu, tmp, &other_pmus, list) {
99 		list_del(&pmu->list);
100 
101 		perf_pmu__delete(pmu);
102 	}
103 	read_sysfs_core_pmus = false;
104 	read_sysfs_all_pmus = false;
105 }
106 
pmu_find(const char * name)107 static struct perf_pmu *pmu_find(const char *name)
108 {
109 	struct perf_pmu *pmu;
110 
111 	list_for_each_entry(pmu, &core_pmus, list) {
112 		if (!strcmp(pmu->name, name) ||
113 		    (pmu->alias_name && !strcmp(pmu->alias_name, name)))
114 			return pmu;
115 	}
116 	list_for_each_entry(pmu, &other_pmus, list) {
117 		if (!strcmp(pmu->name, name) ||
118 		    (pmu->alias_name && !strcmp(pmu->alias_name, name)))
119 			return pmu;
120 	}
121 
122 	return NULL;
123 }
124 
perf_pmus__find(const char * name)125 struct perf_pmu *perf_pmus__find(const char *name)
126 {
127 	struct perf_pmu *pmu;
128 	int dirfd;
129 	bool core_pmu;
130 
131 	/*
132 	 * Once PMU is loaded it stays in the list,
133 	 * so we keep us from multiple reading/parsing
134 	 * the pmu format definitions.
135 	 */
136 	pmu = pmu_find(name);
137 	if (pmu)
138 		return pmu;
139 
140 	if (read_sysfs_all_pmus)
141 		return NULL;
142 
143 	core_pmu = is_pmu_core(name);
144 	if (core_pmu && read_sysfs_core_pmus)
145 		return NULL;
146 
147 	dirfd = perf_pmu__event_source_devices_fd();
148 	pmu = perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name,
149 			       /*eager_load=*/false);
150 	close(dirfd);
151 
152 	if (!pmu) {
153 		/*
154 		 * Looking up an inidividual PMU failed. This may mean name is
155 		 * an alias, so read the PMUs from sysfs and try to find again.
156 		 */
157 		pmu_read_sysfs(core_pmu);
158 		pmu = pmu_find(name);
159 	}
160 	return pmu;
161 }
162 
perf_pmu__find2(int dirfd,const char * name)163 static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)
164 {
165 	struct perf_pmu *pmu;
166 	bool core_pmu;
167 
168 	/*
169 	 * Once PMU is loaded it stays in the list,
170 	 * so we keep us from multiple reading/parsing
171 	 * the pmu format definitions.
172 	 */
173 	pmu = pmu_find(name);
174 	if (pmu)
175 		return pmu;
176 
177 	if (read_sysfs_all_pmus)
178 		return NULL;
179 
180 	core_pmu = is_pmu_core(name);
181 	if (core_pmu && read_sysfs_core_pmus)
182 		return NULL;
183 
184 	return perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name,
185 				/*eager_load=*/false);
186 }
187 
pmus_cmp(void * priv __maybe_unused,const struct list_head * lhs,const struct list_head * rhs)188 static int pmus_cmp(void *priv __maybe_unused,
189 		    const struct list_head *lhs, const struct list_head *rhs)
190 {
191 	struct perf_pmu *lhs_pmu = container_of(lhs, struct perf_pmu, list);
192 	struct perf_pmu *rhs_pmu = container_of(rhs, struct perf_pmu, list);
193 
194 	return pmu_name_cmp(lhs_pmu->name ?: "", rhs_pmu->name ?: "");
195 }
196 
197 /* Add all pmus in sysfs to pmu list: */
pmu_read_sysfs(bool core_only)198 static void pmu_read_sysfs(bool core_only)
199 {
200 	int fd;
201 	DIR *dir;
202 	struct dirent *dent;
203 
204 	if (read_sysfs_all_pmus || (core_only && read_sysfs_core_pmus))
205 		return;
206 
207 	fd = perf_pmu__event_source_devices_fd();
208 	if (fd < 0)
209 		return;
210 
211 	dir = fdopendir(fd);
212 	if (!dir) {
213 		close(fd);
214 		return;
215 	}
216 
217 	while ((dent = readdir(dir))) {
218 		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
219 			continue;
220 		if (core_only && !is_pmu_core(dent->d_name))
221 			continue;
222 		/* add to static LIST_HEAD(core_pmus) or LIST_HEAD(other_pmus): */
223 		perf_pmu__find2(fd, dent->d_name);
224 	}
225 
226 	closedir(dir);
227 	if (list_empty(&core_pmus)) {
228 		if (!perf_pmu__create_placeholder_core_pmu(&core_pmus))
229 			pr_err("Failure to set up any core PMUs\n");
230 	}
231 	list_sort(NULL, &core_pmus, pmus_cmp);
232 	list_sort(NULL, &other_pmus, pmus_cmp);
233 	if (!list_empty(&core_pmus)) {
234 		read_sysfs_core_pmus = true;
235 		if (!core_only)
236 			read_sysfs_all_pmus = true;
237 	}
238 }
239 
__perf_pmus__find_by_type(unsigned int type)240 static struct perf_pmu *__perf_pmus__find_by_type(unsigned int type)
241 {
242 	struct perf_pmu *pmu;
243 
244 	list_for_each_entry(pmu, &core_pmus, list) {
245 		if (pmu->type == type)
246 			return pmu;
247 	}
248 
249 	list_for_each_entry(pmu, &other_pmus, list) {
250 		if (pmu->type == type)
251 			return pmu;
252 	}
253 	return NULL;
254 }
255 
perf_pmus__find_by_type(unsigned int type)256 struct perf_pmu *perf_pmus__find_by_type(unsigned int type)
257 {
258 	struct perf_pmu *pmu = __perf_pmus__find_by_type(type);
259 
260 	if (pmu || read_sysfs_all_pmus)
261 		return pmu;
262 
263 	pmu_read_sysfs(/*core_only=*/false);
264 	pmu = __perf_pmus__find_by_type(type);
265 	return pmu;
266 }
267 
268 /*
269  * pmu iterator: If pmu is NULL, we start at the begin, otherwise return the
270  * next pmu. Returns NULL on end.
271  */
perf_pmus__scan(struct perf_pmu * pmu)272 struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu)
273 {
274 	bool use_core_pmus = !pmu || pmu->is_core;
275 
276 	if (!pmu) {
277 		pmu_read_sysfs(/*core_only=*/false);
278 		pmu = list_prepare_entry(pmu, &core_pmus, list);
279 	}
280 	if (use_core_pmus) {
281 		list_for_each_entry_continue(pmu, &core_pmus, list)
282 			return pmu;
283 
284 		pmu = NULL;
285 		pmu = list_prepare_entry(pmu, &other_pmus, list);
286 	}
287 	list_for_each_entry_continue(pmu, &other_pmus, list)
288 		return pmu;
289 	return NULL;
290 }
291 
perf_pmus__scan_core(struct perf_pmu * pmu)292 struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu)
293 {
294 	if (!pmu) {
295 		pmu_read_sysfs(/*core_only=*/true);
296 		return list_first_entry_or_null(&core_pmus, typeof(*pmu), list);
297 	}
298 	list_for_each_entry_continue(pmu, &core_pmus, list)
299 		return pmu;
300 
301 	return NULL;
302 }
303 
perf_pmus__scan_skip_duplicates(struct perf_pmu * pmu)304 static struct perf_pmu *perf_pmus__scan_skip_duplicates(struct perf_pmu *pmu)
305 {
306 	bool use_core_pmus = !pmu || pmu->is_core;
307 	int last_pmu_name_len = 0;
308 	const char *last_pmu_name = (pmu && pmu->name) ? pmu->name : "";
309 
310 	if (!pmu) {
311 		pmu_read_sysfs(/*core_only=*/false);
312 		pmu = list_prepare_entry(pmu, &core_pmus, list);
313 	} else
314 		last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");
315 
316 	if (use_core_pmus) {
317 		list_for_each_entry_continue(pmu, &core_pmus, list) {
318 			int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");
319 
320 			if (last_pmu_name_len == pmu_name_len &&
321 			    !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len))
322 				continue;
323 
324 			return pmu;
325 		}
326 		pmu = NULL;
327 		pmu = list_prepare_entry(pmu, &other_pmus, list);
328 	}
329 	list_for_each_entry_continue(pmu, &other_pmus, list) {
330 		int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");
331 
332 		if (last_pmu_name_len == pmu_name_len &&
333 		    !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len))
334 			continue;
335 
336 		return pmu;
337 	}
338 	return NULL;
339 }
340 
perf_pmus__pmu_for_pmu_filter(const char * str)341 const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str)
342 {
343 	struct perf_pmu *pmu = NULL;
344 
345 	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
346 		if (!strcmp(pmu->name, str))
347 			return pmu;
348 		/* Ignore "uncore_" prefix. */
349 		if (!strncmp(pmu->name, "uncore_", 7)) {
350 			if (!strcmp(pmu->name + 7, str))
351 				return pmu;
352 		}
353 		/* Ignore "cpu_" prefix on Intel hybrid PMUs. */
354 		if (!strncmp(pmu->name, "cpu_", 4)) {
355 			if (!strcmp(pmu->name + 4, str))
356 				return pmu;
357 		}
358 	}
359 	return NULL;
360 }
361 
362 /** Struct for ordering events as output in perf list. */
363 struct sevent {
364 	/** PMU for event. */
365 	const struct perf_pmu *pmu;
366 	const char *name;
367 	const char* alias;
368 	const char *scale_unit;
369 	const char *desc;
370 	const char *long_desc;
371 	const char *encoding_desc;
372 	const char *topic;
373 	const char *pmu_name;
374 	bool deprecated;
375 };
376 
cmp_sevent(const void * a,const void * b)377 static int cmp_sevent(const void *a, const void *b)
378 {
379 	const struct sevent *as = a;
380 	const struct sevent *bs = b;
381 	bool a_iscpu, b_iscpu;
382 	int ret;
383 
384 	/* Put extra events last. */
385 	if (!!as->desc != !!bs->desc)
386 		return !!as->desc - !!bs->desc;
387 
388 	/* Order by topics. */
389 	ret = strcmp(as->topic ?: "", bs->topic ?: "");
390 	if (ret)
391 		return ret;
392 
393 	/* Order CPU core events to be first */
394 	a_iscpu = as->pmu ? as->pmu->is_core : true;
395 	b_iscpu = bs->pmu ? bs->pmu->is_core : true;
396 	if (a_iscpu != b_iscpu)
397 		return a_iscpu ? -1 : 1;
398 
399 	/* Order by PMU name. */
400 	if (as->pmu != bs->pmu) {
401 		ret = strcmp(as->pmu_name ?: "", bs->pmu_name ?: "");
402 		if (ret)
403 			return ret;
404 	}
405 
406 	/* Order by event name. */
407 	return strcmp(as->name, bs->name);
408 }
409 
pmu_alias_is_duplicate(struct sevent * a,struct sevent * b)410 static bool pmu_alias_is_duplicate(struct sevent *a, struct sevent *b)
411 {
412 	/* Different names -> never duplicates */
413 	if (strcmp(a->name ?: "//", b->name ?: "//"))
414 		return false;
415 
416 	/* Don't remove duplicates for different PMUs */
417 	return strcmp(a->pmu_name, b->pmu_name) == 0;
418 }
419 
420 struct events_callback_state {
421 	struct sevent *aliases;
422 	size_t aliases_len;
423 	size_t index;
424 };
425 
perf_pmus__print_pmu_events__callback(void * vstate,struct pmu_event_info * info)426 static int perf_pmus__print_pmu_events__callback(void *vstate,
427 						struct pmu_event_info *info)
428 {
429 	struct events_callback_state *state = vstate;
430 	struct sevent *s;
431 
432 	if (state->index >= state->aliases_len) {
433 		pr_err("Unexpected event %s/%s/\n", info->pmu->name, info->name);
434 		return 1;
435 	}
436 	s = &state->aliases[state->index];
437 	s->pmu = info->pmu;
438 #define COPY_STR(str) s->str = info->str ? strdup(info->str) : NULL
439 	COPY_STR(name);
440 	COPY_STR(alias);
441 	COPY_STR(scale_unit);
442 	COPY_STR(desc);
443 	COPY_STR(long_desc);
444 	COPY_STR(encoding_desc);
445 	COPY_STR(topic);
446 	COPY_STR(pmu_name);
447 #undef COPY_STR
448 	s->deprecated = info->deprecated;
449 	state->index++;
450 	return 0;
451 }
452 
perf_pmus__print_pmu_events(const struct print_callbacks * print_cb,void * print_state)453 void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
454 {
455 	struct perf_pmu *pmu;
456 	int printed = 0;
457 	int len;
458 	struct sevent *aliases;
459 	struct events_callback_state state;
460 	bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state);
461 	struct perf_pmu *(*scan_fn)(struct perf_pmu *);
462 
463 	if (skip_duplicate_pmus)
464 		scan_fn = perf_pmus__scan_skip_duplicates;
465 	else
466 		scan_fn = perf_pmus__scan;
467 
468 	pmu = NULL;
469 	len = 0;
470 	while ((pmu = scan_fn(pmu)) != NULL)
471 		len += perf_pmu__num_events(pmu);
472 
473 	aliases = zalloc(sizeof(struct sevent) * len);
474 	if (!aliases) {
475 		pr_err("FATAL: not enough memory to print PMU events\n");
476 		return;
477 	}
478 	pmu = NULL;
479 	state = (struct events_callback_state) {
480 		.aliases = aliases,
481 		.aliases_len = len,
482 		.index = 0,
483 	};
484 	while ((pmu = scan_fn(pmu)) != NULL) {
485 		perf_pmu__for_each_event(pmu, skip_duplicate_pmus, &state,
486 					 perf_pmus__print_pmu_events__callback);
487 	}
488 	qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
489 	for (int j = 0; j < len; j++) {
490 		/* Skip duplicates */
491 		if (j < len - 1 && pmu_alias_is_duplicate(&aliases[j], &aliases[j + 1]))
492 			goto free;
493 
494 		print_cb->print_event(print_state,
495 				aliases[j].pmu_name,
496 				aliases[j].topic,
497 				aliases[j].name,
498 				aliases[j].alias,
499 				aliases[j].scale_unit,
500 				aliases[j].deprecated,
501 				"Kernel PMU event",
502 				aliases[j].desc,
503 				aliases[j].long_desc,
504 				aliases[j].encoding_desc);
505 free:
506 		zfree(&aliases[j].name);
507 		zfree(&aliases[j].alias);
508 		zfree(&aliases[j].scale_unit);
509 		zfree(&aliases[j].desc);
510 		zfree(&aliases[j].long_desc);
511 		zfree(&aliases[j].encoding_desc);
512 		zfree(&aliases[j].topic);
513 		zfree(&aliases[j].pmu_name);
514 	}
515 	if (printed && pager_in_use())
516 		printf("\n");
517 
518 	zfree(&aliases);
519 }
520 
521 struct build_format_string_args {
522 	struct strbuf short_string;
523 	struct strbuf long_string;
524 	int num_formats;
525 };
526 
build_format_string(void * state,const char * name,int config,const unsigned long * bits)527 static int build_format_string(void *state, const char *name, int config,
528 			       const unsigned long *bits)
529 {
530 	struct build_format_string_args *args = state;
531 	unsigned int num_bits;
532 	int ret1, ret2 = 0;
533 
534 	(void)config;
535 	args->num_formats++;
536 	if (args->num_formats > 1) {
537 		strbuf_addch(&args->long_string, ',');
538 		if (args->num_formats < 4)
539 			strbuf_addch(&args->short_string, ',');
540 	}
541 	num_bits = bits ? bitmap_weight(bits, PERF_PMU_FORMAT_BITS) : 0;
542 	if (num_bits <= 1) {
543 		ret1 = strbuf_addf(&args->long_string, "%s", name);
544 		if (args->num_formats < 4)
545 			ret2 = strbuf_addf(&args->short_string, "%s", name);
546 	} else if (num_bits > 8) {
547 		ret1 = strbuf_addf(&args->long_string, "%s=0..0x%llx", name,
548 				   ULLONG_MAX >> (64 - num_bits));
549 		if (args->num_formats < 4) {
550 			ret2 = strbuf_addf(&args->short_string, "%s=0..0x%llx", name,
551 					   ULLONG_MAX >> (64 - num_bits));
552 		}
553 	} else {
554 		ret1 = strbuf_addf(&args->long_string, "%s=0..%llu", name,
555 				  ULLONG_MAX >> (64 - num_bits));
556 		if (args->num_formats < 4) {
557 			ret2 = strbuf_addf(&args->short_string, "%s=0..%llu", name,
558 					   ULLONG_MAX >> (64 - num_bits));
559 		}
560 	}
561 	return ret1 < 0 ? ret1 : (ret2 < 0 ? ret2 : 0);
562 }
563 
perf_pmus__print_raw_pmu_events(const struct print_callbacks * print_cb,void * print_state)564 void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state)
565 {
566 	bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state);
567 	struct perf_pmu *(*scan_fn)(struct perf_pmu *);
568 	struct perf_pmu *pmu = NULL;
569 
570 	if (skip_duplicate_pmus)
571 		scan_fn = perf_pmus__scan_skip_duplicates;
572 	else
573 		scan_fn = perf_pmus__scan;
574 
575 	while ((pmu = scan_fn(pmu)) != NULL) {
576 		struct build_format_string_args format_args = {
577 			.short_string = STRBUF_INIT,
578 			.long_string = STRBUF_INIT,
579 			.num_formats = 0,
580 		};
581 		int len = pmu_name_len_no_suffix(pmu->name);
582 		const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";
583 
584 		if (!pmu->is_core)
585 			desc = NULL;
586 
587 		strbuf_addf(&format_args.short_string, "%.*s/", len, pmu->name);
588 		strbuf_addf(&format_args.long_string, "%.*s/", len, pmu->name);
589 		perf_pmu__for_each_format(pmu, &format_args, build_format_string);
590 
591 		if (format_args.num_formats > 3)
592 			strbuf_addf(&format_args.short_string, ",.../modifier");
593 		else
594 			strbuf_addf(&format_args.short_string, "/modifier");
595 
596 		strbuf_addf(&format_args.long_string, "/modifier");
597 		print_cb->print_event(print_state,
598 				/*topic=*/NULL,
599 				/*pmu_name=*/NULL,
600 				format_args.short_string.buf,
601 				/*event_alias=*/NULL,
602 				/*scale_unit=*/NULL,
603 				/*deprecated=*/false,
604 				"Raw event descriptor",
605 				desc,
606 				/*long_desc=*/NULL,
607 				format_args.long_string.buf);
608 
609 		strbuf_release(&format_args.short_string);
610 		strbuf_release(&format_args.long_string);
611 	}
612 }
613 
perf_pmus__have_event(const char * pname,const char * name)614 bool perf_pmus__have_event(const char *pname, const char *name)
615 {
616 	struct perf_pmu *pmu = perf_pmus__find(pname);
617 
618 	return pmu && perf_pmu__have_event(pmu, name);
619 }
620 
perf_pmus__num_core_pmus(void)621 int perf_pmus__num_core_pmus(void)
622 {
623 	static int count;
624 
625 	if (!count) {
626 		struct perf_pmu *pmu = NULL;
627 
628 		while ((pmu = perf_pmus__scan_core(pmu)) != NULL)
629 			count++;
630 	}
631 	return count;
632 }
633 
__perf_pmus__supports_extended_type(void)634 static bool __perf_pmus__supports_extended_type(void)
635 {
636 	struct perf_pmu *pmu = NULL;
637 
638 	if (perf_pmus__num_core_pmus() <= 1)
639 		return false;
640 
641 	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
642 		if (!is_event_supported(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES | ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)))
643 			return false;
644 	}
645 
646 	return true;
647 }
648 
649 static bool perf_pmus__do_support_extended_type;
650 
perf_pmus__init_supports_extended_type(void)651 static void perf_pmus__init_supports_extended_type(void)
652 {
653 	perf_pmus__do_support_extended_type = __perf_pmus__supports_extended_type();
654 }
655 
perf_pmus__supports_extended_type(void)656 bool perf_pmus__supports_extended_type(void)
657 {
658 	static pthread_once_t extended_type_once = PTHREAD_ONCE_INIT;
659 
660 	pthread_once(&extended_type_once, perf_pmus__init_supports_extended_type);
661 
662 	return perf_pmus__do_support_extended_type;
663 }
664 
perf_pmus__default_pmu_name(void)665 char *perf_pmus__default_pmu_name(void)
666 {
667 	int fd;
668 	DIR *dir;
669 	struct dirent *dent;
670 	char *result = NULL;
671 
672 	if (!list_empty(&core_pmus))
673 		return strdup(list_first_entry(&core_pmus, struct perf_pmu, list)->name);
674 
675 	fd = perf_pmu__event_source_devices_fd();
676 	if (fd < 0)
677 		return strdup("cpu");
678 
679 	dir = fdopendir(fd);
680 	if (!dir) {
681 		close(fd);
682 		return strdup("cpu");
683 	}
684 
685 	while ((dent = readdir(dir))) {
686 		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
687 			continue;
688 		if (is_pmu_core(dent->d_name)) {
689 			result = strdup(dent->d_name);
690 			break;
691 		}
692 	}
693 
694 	closedir(dir);
695 	return result ?: strdup("cpu");
696 }
697 
evsel__find_pmu(const struct evsel * evsel)698 struct perf_pmu *evsel__find_pmu(const struct evsel *evsel)
699 {
700 	struct perf_pmu *pmu = evsel->pmu;
701 
702 	if (!pmu) {
703 		pmu = perf_pmus__find_by_type(evsel->core.attr.type);
704 		((struct evsel *)evsel)->pmu = pmu;
705 	}
706 	return pmu;
707 }
708 
perf_pmus__find_core_pmu(void)709 struct perf_pmu *perf_pmus__find_core_pmu(void)
710 {
711 	return perf_pmus__scan_core(NULL);
712 }
713 
perf_pmus__add_test_pmu(int test_sysfs_dirfd,const char * name)714 struct perf_pmu *perf_pmus__add_test_pmu(int test_sysfs_dirfd, const char *name)
715 {
716 	/*
717 	 * Some PMU functions read from the sysfs mount point, so care is
718 	 * needed, hence passing the eager_load flag to load things like the
719 	 * format files.
720 	 */
721 	return perf_pmu__lookup(&other_pmus, test_sysfs_dirfd, name, /*eager_load=*/true);
722 }
723