1 // SPDX-License-Identifier: GPL-2.0
2 #include <dirent.h>
3 #include <errno.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <sys/param.h>
9 #include <unistd.h>
10
11 #include <api/fs/tracing_path.h>
12 #include <api/io.h>
13 #include <linux/stddef.h>
14 #include <linux/perf_event.h>
15 #include <linux/zalloc.h>
16 #include <subcmd/pager.h>
17
18 #include "build-id.h"
19 #include "debug.h"
20 #include "evsel.h"
21 #include "metricgroup.h"
22 #include "parse-events.h"
23 #include "pmu.h"
24 #include "pmus.h"
25 #include "print-events.h"
26 #include "probe-file.h"
27 #include "string2.h"
28 #include "strlist.h"
29 #include "tracepoint.h"
30 #include "pfm.h"
31 #include "thread_map.h"
32 #include "util.h"
33
34 #define MAX_NAME_LEN 100
35
36 /** Strings corresponding to enum perf_type_id. */
37 static const char * const event_type_descriptors[] = {
38 "Hardware event",
39 "Software event",
40 "Tracepoint event",
41 "Hardware cache event",
42 "Raw event descriptor",
43 "Hardware breakpoint",
44 };
45
46 static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = {
47 [PERF_TOOL_DURATION_TIME] = {
48 .symbol = "duration_time",
49 .alias = "",
50 },
51 [PERF_TOOL_USER_TIME] = {
52 .symbol = "user_time",
53 .alias = "",
54 },
55 [PERF_TOOL_SYSTEM_TIME] = {
56 .symbol = "system_time",
57 .alias = "",
58 },
59 };
60
61 /*
62 * Print the events from <debugfs_mount_point>/tracing/events
63 */
print_tracepoint_events(const struct print_callbacks * print_cb __maybe_unused,void * print_state __maybe_unused)64 void print_tracepoint_events(const struct print_callbacks *print_cb __maybe_unused, void *print_state __maybe_unused)
65 {
66 char *events_path = get_tracing_file("events");
67 int events_fd = open(events_path, O_PATH);
68 struct dirent **sys_namelist = NULL;
69 int sys_items;
70
71 if (events_fd < 0) {
72 pr_err("Error: failed to open tracing events directory\n");
73 pr_err("%s: %s\n", events_path, strerror(errno));
74 return;
75 }
76 put_tracing_file(events_path);
77
78 sys_items = tracing_events__scandir_alphasort(&sys_namelist);
79
80 for (int i = 0; i < sys_items; i++) {
81 struct dirent *sys_dirent = sys_namelist[i];
82 struct dirent **evt_namelist = NULL;
83 int dir_fd;
84 int evt_items;
85
86 if (sys_dirent->d_type != DT_DIR ||
87 !strcmp(sys_dirent->d_name, ".") ||
88 !strcmp(sys_dirent->d_name, ".."))
89 goto next_sys;
90
91 dir_fd = openat(events_fd, sys_dirent->d_name, O_PATH);
92 if (dir_fd < 0)
93 goto next_sys;
94
95 evt_items = scandirat(events_fd, sys_dirent->d_name, &evt_namelist, NULL, alphasort);
96 for (int j = 0; j < evt_items; j++) {
97 /*
98 * Buffer sized at twice the max filename length + 1
99 * separator + 1 \0 terminator.
100 */
101 char buf[NAME_MAX * 2 + 2];
102 /* 16 possible hex digits and 22 other characters and \0. */
103 char encoding[16 + 22];
104 struct dirent *evt_dirent = evt_namelist[j];
105 struct io id;
106 __u64 config;
107
108 if (evt_dirent->d_type != DT_DIR ||
109 !strcmp(evt_dirent->d_name, ".") ||
110 !strcmp(evt_dirent->d_name, ".."))
111 goto next_evt;
112
113 snprintf(buf, sizeof(buf), "%s/id", evt_dirent->d_name);
114 io__init(&id, openat(dir_fd, buf, O_RDONLY), buf, sizeof(buf));
115
116 if (id.fd < 0)
117 goto next_evt;
118
119 if (io__get_dec(&id, &config) < 0) {
120 close(id.fd);
121 goto next_evt;
122 }
123 close(id.fd);
124
125 snprintf(buf, sizeof(buf), "%s:%s",
126 sys_dirent->d_name, evt_dirent->d_name);
127 snprintf(encoding, sizeof(encoding), "tracepoint/config=0x%llx/", config);
128 print_cb->print_event(print_state,
129 /*topic=*/NULL,
130 /*pmu_name=*/NULL, /* really "tracepoint" */
131 /*event_name=*/buf,
132 /*event_alias=*/NULL,
133 /*scale_unit=*/NULL,
134 /*deprecated=*/false,
135 "Tracepoint event",
136 /*desc=*/NULL,
137 /*long_desc=*/NULL,
138 encoding);
139 next_evt:
140 free(evt_namelist[j]);
141 }
142 close(dir_fd);
143 free(evt_namelist);
144 next_sys:
145 free(sys_namelist[i]);
146 }
147
148 free(sys_namelist);
149 close(events_fd);
150 }
151
print_sdt_events(const struct print_callbacks * print_cb,void * print_state)152 void print_sdt_events(const struct print_callbacks *print_cb, void *print_state)
153 {
154 struct strlist *bidlist, *sdtlist;
155 struct str_node *bid_nd, *sdt_name, *next_sdt_name;
156 const char *last_sdt_name = NULL;
157
158 /*
159 * The implicitly sorted sdtlist will hold the tracepoint name followed
160 * by @<buildid>. If the tracepoint name is unique (determined by
161 * looking at the adjacent nodes) the @<buildid> is dropped otherwise
162 * the executable path and buildid are added to the name.
163 */
164 sdtlist = strlist__new(NULL, NULL);
165 if (!sdtlist) {
166 pr_debug("Failed to allocate new strlist for SDT\n");
167 return;
168 }
169 bidlist = build_id_cache__list_all(true);
170 if (!bidlist) {
171 pr_debug("Failed to get buildids: %d\n", errno);
172 return;
173 }
174 strlist__for_each_entry(bid_nd, bidlist) {
175 struct probe_cache *pcache;
176 struct probe_cache_entry *ent;
177
178 pcache = probe_cache__new(bid_nd->s, NULL);
179 if (!pcache)
180 continue;
181 list_for_each_entry(ent, &pcache->entries, node) {
182 char buf[1024];
183
184 snprintf(buf, sizeof(buf), "%s:%s@%s",
185 ent->pev.group, ent->pev.event, bid_nd->s);
186 strlist__add(sdtlist, buf);
187 }
188 probe_cache__delete(pcache);
189 }
190 strlist__delete(bidlist);
191
192 strlist__for_each_entry(sdt_name, sdtlist) {
193 bool show_detail = false;
194 char *bid = strchr(sdt_name->s, '@');
195 char *evt_name = NULL;
196
197 if (bid)
198 *(bid++) = '\0';
199
200 if (last_sdt_name && !strcmp(last_sdt_name, sdt_name->s)) {
201 show_detail = true;
202 } else {
203 next_sdt_name = strlist__next(sdt_name);
204 if (next_sdt_name) {
205 char *bid2 = strchr(next_sdt_name->s, '@');
206
207 if (bid2)
208 *bid2 = '\0';
209 if (strcmp(sdt_name->s, next_sdt_name->s) == 0)
210 show_detail = true;
211 if (bid2)
212 *bid2 = '@';
213 }
214 }
215 last_sdt_name = sdt_name->s;
216
217 if (show_detail) {
218 char *path = build_id_cache__origname(bid);
219
220 if (path) {
221 if (asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid) < 0)
222 evt_name = NULL;
223 free(path);
224 }
225 }
226 print_cb->print_event(print_state,
227 /*topic=*/NULL,
228 /*pmu_name=*/NULL,
229 evt_name ?: sdt_name->s,
230 /*event_alias=*/NULL,
231 /*deprecated=*/false,
232 /*scale_unit=*/NULL,
233 "SDT event",
234 /*desc=*/NULL,
235 /*long_desc=*/NULL,
236 /*encoding_desc=*/NULL);
237
238 free(evt_name);
239 }
240 strlist__delete(sdtlist);
241 }
242
is_event_supported(u8 type,u64 config)243 bool is_event_supported(u8 type, u64 config)
244 {
245 bool ret = true;
246 struct evsel *evsel;
247 struct perf_event_attr attr = {
248 .type = type,
249 .config = config,
250 .disabled = 1,
251 };
252 struct perf_thread_map *tmap = thread_map__new_by_tid(0);
253
254 if (tmap == NULL)
255 return false;
256
257 evsel = evsel__new(&attr);
258 if (evsel) {
259 ret = evsel__open(evsel, NULL, tmap) >= 0;
260
261 if (!ret) {
262 /*
263 * The event may fail to open if the paranoid value
264 * /proc/sys/kernel/perf_event_paranoid is set to 2
265 * Re-run with exclude_kernel set; we don't do that by
266 * default as some ARM machines do not support it.
267 */
268 evsel->core.attr.exclude_kernel = 1;
269 ret = evsel__open(evsel, NULL, tmap) >= 0;
270 }
271
272 if (!ret) {
273 /*
274 * The event may fail to open if the PMU requires
275 * exclude_guest to be set (e.g. as the Apple M1 PMU
276 * requires).
277 * Re-run with exclude_guest set; we don't do that by
278 * default as it's equally legitimate for another PMU
279 * driver to require that exclude_guest is clear.
280 */
281 evsel->core.attr.exclude_guest = 1;
282 ret = evsel__open(evsel, NULL, tmap) >= 0;
283 }
284
285 evsel__delete(evsel);
286 }
287
288 perf_thread_map__put(tmap);
289 return ret;
290 }
291
print_hwcache_events(const struct print_callbacks * print_cb,void * print_state)292 int print_hwcache_events(const struct print_callbacks *print_cb, void *print_state)
293 {
294 struct perf_pmu *pmu = NULL;
295 const char *event_type_descriptor = event_type_descriptors[PERF_TYPE_HW_CACHE];
296
297 /*
298 * Only print core PMUs, skipping uncore for performance and
299 * PERF_TYPE_SOFTWARE that can succeed in opening legacy cache evenst.
300 */
301 while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
302 if (pmu->is_uncore || pmu->type == PERF_TYPE_SOFTWARE)
303 continue;
304
305 for (int type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
306 for (int op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
307 /* skip invalid cache type */
308 if (!evsel__is_cache_op_valid(type, op))
309 continue;
310
311 for (int res = 0; res < PERF_COUNT_HW_CACHE_RESULT_MAX; res++) {
312 char name[64];
313 char alias_name[128];
314 __u64 config;
315 int ret;
316
317 __evsel__hw_cache_type_op_res_name(type, op, res,
318 name, sizeof(name));
319
320 ret = parse_events__decode_legacy_cache(name, pmu->type,
321 &config);
322 if (ret || !is_event_supported(PERF_TYPE_HW_CACHE, config))
323 continue;
324 snprintf(alias_name, sizeof(alias_name), "%s/%s/",
325 pmu->name, name);
326 print_cb->print_event(print_state,
327 "cache",
328 pmu->name,
329 name,
330 alias_name,
331 /*scale_unit=*/NULL,
332 /*deprecated=*/false,
333 event_type_descriptor,
334 /*desc=*/NULL,
335 /*long_desc=*/NULL,
336 /*encoding_desc=*/NULL);
337 }
338 }
339 }
340 }
341 return 0;
342 }
343
print_tool_events(const struct print_callbacks * print_cb,void * print_state)344 void print_tool_events(const struct print_callbacks *print_cb, void *print_state)
345 {
346 // Start at 1 because the first enum entry means no tool event.
347 for (int i = 1; i < PERF_TOOL_MAX; ++i) {
348 print_cb->print_event(print_state,
349 "tool",
350 /*pmu_name=*/NULL,
351 event_symbols_tool[i].symbol,
352 event_symbols_tool[i].alias,
353 /*scale_unit=*/NULL,
354 /*deprecated=*/false,
355 "Tool event",
356 /*desc=*/NULL,
357 /*long_desc=*/NULL,
358 /*encoding_desc=*/NULL);
359 }
360 }
361
print_symbol_events(const struct print_callbacks * print_cb,void * print_state,unsigned int type,const struct event_symbol * syms,unsigned int max)362 void print_symbol_events(const struct print_callbacks *print_cb, void *print_state,
363 unsigned int type, const struct event_symbol *syms,
364 unsigned int max)
365 {
366 struct strlist *evt_name_list = strlist__new(NULL, NULL);
367 struct str_node *nd;
368
369 if (!evt_name_list) {
370 pr_debug("Failed to allocate new strlist for symbol events\n");
371 return;
372 }
373 for (unsigned int i = 0; i < max; i++) {
374 /*
375 * New attr.config still not supported here, the latest
376 * example was PERF_COUNT_SW_CGROUP_SWITCHES
377 */
378 if (syms[i].symbol == NULL)
379 continue;
380
381 if (!is_event_supported(type, i))
382 continue;
383
384 if (strlen(syms[i].alias)) {
385 char name[MAX_NAME_LEN];
386
387 snprintf(name, MAX_NAME_LEN, "%s OR %s", syms[i].symbol, syms[i].alias);
388 strlist__add(evt_name_list, name);
389 } else
390 strlist__add(evt_name_list, syms[i].symbol);
391 }
392
393 strlist__for_each_entry(nd, evt_name_list) {
394 char *alias = strstr(nd->s, " OR ");
395
396 if (alias) {
397 *alias = '\0';
398 alias += 4;
399 }
400 print_cb->print_event(print_state,
401 /*topic=*/NULL,
402 /*pmu_name=*/NULL,
403 nd->s,
404 alias,
405 /*scale_unit=*/NULL,
406 /*deprecated=*/false,
407 event_type_descriptors[type],
408 /*desc=*/NULL,
409 /*long_desc=*/NULL,
410 /*encoding_desc=*/NULL);
411 }
412 strlist__delete(evt_name_list);
413 }
414
415 /*
416 * Print the help text for the event symbols:
417 */
print_events(const struct print_callbacks * print_cb,void * print_state)418 void print_events(const struct print_callbacks *print_cb, void *print_state)
419 {
420 print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE,
421 event_symbols_hw, PERF_COUNT_HW_MAX);
422 print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE,
423 event_symbols_sw, PERF_COUNT_SW_MAX);
424
425 print_tool_events(print_cb, print_state);
426
427 print_hwcache_events(print_cb, print_state);
428
429 perf_pmus__print_pmu_events(print_cb, print_state);
430
431 print_cb->print_event(print_state,
432 /*topic=*/NULL,
433 /*pmu_name=*/NULL,
434 "rNNN",
435 /*event_alias=*/NULL,
436 /*scale_unit=*/NULL,
437 /*deprecated=*/false,
438 event_type_descriptors[PERF_TYPE_RAW],
439 /*desc=*/NULL,
440 /*long_desc=*/NULL,
441 /*encoding_desc=*/NULL);
442
443 perf_pmus__print_raw_pmu_events(print_cb, print_state);
444
445 print_cb->print_event(print_state,
446 /*topic=*/NULL,
447 /*pmu_name=*/NULL,
448 "mem:<addr>[/len][:access]",
449 /*scale_unit=*/NULL,
450 /*event_alias=*/NULL,
451 /*deprecated=*/false,
452 event_type_descriptors[PERF_TYPE_BREAKPOINT],
453 /*desc=*/NULL,
454 /*long_desc=*/NULL,
455 /*encoding_desc=*/NULL);
456
457 print_tracepoint_events(print_cb, print_state);
458
459 print_sdt_events(print_cb, print_state);
460
461 metricgroup__print(print_cb, print_state);
462
463 print_libpfm_events(print_cb, print_state);
464 }
465