1 // SPDX-License-Identifier: GPL-2.0
11 #include <api/fs/tracing_path.h>
13 #include <linux/stddef.h>
14 #include <linux/perf_event.h>
15 #include <linux/zalloc.h>
16 #include <subcmd/pager.h>
21 #include "metricgroup.h"
22 #include "parse-events.h"
25 #include "print-events.h"
26 #include "probe-file.h"
29 #include "tracepoint.h"
31 #include "thread_map.h"
35 #define MAX_NAME_LEN 100
37 /** Strings corresponding to enum perf_type_id. */
38 static const char * const event_type_descriptors
[] = {
42 "Hardware cache event",
43 "Raw event descriptor",
44 "Hardware breakpoint",
48 * Print the events from <debugfs_mount_point>/tracing/events
50 void print_tracepoint_events(const struct print_callbacks
*print_cb __maybe_unused
, void *print_state __maybe_unused
)
52 char *events_path
= get_tracing_file("events");
53 int events_fd
= open(events_path
, O_PATH
);
54 struct dirent
**sys_namelist
= NULL
;
58 pr_err("Error: failed to open tracing events directory\n");
59 pr_err("%s: %s\n", events_path
, strerror(errno
));
62 put_tracing_file(events_path
);
64 sys_items
= tracing_events__scandir_alphasort(&sys_namelist
);
66 for (int i
= 0; i
< sys_items
; i
++) {
67 struct dirent
*sys_dirent
= sys_namelist
[i
];
68 struct dirent
**evt_namelist
= NULL
;
72 if (sys_dirent
->d_type
!= DT_DIR
||
73 !strcmp(sys_dirent
->d_name
, ".") ||
74 !strcmp(sys_dirent
->d_name
, ".."))
77 dir_fd
= openat(events_fd
, sys_dirent
->d_name
, O_PATH
);
81 evt_items
= scandirat(events_fd
, sys_dirent
->d_name
, &evt_namelist
, NULL
, alphasort
);
82 for (int j
= 0; j
< evt_items
; j
++) {
84 * Buffer sized at twice the max filename length + 1
85 * separator + 1 \0 terminator.
87 char buf
[NAME_MAX
* 2 + 2];
88 /* 16 possible hex digits and 22 other characters and \0. */
89 char encoding
[16 + 22];
90 struct dirent
*evt_dirent
= evt_namelist
[j
];
94 if (evt_dirent
->d_type
!= DT_DIR
||
95 !strcmp(evt_dirent
->d_name
, ".") ||
96 !strcmp(evt_dirent
->d_name
, ".."))
99 snprintf(buf
, sizeof(buf
), "%s/id", evt_dirent
->d_name
);
100 io__init(&id
, openat(dir_fd
, buf
, O_RDONLY
), buf
, sizeof(buf
));
105 if (io__get_dec(&id
, &config
) < 0) {
111 snprintf(buf
, sizeof(buf
), "%s:%s",
112 sys_dirent
->d_name
, evt_dirent
->d_name
);
113 snprintf(encoding
, sizeof(encoding
), "tracepoint/config=0x%llx/", config
);
114 print_cb
->print_event(print_state
,
116 /*pmu_name=*/NULL
, /* really "tracepoint" */
118 /*event_alias=*/NULL
,
120 /*deprecated=*/false,
126 free(evt_namelist
[j
]);
131 free(sys_namelist
[i
]);
138 void print_sdt_events(const struct print_callbacks
*print_cb
, void *print_state
)
140 struct strlist
*bidlist
, *sdtlist
;
141 struct str_node
*bid_nd
, *sdt_name
, *next_sdt_name
;
142 const char *last_sdt_name
= NULL
;
145 * The implicitly sorted sdtlist will hold the tracepoint name followed
146 * by @<buildid>. If the tracepoint name is unique (determined by
147 * looking at the adjacent nodes) the @<buildid> is dropped otherwise
148 * the executable path and buildid are added to the name.
150 sdtlist
= strlist__new(NULL
, NULL
);
152 pr_debug("Failed to allocate new strlist for SDT\n");
155 bidlist
= build_id_cache__list_all(true);
157 pr_debug("Failed to get buildids: %d\n", errno
);
160 strlist__for_each_entry(bid_nd
, bidlist
) {
161 struct probe_cache
*pcache
;
162 struct probe_cache_entry
*ent
;
164 pcache
= probe_cache__new(bid_nd
->s
, NULL
);
167 list_for_each_entry(ent
, &pcache
->entries
, node
) {
170 snprintf(buf
, sizeof(buf
), "%s:%s@%s",
171 ent
->pev
.group
, ent
->pev
.event
, bid_nd
->s
);
172 strlist__add(sdtlist
, buf
);
174 probe_cache__delete(pcache
);
176 strlist__delete(bidlist
);
178 strlist__for_each_entry(sdt_name
, sdtlist
) {
179 bool show_detail
= false;
180 char *bid
= strchr(sdt_name
->s
, '@');
181 char *evt_name
= NULL
;
186 if (last_sdt_name
&& !strcmp(last_sdt_name
, sdt_name
->s
)) {
189 next_sdt_name
= strlist__next(sdt_name
);
191 char *bid2
= strchr(next_sdt_name
->s
, '@');
195 if (strcmp(sdt_name
->s
, next_sdt_name
->s
) == 0)
201 last_sdt_name
= sdt_name
->s
;
204 char *path
= build_id_cache__origname(bid
);
207 if (asprintf(&evt_name
, "%s@%s(%.12s)", sdt_name
->s
, path
, bid
) < 0)
212 print_cb
->print_event(print_state
,
215 evt_name
?: sdt_name
->s
,
216 /*event_alias=*/NULL
,
217 /*deprecated=*/false,
222 /*encoding_desc=*/NULL
);
226 strlist__delete(sdtlist
);
229 bool is_event_supported(u8 type
, u64 config
)
233 struct perf_event_attr attr
= {
238 struct perf_thread_map
*tmap
= thread_map__new_by_tid(0);
243 evsel
= evsel__new(&attr
);
245 ret
= evsel__open(evsel
, NULL
, tmap
) >= 0;
249 * The event may fail to open if the paranoid value
250 * /proc/sys/kernel/perf_event_paranoid is set to 2
251 * Re-run with exclude_kernel set; we don't do that by
252 * default as some ARM machines do not support it.
254 evsel
->core
.attr
.exclude_kernel
= 1;
255 ret
= evsel__open(evsel
, NULL
, tmap
) >= 0;
260 * The event may fail to open if the PMU requires
261 * exclude_guest to be set (e.g. as the Apple M1 PMU
263 * Re-run with exclude_guest set; we don't do that by
264 * default as it's equally legitimate for another PMU
265 * driver to require that exclude_guest is clear.
267 evsel
->core
.attr
.exclude_guest
= 1;
268 ret
= evsel__open(evsel
, NULL
, tmap
) >= 0;
271 evsel__delete(evsel
);
274 perf_thread_map__put(tmap
);
278 int print_hwcache_events(const struct print_callbacks
*print_cb
, void *print_state
)
280 struct perf_pmu
*pmu
= NULL
;
281 const char *event_type_descriptor
= event_type_descriptors
[PERF_TYPE_HW_CACHE
];
284 * Only print core PMUs, skipping uncore for performance and
285 * PERF_TYPE_SOFTWARE that can succeed in opening legacy cache evenst.
287 while ((pmu
= perf_pmus__scan_core(pmu
)) != NULL
) {
288 if (pmu
->is_uncore
|| pmu
->type
== PERF_TYPE_SOFTWARE
)
291 for (int type
= 0; type
< PERF_COUNT_HW_CACHE_MAX
; type
++) {
292 for (int op
= 0; op
< PERF_COUNT_HW_CACHE_OP_MAX
; op
++) {
293 /* skip invalid cache type */
294 if (!evsel__is_cache_op_valid(type
, op
))
297 for (int res
= 0; res
< PERF_COUNT_HW_CACHE_RESULT_MAX
; res
++) {
299 char alias_name
[128];
303 __evsel__hw_cache_type_op_res_name(type
, op
, res
,
306 ret
= parse_events__decode_legacy_cache(name
, pmu
->type
,
308 if (ret
|| !is_event_supported(PERF_TYPE_HW_CACHE
, config
))
310 snprintf(alias_name
, sizeof(alias_name
), "%s/%s/",
312 print_cb
->print_event(print_state
,
318 /*deprecated=*/false,
319 event_type_descriptor
,
322 /*encoding_desc=*/NULL
);
330 void print_symbol_events(const struct print_callbacks
*print_cb
, void *print_state
,
331 unsigned int type
, const struct event_symbol
*syms
,
334 struct strlist
*evt_name_list
= strlist__new(NULL
, NULL
);
337 if (!evt_name_list
) {
338 pr_debug("Failed to allocate new strlist for symbol events\n");
341 for (unsigned int i
= 0; i
< max
; i
++) {
343 * New attr.config still not supported here, the latest
344 * example was PERF_COUNT_SW_CGROUP_SWITCHES
346 if (syms
[i
].symbol
== NULL
)
349 if (!is_event_supported(type
, i
))
352 if (strlen(syms
[i
].alias
)) {
353 char name
[MAX_NAME_LEN
];
355 snprintf(name
, MAX_NAME_LEN
, "%s OR %s", syms
[i
].symbol
, syms
[i
].alias
);
356 strlist__add(evt_name_list
, name
);
358 strlist__add(evt_name_list
, syms
[i
].symbol
);
361 strlist__for_each_entry(nd
, evt_name_list
) {
362 char *alias
= strstr(nd
->s
, " OR ");
368 print_cb
->print_event(print_state
,
374 /*deprecated=*/false,
375 event_type_descriptors
[type
],
378 /*encoding_desc=*/NULL
);
380 strlist__delete(evt_name_list
);
384 * Print the help text for the event symbols:
386 void print_events(const struct print_callbacks
*print_cb
, void *print_state
)
388 print_symbol_events(print_cb
, print_state
, PERF_TYPE_HARDWARE
,
389 event_symbols_hw
, PERF_COUNT_HW_MAX
);
390 print_symbol_events(print_cb
, print_state
, PERF_TYPE_SOFTWARE
,
391 event_symbols_sw
, PERF_COUNT_SW_MAX
);
393 print_hwcache_events(print_cb
, print_state
);
395 perf_pmus__print_pmu_events(print_cb
, print_state
);
397 print_cb
->print_event(print_state
,
401 /*event_alias=*/NULL
,
403 /*deprecated=*/false,
404 event_type_descriptors
[PERF_TYPE_RAW
],
407 /*encoding_desc=*/NULL
);
409 perf_pmus__print_raw_pmu_events(print_cb
, print_state
);
411 print_cb
->print_event(print_state
,
414 "mem:<addr>[/len][:access]",
416 /*event_alias=*/NULL
,
417 /*deprecated=*/false,
418 event_type_descriptors
[PERF_TYPE_BREAKPOINT
],
421 /*encoding_desc=*/NULL
);
423 print_tracepoint_events(print_cb
, print_state
);
425 print_sdt_events(print_cb
, print_state
);
427 metricgroup__print(print_cb
, print_state
);
429 print_libpfm_events(print_cb
, print_state
);