xref: /linux/tools/perf/util/perf_api_probe.c (revision 473f6c8f437b049f8ec015d57cd59bb983b1d85c)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include "perf_api_probe.h"
3 
4 #include <errno.h>
5 
6 #include <perf/cpumap.h>
7 
8 #include "cloexec.h"
9 #include "evlist.h"
10 #include "evsel.h"
11 #include "parse-events.h"
12 #include "perf-sys.h"
13 #include "pmu.h"
14 #include "pmus.h"
15 
16 typedef void (*setup_probe_fn_t)(struct evsel *evsel);
17 
18 static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str)
19 {
20 	struct evlist *evlist;
21 	struct evsel *evsel;
22 	unsigned long flags = perf_event_open_cloexec_flag();
23 	int err = -EAGAIN, fd;
24 	static pid_t pid = -1;
25 
26 	evlist = evlist__new();
27 	if (!evlist)
28 		return -ENOMEM;
29 
30 	if (parse_event(evlist, str))
31 		goto out_delete;
32 
33 	evsel = evlist__first(evlist);
34 
35 	while (1) {
36 		fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
37 		if (fd < 0) {
38 			if (pid == -1 && errno == EACCES) {
39 				pid = 0;
40 				continue;
41 			}
42 			goto out_delete;
43 		}
44 		break;
45 	}
46 	close(fd);
47 
48 	fn(evsel);
49 
50 	fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
51 	if (fd < 0) {
52 		if (errno == EINVAL)
53 			err = -EINVAL;
54 		goto out_delete;
55 	}
56 	close(fd);
57 	err = 0;
58 
59 out_delete:
60 	evlist__put(evlist);
61 	return err;
62 }
63 
64 static bool perf_probe_api(setup_probe_fn_t fn)
65 {
66 	struct perf_pmu *pmu;
67 	struct perf_cpu_map *cpus;
68 	struct perf_cpu cpu;
69 	int ret = 0;
70 
71 	cpus = perf_cpu_map__new_online_cpus();
72 	if (!cpus)
73 		return false;
74 	cpu = perf_cpu_map__cpu(cpus, 0);
75 	perf_cpu_map__put(cpus);
76 
77 	ret = perf_do_probe_api(fn, cpu, "software/cpu-clock/u");
78 	if (!ret)
79 		return true;
80 
81 	pmu = perf_pmus__scan_core(/*pmu=*/NULL);
82 	if (pmu) {
83 		const char *try[] = {"cycles", "instructions", NULL};
84 		char buf[256];
85 		int i = 0;
86 
87 		while (ret == -EAGAIN && try[i]) {
88 			snprintf(buf, sizeof(buf), "%s/%s/u", pmu->name, try[i++]);
89 			ret = perf_do_probe_api(fn, cpu, buf);
90 			if (!ret)
91 				return true;
92 		}
93 	}
94 	return false;
95 }
96 
97 static void perf_probe_sample_identifier(struct evsel *evsel)
98 {
99 	evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
100 }
101 
102 static void perf_probe_comm_exec(struct evsel *evsel)
103 {
104 	evsel->core.attr.comm_exec = 1;
105 }
106 
107 static void perf_probe_context_switch(struct evsel *evsel)
108 {
109 	evsel->core.attr.context_switch = 1;
110 }
111 
112 static void perf_probe_text_poke(struct evsel *evsel)
113 {
114 	evsel->core.attr.text_poke = 1;
115 }
116 
117 static void perf_probe_build_id(struct evsel *evsel)
118 {
119 	evsel->core.attr.build_id = 1;
120 }
121 
122 static void perf_probe_cgroup(struct evsel *evsel)
123 {
124 	evsel->core.attr.cgroup = 1;
125 }
126 
127 bool perf_can_sample_identifier(void)
128 {
129 	return perf_probe_api(perf_probe_sample_identifier);
130 }
131 
132 bool perf_can_comm_exec(void)
133 {
134 	return perf_probe_api(perf_probe_comm_exec);
135 }
136 
137 bool perf_can_record_switch_events(void)
138 {
139 	return perf_probe_api(perf_probe_context_switch);
140 }
141 
142 bool perf_can_record_text_poke_events(void)
143 {
144 	return perf_probe_api(perf_probe_text_poke);
145 }
146 
147 bool perf_can_record_cpu_wide(void)
148 {
149 	struct perf_event_attr attr = {
150 		.type = PERF_TYPE_SOFTWARE,
151 		.config = PERF_COUNT_SW_CPU_CLOCK,
152 		.exclude_kernel = 1,
153 	};
154 	struct perf_cpu_map *cpus;
155 	struct perf_cpu cpu;
156 	int fd;
157 
158 	cpus = perf_cpu_map__new_online_cpus();
159 	if (!cpus)
160 		return false;
161 
162 	cpu = perf_cpu_map__cpu(cpus, 0);
163 	perf_cpu_map__put(cpus);
164 
165 	fd = sys_perf_event_open(&attr, -1, cpu.cpu, -1, 0);
166 	if (fd < 0)
167 		return false;
168 	close(fd);
169 
170 	return true;
171 }
172 
173 /*
174  * Architectures are expected to know if AUX area sampling is supported by the
175  * hardware. Here we check for kernel support.
176  */
177 bool perf_can_aux_sample(void)
178 {
179 	struct perf_event_attr attr = {
180 		.size = sizeof(struct perf_event_attr),
181 		.exclude_kernel = 1,
182 		/*
183 		 * Non-zero value causes the kernel to calculate the effective
184 		 * attribute size up to that byte.
185 		 */
186 		.aux_sample_size = 1,
187 	};
188 	int fd;
189 
190 	fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
191 	/*
192 	 * If the kernel attribute is big enough to contain aux_sample_size
193 	 * then we assume that it is supported. We are relying on the kernel to
194 	 * validate the attribute size before anything else that could be wrong.
195 	 */
196 	if (fd < 0 && errno == E2BIG)
197 		return false;
198 	if (fd >= 0)
199 		close(fd);
200 
201 	return true;
202 }
203 
204 bool perf_can_record_build_id(void)
205 {
206 	return perf_probe_api(perf_probe_build_id);
207 }
208 
209 bool perf_can_record_cgroup(void)
210 {
211 	return perf_probe_api(perf_probe_cgroup);
212 }
213