Linux Audio

Check our new training course

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}