f5b2ea0c4fa19fb75b21f40cfa1f3978931f73f5
[platform/kernel/linux-starfive.git] / tools / perf / util / print-events.c
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 <linux/stddef.h>
13 #include <linux/perf_event.h>
14 #include <linux/zalloc.h>
15 #include <subcmd/pager.h>
16
17 #include "build-id.h"
18 #include "debug.h"
19 #include "evsel.h"
20 #include "metricgroup.h"
21 #include "parse-events.h"
22 #include "pmu.h"
23 #include "print-events.h"
24 #include "probe-file.h"
25 #include "string2.h"
26 #include "strlist.h"
27 #include "tracepoint.h"
28 #include "pfm.h"
29 #include "pmu-hybrid.h"
30
31 #define MAX_NAME_LEN 100
32
33 /** Strings corresponding to enum perf_type_id. */
34 static const char * const event_type_descriptors[] = {
35         "Hardware event",
36         "Software event",
37         "Tracepoint event",
38         "Hardware cache event",
39         "Raw hardware event descriptor",
40         "Hardware breakpoint",
41 };
42
43 static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = {
44         [PERF_TOOL_DURATION_TIME] = {
45                 .symbol = "duration_time",
46                 .alias  = "",
47         },
48         [PERF_TOOL_USER_TIME] = {
49                 .symbol = "user_time",
50                 .alias  = "",
51         },
52         [PERF_TOOL_SYSTEM_TIME] = {
53                 .symbol = "system_time",
54                 .alias  = "",
55         },
56 };
57
58 /*
59  * Print the events from <debugfs_mount_point>/tracing/events
60  */
61 void print_tracepoint_events(const struct print_callbacks *print_cb __maybe_unused, void *print_state __maybe_unused)
62 {
63         char *events_path = get_tracing_file("events");
64         int events_fd = open(events_path, O_PATH);
65
66         put_tracing_file(events_path);
67         if (events_fd < 0) {
68                 printf("Error: failed to open tracing events directory\n");
69                 return;
70         }
71
72 #ifdef HAVE_SCANDIRAT_SUPPORT
73 {
74         struct dirent **sys_namelist = NULL;
75         int sys_items = tracing_events__scandir_alphasort(&sys_namelist);
76
77         for (int i = 0; i < sys_items; i++) {
78                 struct dirent *sys_dirent = sys_namelist[i];
79                 struct dirent **evt_namelist = NULL;
80                 int dir_fd;
81                 int evt_items;
82
83                 if (sys_dirent->d_type != DT_DIR ||
84                     !strcmp(sys_dirent->d_name, ".") ||
85                     !strcmp(sys_dirent->d_name, ".."))
86                         goto next_sys;
87
88                 dir_fd = openat(events_fd, sys_dirent->d_name, O_PATH);
89                 if (dir_fd < 0)
90                         goto next_sys;
91
92                 evt_items = scandirat(events_fd, sys_dirent->d_name, &evt_namelist, NULL, alphasort);
93                 for (int j = 0; j < evt_items; j++) {
94                         struct dirent *evt_dirent = evt_namelist[j];
95                         char evt_path[MAXPATHLEN];
96                         int evt_fd;
97
98                         if (evt_dirent->d_type != DT_DIR ||
99                             !strcmp(evt_dirent->d_name, ".") ||
100                             !strcmp(evt_dirent->d_name, ".."))
101                                 goto next_evt;
102
103                         snprintf(evt_path, sizeof(evt_path), "%s/id", evt_dirent->d_name);
104                         evt_fd = openat(dir_fd, evt_path, O_RDONLY);
105                         if (evt_fd < 0)
106                                 goto next_evt;
107                         close(evt_fd);
108
109                         snprintf(evt_path, MAXPATHLEN, "%s:%s",
110                                  sys_dirent->d_name, evt_dirent->d_name);
111                         print_cb->print_event(print_state,
112                                         /*topic=*/NULL,
113                                         /*pmu_name=*/NULL,
114                                         evt_path,
115                                         /*event_alias=*/NULL,
116                                         /*scale_unit=*/NULL,
117                                         /*deprecated=*/false,
118                                         "Tracepoint event",
119                                         /*desc=*/NULL,
120                                         /*long_desc=*/NULL,
121                                         /*encoding_desc=*/NULL);
122 next_evt:
123                         free(evt_namelist[j]);
124                 }
125                 close(dir_fd);
126                 free(evt_namelist);
127 next_sys:
128                 free(sys_namelist[i]);
129         }
130
131         free(sys_namelist);
132 }
133 #else
134         printf("\nWARNING: Your libc doesn't have the scandir function, please ask its maintainers to implement it.\n"
135                "         As a rough fallback, please do 'ls %s' to see the available tracepoint events.\n", events_path);
136 #endif
137         close(events_fd);
138 }
139
140 void print_sdt_events(const struct print_callbacks *print_cb, void *print_state)
141 {
142         struct strlist *bidlist, *sdtlist;
143         struct str_node *bid_nd, *sdt_name, *next_sdt_name;
144         const char *last_sdt_name = NULL;
145
146         /*
147          * The implicitly sorted sdtlist will hold the tracepoint name followed
148          * by @<buildid>. If the tracepoint name is unique (determined by
149          * looking at the adjacent nodes) the @<buildid> is dropped otherwise
150          * the executable path and buildid are added to the name.
151          */
152         sdtlist = strlist__new(NULL, NULL);
153         if (!sdtlist) {
154                 pr_debug("Failed to allocate new strlist for SDT\n");
155                 return;
156         }
157         bidlist = build_id_cache__list_all(true);
158         if (!bidlist) {
159                 pr_debug("Failed to get buildids: %d\n", errno);
160                 return;
161         }
162         strlist__for_each_entry(bid_nd, bidlist) {
163                 struct probe_cache *pcache;
164                 struct probe_cache_entry *ent;
165
166                 pcache = probe_cache__new(bid_nd->s, NULL);
167                 if (!pcache)
168                         continue;
169                 list_for_each_entry(ent, &pcache->entries, node) {
170                         char buf[1024];
171
172                         snprintf(buf, sizeof(buf), "%s:%s@%s",
173                                  ent->pev.group, ent->pev.event, bid_nd->s);
174                         strlist__add(sdtlist, buf);
175                 }
176                 probe_cache__delete(pcache);
177         }
178         strlist__delete(bidlist);
179
180         strlist__for_each_entry(sdt_name, sdtlist) {
181                 bool show_detail = false;
182                 char *bid = strchr(sdt_name->s, '@');
183                 char *evt_name = NULL;
184
185                 if (bid)
186                         *(bid++) = '\0';
187
188                 if (last_sdt_name && !strcmp(last_sdt_name, sdt_name->s)) {
189                         show_detail = true;
190                 } else {
191                         next_sdt_name = strlist__next(sdt_name);
192                         if (next_sdt_name) {
193                                 char *bid2 = strchr(next_sdt_name->s, '@');
194
195                                 if (bid2)
196                                         *bid2 = '\0';
197                                 if (strcmp(sdt_name->s, next_sdt_name->s) == 0)
198                                         show_detail = true;
199                                 if (bid2)
200                                         *bid2 = '@';
201                         }
202                 }
203                 last_sdt_name = sdt_name->s;
204
205                 if (show_detail) {
206                         char *path = build_id_cache__origname(bid);
207
208                         if (path) {
209                                 if (asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid) < 0)
210                                         evt_name = NULL;
211                                 free(path);
212                         }
213                 }
214                 print_cb->print_event(print_state,
215                                 /*topic=*/NULL,
216                                 /*pmu_name=*/NULL,
217                                 evt_name ?: sdt_name->s,
218                                 /*event_alias=*/NULL,
219                                 /*deprecated=*/false,
220                                 /*scale_unit=*/NULL,
221                                 "SDT event",
222                                 /*desc=*/NULL,
223                                 /*long_desc=*/NULL,
224                                 /*encoding_desc=*/NULL);
225
226                 free(evt_name);
227         }
228         strlist__delete(sdtlist);
229 }
230
231 int print_hwcache_events(const struct print_callbacks *print_cb, void *print_state)
232 {
233         struct strlist *evt_name_list = strlist__new(NULL, NULL);
234         struct str_node *nd;
235
236         if (!evt_name_list) {
237                 pr_debug("Failed to allocate new strlist for hwcache events\n");
238                 return -ENOMEM;
239         }
240         for (int type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
241                 for (int op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
242                         /* skip invalid cache type */
243                         if (!evsel__is_cache_op_valid(type, op))
244                                 continue;
245
246                         for (int i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
247                                 struct perf_pmu *pmu = NULL;
248                                 char name[64];
249
250                                 __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name));
251                                 if (!perf_pmu__has_hybrid()) {
252                                         if (is_event_supported(PERF_TYPE_HW_CACHE,
253                                                                type | (op << 8) | (i << 16)))
254                                                 strlist__add(evt_name_list, name);
255                                         continue;
256                                 }
257                                 perf_pmu__for_each_hybrid_pmu(pmu) {
258                                         if (is_event_supported(PERF_TYPE_HW_CACHE,
259                                             type | (op << 8) | (i << 16) |
260                                             ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT))) {
261                                                 char new_name[128];
262                                                         snprintf(new_name, sizeof(new_name),
263                                                                  "%s/%s/", pmu->name, name);
264                                                         strlist__add(evt_name_list, new_name);
265                                         }
266                                 }
267                         }
268                 }
269         }
270
271         strlist__for_each_entry(nd, evt_name_list) {
272                 print_cb->print_event(print_state,
273                                 "cache",
274                                 /*pmu_name=*/NULL,
275                                 nd->s,
276                                 /*event_alias=*/NULL,
277                                 /*scale_unit=*/NULL,
278                                 /*deprecated=*/false,
279                                 event_type_descriptors[PERF_TYPE_HW_CACHE],
280                                 /*desc=*/NULL,
281                                 /*long_desc=*/NULL,
282                                 /*encoding_desc=*/NULL);
283         }
284         strlist__delete(evt_name_list);
285         return 0;
286 }
287
288 void print_tool_events(const struct print_callbacks *print_cb, void *print_state)
289 {
290         // Start at 1 because the first enum entry means no tool event.
291         for (int i = 1; i < PERF_TOOL_MAX; ++i) {
292                 print_cb->print_event(print_state,
293                                 "tool",
294                                 /*pmu_name=*/NULL,
295                                 event_symbols_tool[i].symbol,
296                                 event_symbols_tool[i].alias,
297                                 /*scale_unit=*/NULL,
298                                 /*deprecated=*/false,
299                                 "Tool event",
300                                 /*desc=*/NULL,
301                                 /*long_desc=*/NULL,
302                                 /*encoding_desc=*/NULL);
303         }
304 }
305
306 void print_symbol_events(const struct print_callbacks *print_cb, void *print_state,
307                          unsigned int type, const struct event_symbol *syms,
308                          unsigned int max)
309 {
310         struct strlist *evt_name_list = strlist__new(NULL, NULL);
311         struct str_node *nd;
312
313         if (!evt_name_list) {
314                 pr_debug("Failed to allocate new strlist for symbol events\n");
315                 return;
316         }
317         for (unsigned int i = 0; i < max; i++) {
318                 /*
319                  * New attr.config still not supported here, the latest
320                  * example was PERF_COUNT_SW_CGROUP_SWITCHES
321                  */
322                 if (syms[i].symbol == NULL)
323                         continue;
324
325                 if (!is_event_supported(type, i))
326                         continue;
327
328                 if (strlen(syms[i].alias)) {
329                         char name[MAX_NAME_LEN];
330
331                         snprintf(name, MAX_NAME_LEN, "%s OR %s", syms[i].symbol, syms[i].alias);
332                         strlist__add(evt_name_list, name);
333                 } else
334                         strlist__add(evt_name_list, syms[i].symbol);
335         }
336
337         strlist__for_each_entry(nd, evt_name_list) {
338                 char *alias = strstr(nd->s, " OR ");
339
340                 if (alias) {
341                         *alias = '\0';
342                         alias += 4;
343                 }
344                 print_cb->print_event(print_state,
345                                 /*topic=*/NULL,
346                                 /*pmu_name=*/NULL,
347                                 nd->s,
348                                 alias,
349                                 /*scale_unit=*/NULL,
350                                 /*deprecated=*/false,
351                                 event_type_descriptors[type],
352                                 /*desc=*/NULL,
353                                 /*long_desc=*/NULL,
354                                 /*encoding_desc=*/NULL);
355         }
356         strlist__delete(evt_name_list);
357 }
358
359 /*
360  * Print the help text for the event symbols:
361  */
362 void print_events(const struct print_callbacks *print_cb, void *print_state)
363 {
364         print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE,
365                         event_symbols_hw, PERF_COUNT_HW_MAX);
366         print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE,
367                         event_symbols_sw, PERF_COUNT_SW_MAX);
368
369         print_tool_events(print_cb, print_state);
370
371         print_hwcache_events(print_cb, print_state);
372
373         print_pmu_events(print_cb, print_state);
374
375         print_cb->print_event(print_state,
376                         /*topic=*/NULL,
377                         /*pmu_name=*/NULL,
378                         "rNNN",
379                         /*event_alias=*/NULL,
380                         /*scale_unit=*/NULL,
381                         /*deprecated=*/false,
382                         event_type_descriptors[PERF_TYPE_RAW],
383                         /*desc=*/NULL,
384                         /*long_desc=*/NULL,
385                         /*encoding_desc=*/NULL);
386
387         print_cb->print_event(print_state,
388                         /*topic=*/NULL,
389                         /*pmu_name=*/NULL,
390                         "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
391                         /*event_alias=*/NULL,
392                         /*scale_unit=*/NULL,
393                         /*deprecated=*/false,
394                         event_type_descriptors[PERF_TYPE_RAW],
395                         "(see 'man perf-list' on how to encode it)",
396                         /*long_desc=*/NULL,
397                         /*encoding_desc=*/NULL);
398
399         print_cb->print_event(print_state,
400                         /*topic=*/NULL,
401                         /*pmu_name=*/NULL,
402                         "mem:<addr>[/len][:access]",
403                         /*scale_unit=*/NULL,
404                         /*event_alias=*/NULL,
405                         /*deprecated=*/false,
406                         event_type_descriptors[PERF_TYPE_BREAKPOINT],
407                         /*desc=*/NULL,
408                         /*long_desc=*/NULL,
409                         /*encoding_desc=*/NULL);
410
411         print_tracepoint_events(print_cb, print_state);
412
413         print_sdt_events(print_cb, print_state);
414
415         metricgroup__print(print_cb, print_state);
416
417         print_libpfm_events(print_cb, print_state);
418 }