]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
b4209025 | 2 | #include "debug.h" |
faf96706 AH |
3 | #include "evlist.h" |
4 | #include "evsel.h" | |
75562573 | 5 | #include "parse-events.h" |
a43783ae | 6 | #include <errno.h> |
f2a39fe8 ACM |
7 | #include <limits.h> |
8 | #include <stdlib.h> | |
cd0cfad7 | 9 | #include <api/fs/fs.h> |
67230479 | 10 | #include <subcmd/parse-options.h> |
9c3516d1 | 11 | #include <perf/cpumap.h> |
57480d2c | 12 | #include "cloexec.h" |
aeb00b1a | 13 | #include "record.h" |
91854f9a | 14 | #include "../perf-sys.h" |
75562573 | 15 | |
32dcd021 | 16 | typedef void (*setup_probe_fn_t)(struct evsel *evsel); |
75562573 AH |
17 | |
18 | static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) | |
19 | { | |
63503dba | 20 | struct evlist *evlist; |
32dcd021 | 21 | struct evsel *evsel; |
57480d2c | 22 | unsigned long flags = perf_event_open_cloexec_flag(); |
75562573 | 23 | int err = -EAGAIN, fd; |
46ec69ad | 24 | static pid_t pid = -1; |
75562573 | 25 | |
0f98b11c | 26 | evlist = evlist__new(); |
75562573 AH |
27 | if (!evlist) |
28 | return -ENOMEM; | |
29 | ||
b39b8393 | 30 | if (parse_events(evlist, str, NULL)) |
75562573 AH |
31 | goto out_delete; |
32 | ||
515dbe48 | 33 | evsel = evlist__first(evlist); |
75562573 | 34 | |
46ec69ad | 35 | while (1) { |
1fc632ce | 36 | fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); |
46ec69ad AH |
37 | if (fd < 0) { |
38 | if (pid == -1 && errno == EACCES) { | |
39 | pid = 0; | |
40 | continue; | |
41 | } | |
42 | goto out_delete; | |
43 | } | |
44 | break; | |
45 | } | |
75562573 AH |
46 | close(fd); |
47 | ||
48 | fn(evsel); | |
49 | ||
1fc632ce | 50 | fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); |
75562573 AH |
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: | |
c12995a5 | 60 | evlist__delete(evlist); |
75562573 AH |
61 | return err; |
62 | } | |
63 | ||
64 | static bool perf_probe_api(setup_probe_fn_t fn) | |
65 | { | |
c6fa3565 | 66 | const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL}; |
f854839b | 67 | struct perf_cpu_map *cpus; |
75562573 AH |
68 | int cpu, ret, i = 0; |
69 | ||
9c3516d1 | 70 | cpus = perf_cpu_map__new(NULL); |
75562573 AH |
71 | if (!cpus) |
72 | return false; | |
73 | cpu = cpus->map[0]; | |
38f01d8d | 74 | perf_cpu_map__put(cpus); |
75562573 AH |
75 | |
76 | do { | |
77 | ret = perf_do_probe_api(fn, cpu, try[i++]); | |
78 | if (!ret) | |
79 | return true; | |
80 | } while (ret == -EAGAIN && try[i]); | |
81 | ||
82 | return false; | |
83 | } | |
84 | ||
32dcd021 | 85 | static void perf_probe_sample_identifier(struct evsel *evsel) |
75562573 | 86 | { |
1fc632ce | 87 | evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER; |
75562573 AH |
88 | } |
89 | ||
32dcd021 | 90 | static void perf_probe_comm_exec(struct evsel *evsel) |
39e09d40 | 91 | { |
1fc632ce | 92 | evsel->core.attr.comm_exec = 1; |
39e09d40 AH |
93 | } |
94 | ||
32dcd021 | 95 | static void perf_probe_context_switch(struct evsel *evsel) |
b757bb09 | 96 | { |
1fc632ce | 97 | evsel->core.attr.context_switch = 1; |
b757bb09 AH |
98 | } |
99 | ||
75562573 AH |
100 | bool perf_can_sample_identifier(void) |
101 | { | |
102 | return perf_probe_api(perf_probe_sample_identifier); | |
103 | } | |
faf96706 | 104 | |
39e09d40 AH |
105 | static bool perf_can_comm_exec(void) |
106 | { | |
107 | return perf_probe_api(perf_probe_comm_exec); | |
108 | } | |
109 | ||
b757bb09 AH |
110 | bool perf_can_record_switch_events(void) |
111 | { | |
112 | return perf_probe_api(perf_probe_context_switch); | |
113 | } | |
114 | ||
83509565 AH |
115 | bool perf_can_record_cpu_wide(void) |
116 | { | |
117 | struct perf_event_attr attr = { | |
118 | .type = PERF_TYPE_SOFTWARE, | |
119 | .config = PERF_COUNT_SW_CPU_CLOCK, | |
120 | .exclude_kernel = 1, | |
121 | }; | |
f854839b | 122 | struct perf_cpu_map *cpus; |
83509565 AH |
123 | int cpu, fd; |
124 | ||
9c3516d1 | 125 | cpus = perf_cpu_map__new(NULL); |
83509565 AH |
126 | if (!cpus) |
127 | return false; | |
128 | cpu = cpus->map[0]; | |
38f01d8d | 129 | perf_cpu_map__put(cpus); |
83509565 AH |
130 | |
131 | fd = sys_perf_event_open(&attr, -1, cpu, -1, 0); | |
132 | if (fd < 0) | |
133 | return false; | |
134 | close(fd); | |
135 | ||
136 | return true; | |
137 | } | |
138 | ||
9bca1a4e AH |
139 | /* |
140 | * Architectures are expected to know if AUX area sampling is supported by the | |
141 | * hardware. Here we check for kernel support. | |
142 | */ | |
143 | bool perf_can_aux_sample(void) | |
144 | { | |
145 | struct perf_event_attr attr = { | |
146 | .size = sizeof(struct perf_event_attr), | |
147 | .exclude_kernel = 1, | |
148 | /* | |
149 | * Non-zero value causes the kernel to calculate the effective | |
150 | * attribute size up to that byte. | |
151 | */ | |
152 | .aux_sample_size = 1, | |
153 | }; | |
154 | int fd; | |
155 | ||
156 | fd = sys_perf_event_open(&attr, -1, 0, -1, 0); | |
157 | /* | |
158 | * If the kernel attribute is big enough to contain aux_sample_size | |
159 | * then we assume that it is supported. We are relying on the kernel to | |
160 | * validate the attribute size before anything else that could be wrong. | |
161 | */ | |
162 | if (fd < 0 && errno == E2BIG) | |
163 | return false; | |
164 | if (fd >= 0) | |
165 | close(fd); | |
166 | ||
167 | return true; | |
168 | } | |
169 | ||
5f342788 AH |
170 | static void perf_evsel__config_leader_sampling(struct evsel *evsel) |
171 | { | |
172 | struct perf_event_attr *attr = &evsel->core.attr; | |
173 | struct evsel *leader = evsel->leader; | |
174 | ||
175 | /* | |
176 | * Disable sampling for all group members other | |
177 | * than leader in case leader 'leads' the sampling. | |
178 | */ | |
179 | if (leader != evsel && leader->sample_read) { | |
180 | attr->freq = 0; | |
181 | attr->sample_freq = 0; | |
182 | attr->sample_period = 0; | |
183 | attr->write_backward = 0; | |
184 | ||
185 | /* | |
186 | * We don't get sample for slave events, we make them | |
187 | * when delivering group leader sample. Set the slave | |
188 | * event to follow the master sample_type to ease up | |
189 | * report. | |
190 | */ | |
191 | attr->sample_type = leader->core.attr.sample_type; | |
192 | } | |
193 | } | |
194 | ||
63503dba | 195 | void perf_evlist__config(struct evlist *evlist, struct record_opts *opts, |
e68ae9cf | 196 | struct callchain_param *callchain) |
faf96706 | 197 | { |
32dcd021 | 198 | struct evsel *evsel; |
75562573 | 199 | bool use_sample_identifier = false; |
39e09d40 | 200 | bool use_comm_exec; |
ad46e48c | 201 | bool sample_id = opts->sample_id; |
75562573 | 202 | |
faf96706 AH |
203 | /* |
204 | * Set the evsel leader links before we configure attributes, | |
205 | * since some might depend on this info. | |
206 | */ | |
207 | if (opts->group) | |
208 | perf_evlist__set_leader(evlist); | |
209 | ||
f72f901d | 210 | if (evlist->core.cpus->map[0] < 0) |
faf96706 AH |
211 | opts->no_inherit = true; |
212 | ||
39e09d40 AH |
213 | use_comm_exec = perf_can_comm_exec(); |
214 | ||
e5cadb93 | 215 | evlist__for_each_entry(evlist, evsel) { |
e68ae9cf | 216 | perf_evsel__config(evsel, opts, callchain); |
60b0896c | 217 | if (evsel->tracking && use_comm_exec) |
1fc632ce | 218 | evsel->core.attr.comm_exec = 1; |
39e09d40 | 219 | } |
faf96706 | 220 | |
5f342788 AH |
221 | /* Configure leader sampling here now that the sample type is known */ |
222 | evlist__for_each_entry(evlist, evsel) | |
223 | perf_evsel__config_leader_sampling(evsel); | |
224 | ||
9e0cc4fe AH |
225 | if (opts->full_auxtrace) { |
226 | /* | |
227 | * Need to be able to synthesize and parse selected events with | |
228 | * arbitrary sample types, which requires always being able to | |
229 | * match the id. | |
230 | */ | |
231 | use_sample_identifier = perf_can_sample_identifier(); | |
ad46e48c | 232 | sample_id = true; |
6484d2f9 | 233 | } else if (evlist->core.nr_entries > 1) { |
515dbe48 | 234 | struct evsel *first = evlist__first(evlist); |
75562573 | 235 | |
e5cadb93 | 236 | evlist__for_each_entry(evlist, evsel) { |
1fc632ce | 237 | if (evsel->core.attr.sample_type == first->core.attr.sample_type) |
75562573 AH |
238 | continue; |
239 | use_sample_identifier = perf_can_sample_identifier(); | |
240 | break; | |
241 | } | |
ad46e48c JO |
242 | sample_id = true; |
243 | } | |
244 | ||
245 | if (sample_id) { | |
e5cadb93 | 246 | evlist__for_each_entry(evlist, evsel) |
75562573 | 247 | perf_evsel__set_sample_id(evsel, use_sample_identifier); |
faf96706 | 248 | } |
75562573 AH |
249 | |
250 | perf_evlist__set_id_pos(evlist); | |
faf96706 | 251 | } |
714647bd JO |
252 | |
253 | static int get_max_rate(unsigned int *rate) | |
254 | { | |
ce27309f | 255 | return sysctl__read_int("kernel/perf_event_max_sample_rate", (int *)rate); |
714647bd JO |
256 | } |
257 | ||
b4006796 | 258 | static int record_opts__config_freq(struct record_opts *opts) |
714647bd JO |
259 | { |
260 | bool user_freq = opts->user_freq != UINT_MAX; | |
261 | unsigned int max_rate; | |
262 | ||
263 | if (opts->user_interval != ULLONG_MAX) | |
264 | opts->default_interval = opts->user_interval; | |
265 | if (user_freq) | |
266 | opts->freq = opts->user_freq; | |
267 | ||
268 | /* | |
269 | * User specified count overrides default frequency. | |
270 | */ | |
271 | if (opts->default_interval) | |
272 | opts->freq = 0; | |
273 | else if (opts->freq) { | |
274 | opts->default_interval = opts->freq; | |
275 | } else { | |
276 | pr_err("frequency and count are zero, aborting\n"); | |
277 | return -1; | |
278 | } | |
279 | ||
280 | if (get_max_rate(&max_rate)) | |
281 | return 0; | |
282 | ||
283 | /* | |
284 | * User specified frequency is over current maximum. | |
285 | */ | |
286 | if (user_freq && (max_rate < opts->freq)) { | |
b09c2364 ACM |
287 | if (opts->strict_freq) { |
288 | pr_err("error: Maximum frequency rate (%'u Hz) exceeded.\n" | |
289 | " Please use -F freq option with a lower value or consider\n" | |
290 | " tweaking /proc/sys/kernel/perf_event_max_sample_rate.\n", | |
291 | max_rate); | |
292 | return -1; | |
293 | } else { | |
294 | pr_warning("warning: Maximum frequency rate (%'u Hz) exceeded, throttling from %'u Hz to %'u Hz.\n" | |
295 | " The limit can be raised via /proc/sys/kernel/perf_event_max_sample_rate.\n" | |
296 | " The kernel will lower it when perf's interrupts take too long.\n" | |
297 | " Use --strict-freq to disable this throttling, refusing to record.\n", | |
298 | max_rate, opts->freq, max_rate); | |
299 | ||
300 | opts->freq = max_rate; | |
301 | } | |
714647bd JO |
302 | } |
303 | ||
304 | /* | |
305 | * Default frequency is over current maximum. | |
306 | */ | |
307 | if (max_rate < opts->freq) { | |
308 | pr_warning("Lowering default frequency rate to %u.\n" | |
309 | "Please consider tweaking " | |
310 | "/proc/sys/kernel/perf_event_max_sample_rate.\n", | |
311 | max_rate); | |
312 | opts->freq = max_rate; | |
313 | } | |
314 | ||
315 | return 0; | |
316 | } | |
317 | ||
b4006796 | 318 | int record_opts__config(struct record_opts *opts) |
714647bd | 319 | { |
b4006796 | 320 | return record_opts__config_freq(opts); |
714647bd | 321 | } |
c09ec622 | 322 | |
63503dba | 323 | bool perf_evlist__can_select_event(struct evlist *evlist, const char *str) |
c09ec622 | 324 | { |
63503dba | 325 | struct evlist *temp_evlist; |
32dcd021 | 326 | struct evsel *evsel; |
c09ec622 AH |
327 | int err, fd, cpu; |
328 | bool ret = false; | |
46ec69ad | 329 | pid_t pid = -1; |
c09ec622 | 330 | |
0f98b11c | 331 | temp_evlist = evlist__new(); |
c09ec622 AH |
332 | if (!temp_evlist) |
333 | return false; | |
334 | ||
b39b8393 | 335 | err = parse_events(temp_evlist, str, NULL); |
c09ec622 AH |
336 | if (err) |
337 | goto out_delete; | |
338 | ||
515dbe48 | 339 | evsel = evlist__last(temp_evlist); |
c09ec622 | 340 | |
315c0a1f | 341 | if (!evlist || perf_cpu_map__empty(evlist->core.cpus)) { |
9c3516d1 | 342 | struct perf_cpu_map *cpus = perf_cpu_map__new(NULL); |
c09ec622 AH |
343 | |
344 | cpu = cpus ? cpus->map[0] : 0; | |
38f01d8d | 345 | perf_cpu_map__put(cpus); |
c09ec622 | 346 | } else { |
f72f901d | 347 | cpu = evlist->core.cpus->map[0]; |
c09ec622 AH |
348 | } |
349 | ||
46ec69ad | 350 | while (1) { |
1fc632ce | 351 | fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, |
46ec69ad AH |
352 | perf_event_open_cloexec_flag()); |
353 | if (fd < 0) { | |
354 | if (pid == -1 && errno == EACCES) { | |
355 | pid = 0; | |
356 | continue; | |
357 | } | |
358 | goto out_delete; | |
359 | } | |
360 | break; | |
c09ec622 | 361 | } |
46ec69ad AH |
362 | close(fd); |
363 | ret = true; | |
c09ec622 AH |
364 | |
365 | out_delete: | |
c12995a5 | 366 | evlist__delete(temp_evlist); |
c09ec622 AH |
367 | return ret; |
368 | } | |
67230479 ACM |
369 | |
370 | int record__parse_freq(const struct option *opt, const char *str, int unset __maybe_unused) | |
371 | { | |
372 | unsigned int freq; | |
373 | struct record_opts *opts = opt->value; | |
374 | ||
375 | if (!str) | |
376 | return -EINVAL; | |
377 | ||
378 | if (strcasecmp(str, "max") == 0) { | |
379 | if (get_max_rate(&freq)) { | |
380 | pr_err("couldn't read /proc/sys/kernel/perf_event_max_sample_rate\n"); | |
381 | return -1; | |
382 | } | |
383 | pr_info("info: Using a maximum frequency rate of %'d Hz\n", freq); | |
384 | } else { | |
385 | freq = atoi(str); | |
386 | } | |
387 | ||
388 | opts->user_freq = freq; | |
389 | return 0; | |
390 | } |