xref: /linux/tools/perf/util/tp_pmu.c (revision 45b6e281cb0648acd04f896375de69481d29daa7)
1d002aab8SIan Rogers // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2d002aab8SIan Rogers #include "tp_pmu.h"
3*45b6e281SIan Rogers #include "pmus.h"
4d002aab8SIan Rogers #include <api/fs/fs.h>
5d002aab8SIan Rogers #include <api/fs/tracing_path.h>
6d002aab8SIan Rogers #include <api/io_dir.h>
7d002aab8SIan Rogers #include <linux/kernel.h>
8d002aab8SIan Rogers #include <errno.h>
9d002aab8SIan Rogers #include <string.h>
10d002aab8SIan Rogers 
11d002aab8SIan Rogers int tp_pmu__id(const char *sys, const char *name)
12d002aab8SIan Rogers {
13d002aab8SIan Rogers 	char *tp_dir = get_events_file(sys);
14d002aab8SIan Rogers 	char path[PATH_MAX];
15d002aab8SIan Rogers 	int id, err;
16d002aab8SIan Rogers 
17d002aab8SIan Rogers 	if (!tp_dir)
18d002aab8SIan Rogers 		return -1;
19d002aab8SIan Rogers 
20d002aab8SIan Rogers 	scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name);
21d002aab8SIan Rogers 	put_events_file(tp_dir);
22d002aab8SIan Rogers 	err = filename__read_int(path, &id);
23d002aab8SIan Rogers 	if (err)
24d002aab8SIan Rogers 		return err;
25d002aab8SIan Rogers 
26d002aab8SIan Rogers 	return id;
27d002aab8SIan Rogers }
28d002aab8SIan Rogers 
29d002aab8SIan Rogers 
30d002aab8SIan Rogers int tp_pmu__for_each_tp_event(const char *sys, void *state, tp_event_callback cb)
31d002aab8SIan Rogers {
32d002aab8SIan Rogers 	char *evt_path;
33d002aab8SIan Rogers 	struct io_dirent64 *evt_ent;
34d002aab8SIan Rogers 	struct io_dir evt_dir;
35d002aab8SIan Rogers 	int ret = 0;
36d002aab8SIan Rogers 
37d002aab8SIan Rogers 	evt_path = get_events_file(sys);
38d002aab8SIan Rogers 	if (!evt_path)
39d002aab8SIan Rogers 		return -errno;
40d002aab8SIan Rogers 
41d002aab8SIan Rogers 	io_dir__init(&evt_dir, open(evt_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
42d002aab8SIan Rogers 	if (evt_dir.dirfd < 0) {
43d002aab8SIan Rogers 		ret = -errno;
44d002aab8SIan Rogers 		put_events_file(evt_path);
45d002aab8SIan Rogers 		return ret;
46d002aab8SIan Rogers 	}
47d002aab8SIan Rogers 	put_events_file(evt_path);
48d002aab8SIan Rogers 
49d002aab8SIan Rogers 	while (!ret && (evt_ent = io_dir__readdir(&evt_dir))) {
50d002aab8SIan Rogers 		if (!strcmp(evt_ent->d_name, ".")
51d002aab8SIan Rogers 		    || !strcmp(evt_ent->d_name, "..")
52d002aab8SIan Rogers 		    || !strcmp(evt_ent->d_name, "enable")
53d002aab8SIan Rogers 		    || !strcmp(evt_ent->d_name, "filter"))
54d002aab8SIan Rogers 			continue;
55d002aab8SIan Rogers 
56d002aab8SIan Rogers 		ret = cb(state, sys, evt_ent->d_name);
57d002aab8SIan Rogers 		if (ret)
58d002aab8SIan Rogers 			break;
59d002aab8SIan Rogers 	}
60d002aab8SIan Rogers 	close(evt_dir.dirfd);
61d002aab8SIan Rogers 	return ret;
62d002aab8SIan Rogers }
63d002aab8SIan Rogers 
64d002aab8SIan Rogers int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb)
65d002aab8SIan Rogers {
66d002aab8SIan Rogers 	struct io_dirent64 *events_ent;
67d002aab8SIan Rogers 	struct io_dir events_dir;
68d002aab8SIan Rogers 	int ret = 0;
69d002aab8SIan Rogers 	char *events_dir_path = get_tracing_file("events");
70d002aab8SIan Rogers 
71d002aab8SIan Rogers 	if (!events_dir_path)
72d002aab8SIan Rogers 		return -errno;
73d002aab8SIan Rogers 
74d002aab8SIan Rogers 	io_dir__init(&events_dir, open(events_dir_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
75d002aab8SIan Rogers 	if (events_dir.dirfd < 0) {
76d002aab8SIan Rogers 		ret = -errno;
77d002aab8SIan Rogers 		put_events_file(events_dir_path);
78d002aab8SIan Rogers 		return ret;
79d002aab8SIan Rogers 	}
80d002aab8SIan Rogers 	put_events_file(events_dir_path);
81d002aab8SIan Rogers 
82d002aab8SIan Rogers 	while (!ret && (events_ent = io_dir__readdir(&events_dir))) {
83d002aab8SIan Rogers 		if (!strcmp(events_ent->d_name, ".") ||
84d002aab8SIan Rogers 		    !strcmp(events_ent->d_name, "..") ||
85d002aab8SIan Rogers 		    !strcmp(events_ent->d_name, "enable") ||
86d002aab8SIan Rogers 		    !strcmp(events_ent->d_name, "header_event") ||
87d002aab8SIan Rogers 		    !strcmp(events_ent->d_name, "header_page"))
88d002aab8SIan Rogers 			continue;
89d002aab8SIan Rogers 
90d002aab8SIan Rogers 		ret = cb(state, events_ent->d_name);
91d002aab8SIan Rogers 		if (ret)
92d002aab8SIan Rogers 			break;
93d002aab8SIan Rogers 	}
94d002aab8SIan Rogers 	close(events_dir.dirfd);
95d002aab8SIan Rogers 	return ret;
96d002aab8SIan Rogers }
97*45b6e281SIan Rogers 
98*45b6e281SIan Rogers bool perf_pmu__is_tracepoint(const struct perf_pmu *pmu)
99*45b6e281SIan Rogers {
100*45b6e281SIan Rogers 	return pmu->type == PERF_TYPE_TRACEPOINT;
101*45b6e281SIan Rogers }
102*45b6e281SIan Rogers 
103*45b6e281SIan Rogers struct for_each_event_args {
104*45b6e281SIan Rogers 	void *state;
105*45b6e281SIan Rogers 	pmu_event_callback cb;
106*45b6e281SIan Rogers 	const struct perf_pmu *pmu;
107*45b6e281SIan Rogers };
108*45b6e281SIan Rogers 
109*45b6e281SIan Rogers static int for_each_event_cb(void *state, const char *sys_name, const char *evt_name)
110*45b6e281SIan Rogers {
111*45b6e281SIan Rogers 	struct for_each_event_args *args = state;
112*45b6e281SIan Rogers 	char name[2 * FILENAME_MAX + 2];
113*45b6e281SIan Rogers 	/* 16 possible hex digits and 22 other characters and \0. */
114*45b6e281SIan Rogers 	char encoding[16 + 22];
115*45b6e281SIan Rogers 	char *format = NULL;
116*45b6e281SIan Rogers 	size_t format_size;
117*45b6e281SIan Rogers 	struct pmu_event_info info = {
118*45b6e281SIan Rogers 		.pmu = args->pmu,
119*45b6e281SIan Rogers 		.pmu_name = args->pmu->name,
120*45b6e281SIan Rogers 		.event_type_desc = "Tracepoint event",
121*45b6e281SIan Rogers 	};
122*45b6e281SIan Rogers 	char *tp_dir = get_events_file(sys_name);
123*45b6e281SIan Rogers 	char path[PATH_MAX];
124*45b6e281SIan Rogers 	int id, err;
125*45b6e281SIan Rogers 
126*45b6e281SIan Rogers 	if (!tp_dir)
127*45b6e281SIan Rogers 		return -1;
128*45b6e281SIan Rogers 
129*45b6e281SIan Rogers 	scnprintf(path, sizeof(path), "%s/%s/id", tp_dir, evt_name);
130*45b6e281SIan Rogers 	err = filename__read_int(path, &id);
131*45b6e281SIan Rogers 	if (err == 0) {
132*45b6e281SIan Rogers 		snprintf(encoding, sizeof(encoding), "tracepoint/config=0x%x/", id);
133*45b6e281SIan Rogers 		info.encoding_desc = encoding;
134*45b6e281SIan Rogers 	}
135*45b6e281SIan Rogers 
136*45b6e281SIan Rogers 	scnprintf(path, sizeof(path), "%s/%s/format", tp_dir, evt_name);
137*45b6e281SIan Rogers 	put_events_file(tp_dir);
138*45b6e281SIan Rogers 	err = filename__read_str(path, &format, &format_size);
139*45b6e281SIan Rogers 	if (err == 0) {
140*45b6e281SIan Rogers 		info.long_desc = format;
141*45b6e281SIan Rogers 		for (size_t i = 0 ; i < format_size; i++) {
142*45b6e281SIan Rogers 			/* Swap tabs to spaces due to some rendering issues. */
143*45b6e281SIan Rogers 			if (format[i] == '\t')
144*45b6e281SIan Rogers 				format[i] = ' ';
145*45b6e281SIan Rogers 		}
146*45b6e281SIan Rogers 	}
147*45b6e281SIan Rogers 	snprintf(name, sizeof(name), "%s:%s", sys_name, evt_name);
148*45b6e281SIan Rogers 	info.name = name;
149*45b6e281SIan Rogers 	err = args->cb(args->state, &info);
150*45b6e281SIan Rogers 	free(format);
151*45b6e281SIan Rogers 	return err;
152*45b6e281SIan Rogers }
153*45b6e281SIan Rogers 
154*45b6e281SIan Rogers static int for_each_event_sys_cb(void *state, const char *sys_name)
155*45b6e281SIan Rogers {
156*45b6e281SIan Rogers 	return tp_pmu__for_each_tp_event(sys_name, state, for_each_event_cb);
157*45b6e281SIan Rogers }
158*45b6e281SIan Rogers 
159*45b6e281SIan Rogers int tp_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb)
160*45b6e281SIan Rogers {
161*45b6e281SIan Rogers 	struct for_each_event_args args = {
162*45b6e281SIan Rogers 		.state = state,
163*45b6e281SIan Rogers 		.cb = cb,
164*45b6e281SIan Rogers 		.pmu = pmu,
165*45b6e281SIan Rogers 	};
166*45b6e281SIan Rogers 
167*45b6e281SIan Rogers 	return tp_pmu__for_each_tp_sys(&args, for_each_event_sys_cb);
168*45b6e281SIan Rogers }
169*45b6e281SIan Rogers 
170*45b6e281SIan Rogers static int num_events_cb(void *state, const char *sys_name __maybe_unused,
171*45b6e281SIan Rogers 			 const char *evt_name __maybe_unused)
172*45b6e281SIan Rogers {
173*45b6e281SIan Rogers 	size_t *count = state;
174*45b6e281SIan Rogers 
175*45b6e281SIan Rogers 	(*count)++;
176*45b6e281SIan Rogers 	return 0;
177*45b6e281SIan Rogers }
178*45b6e281SIan Rogers 
179*45b6e281SIan Rogers static int num_events_sys_cb(void *state, const char *sys_name)
180*45b6e281SIan Rogers {
181*45b6e281SIan Rogers 	return tp_pmu__for_each_tp_event(sys_name, state, num_events_cb);
182*45b6e281SIan Rogers }
183*45b6e281SIan Rogers 
184*45b6e281SIan Rogers size_t tp_pmu__num_events(struct perf_pmu *pmu __maybe_unused)
185*45b6e281SIan Rogers {
186*45b6e281SIan Rogers 	size_t count = 0;
187*45b6e281SIan Rogers 
188*45b6e281SIan Rogers 	tp_pmu__for_each_tp_sys(&count, num_events_sys_cb);
189*45b6e281SIan Rogers 	return count;
190*45b6e281SIan Rogers }
191*45b6e281SIan Rogers 
192*45b6e281SIan Rogers bool tp_pmu__have_event(struct perf_pmu *pmu __maybe_unused, const char *name)
193*45b6e281SIan Rogers {
194*45b6e281SIan Rogers 	char *dup_name, *colon;
195*45b6e281SIan Rogers 	int id;
196*45b6e281SIan Rogers 
197*45b6e281SIan Rogers 	colon = strchr(name, ':');
198*45b6e281SIan Rogers 	if (colon == NULL)
199*45b6e281SIan Rogers 		return false;
200*45b6e281SIan Rogers 
201*45b6e281SIan Rogers 	dup_name = strdup(name);
202*45b6e281SIan Rogers 	if (!dup_name)
203*45b6e281SIan Rogers 		return false;
204*45b6e281SIan Rogers 
205*45b6e281SIan Rogers 	colon = dup_name + (colon - name);
206*45b6e281SIan Rogers 	*colon = '\0';
207*45b6e281SIan Rogers 	id = tp_pmu__id(dup_name, colon + 1);
208*45b6e281SIan Rogers 	free(dup_name);
209*45b6e281SIan Rogers 	return id >= 0;
210*45b6e281SIan Rogers }
211