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