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