File Index
Files and directories
Sign in
FILE

tp_pmu.c

File preview with syntax highlighting.

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