140c7d246SArnaldo Carvalho de Melo /* SPDX-License-Identifier: GPL-2.0 */
240c7d246SArnaldo Carvalho de Melo
340c7d246SArnaldo Carvalho de Melo #include "perf-sys.h"
440c7d246SArnaldo Carvalho de Melo #include "util/cloexec.h"
540c7d246SArnaldo Carvalho de Melo #include "util/evlist.h"
640c7d246SArnaldo Carvalho de Melo #include "util/evsel.h"
740c7d246SArnaldo Carvalho de Melo #include "util/parse-events.h"
840c7d246SArnaldo Carvalho de Melo #include "util/perf_api_probe.h"
940c7d246SArnaldo Carvalho de Melo #include <perf/cpumap.h>
1040c7d246SArnaldo Carvalho de Melo #include <errno.h>
1140c7d246SArnaldo Carvalho de Melo
1240c7d246SArnaldo Carvalho de Melo typedef void (*setup_probe_fn_t)(struct evsel *evsel);
1340c7d246SArnaldo Carvalho de Melo
perf_do_probe_api(setup_probe_fn_t fn,struct perf_cpu cpu,const char * str)146d18804bSIan Rogers static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str)
1540c7d246SArnaldo Carvalho de Melo {
1640c7d246SArnaldo Carvalho de Melo struct evlist *evlist;
1740c7d246SArnaldo Carvalho de Melo struct evsel *evsel;
1840c7d246SArnaldo Carvalho de Melo unsigned long flags = perf_event_open_cloexec_flag();
1940c7d246SArnaldo Carvalho de Melo int err = -EAGAIN, fd;
2040c7d246SArnaldo Carvalho de Melo static pid_t pid = -1;
2140c7d246SArnaldo Carvalho de Melo
2240c7d246SArnaldo Carvalho de Melo evlist = evlist__new();
2340c7d246SArnaldo Carvalho de Melo if (!evlist)
2440c7d246SArnaldo Carvalho de Melo return -ENOMEM;
2540c7d246SArnaldo Carvalho de Melo
26*806731a9SAdrian Hunter if (parse_event(evlist, str))
2740c7d246SArnaldo Carvalho de Melo goto out_delete;
2840c7d246SArnaldo Carvalho de Melo
2940c7d246SArnaldo Carvalho de Melo evsel = evlist__first(evlist);
3040c7d246SArnaldo Carvalho de Melo
3140c7d246SArnaldo Carvalho de Melo while (1) {
326d18804bSIan Rogers fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
3340c7d246SArnaldo Carvalho de Melo if (fd < 0) {
3440c7d246SArnaldo Carvalho de Melo if (pid == -1 && errno == EACCES) {
3540c7d246SArnaldo Carvalho de Melo pid = 0;
3640c7d246SArnaldo Carvalho de Melo continue;
3740c7d246SArnaldo Carvalho de Melo }
3840c7d246SArnaldo Carvalho de Melo goto out_delete;
3940c7d246SArnaldo Carvalho de Melo }
4040c7d246SArnaldo Carvalho de Melo break;
4140c7d246SArnaldo Carvalho de Melo }
4240c7d246SArnaldo Carvalho de Melo close(fd);
4340c7d246SArnaldo Carvalho de Melo
4440c7d246SArnaldo Carvalho de Melo fn(evsel);
4540c7d246SArnaldo Carvalho de Melo
466d18804bSIan Rogers fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
4740c7d246SArnaldo Carvalho de Melo if (fd < 0) {
4840c7d246SArnaldo Carvalho de Melo if (errno == EINVAL)
4940c7d246SArnaldo Carvalho de Melo err = -EINVAL;
5040c7d246SArnaldo Carvalho de Melo goto out_delete;
5140c7d246SArnaldo Carvalho de Melo }
5240c7d246SArnaldo Carvalho de Melo close(fd);
5340c7d246SArnaldo Carvalho de Melo err = 0;
5440c7d246SArnaldo Carvalho de Melo
5540c7d246SArnaldo Carvalho de Melo out_delete:
5640c7d246SArnaldo Carvalho de Melo evlist__delete(evlist);
5740c7d246SArnaldo Carvalho de Melo return err;
5840c7d246SArnaldo Carvalho de Melo }
5940c7d246SArnaldo Carvalho de Melo
perf_probe_api(setup_probe_fn_t fn)6040c7d246SArnaldo Carvalho de Melo static bool perf_probe_api(setup_probe_fn_t fn)
6140c7d246SArnaldo Carvalho de Melo {
6240c7d246SArnaldo Carvalho de Melo const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
6340c7d246SArnaldo Carvalho de Melo struct perf_cpu_map *cpus;
646d18804bSIan Rogers struct perf_cpu cpu;
656d18804bSIan Rogers int ret, i = 0;
6640c7d246SArnaldo Carvalho de Melo
6740c7d246SArnaldo Carvalho de Melo cpus = perf_cpu_map__new(NULL);
6840c7d246SArnaldo Carvalho de Melo if (!cpus)
6940c7d246SArnaldo Carvalho de Melo return false;
7044028699SIan Rogers cpu = perf_cpu_map__cpu(cpus, 0);
7140c7d246SArnaldo Carvalho de Melo perf_cpu_map__put(cpus);
7240c7d246SArnaldo Carvalho de Melo
7340c7d246SArnaldo Carvalho de Melo do {
7440c7d246SArnaldo Carvalho de Melo ret = perf_do_probe_api(fn, cpu, try[i++]);
7540c7d246SArnaldo Carvalho de Melo if (!ret)
7640c7d246SArnaldo Carvalho de Melo return true;
7740c7d246SArnaldo Carvalho de Melo } while (ret == -EAGAIN && try[i]);
7840c7d246SArnaldo Carvalho de Melo
7940c7d246SArnaldo Carvalho de Melo return false;
8040c7d246SArnaldo Carvalho de Melo }
8140c7d246SArnaldo Carvalho de Melo
perf_probe_sample_identifier(struct evsel * evsel)8240c7d246SArnaldo Carvalho de Melo static void perf_probe_sample_identifier(struct evsel *evsel)
8340c7d246SArnaldo Carvalho de Melo {
8440c7d246SArnaldo Carvalho de Melo evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
8540c7d246SArnaldo Carvalho de Melo }
8640c7d246SArnaldo Carvalho de Melo
perf_probe_comm_exec(struct evsel * evsel)8740c7d246SArnaldo Carvalho de Melo static void perf_probe_comm_exec(struct evsel *evsel)
8840c7d246SArnaldo Carvalho de Melo {
8940c7d246SArnaldo Carvalho de Melo evsel->core.attr.comm_exec = 1;
9040c7d246SArnaldo Carvalho de Melo }
9140c7d246SArnaldo Carvalho de Melo
perf_probe_context_switch(struct evsel * evsel)9240c7d246SArnaldo Carvalho de Melo static void perf_probe_context_switch(struct evsel *evsel)
9340c7d246SArnaldo Carvalho de Melo {
9440c7d246SArnaldo Carvalho de Melo evsel->core.attr.context_switch = 1;
9540c7d246SArnaldo Carvalho de Melo }
9640c7d246SArnaldo Carvalho de Melo
perf_probe_text_poke(struct evsel * evsel)97246eba8eSAdrian Hunter static void perf_probe_text_poke(struct evsel *evsel)
98246eba8eSAdrian Hunter {
99246eba8eSAdrian Hunter evsel->core.attr.text_poke = 1;
100246eba8eSAdrian Hunter }
101246eba8eSAdrian Hunter
perf_probe_build_id(struct evsel * evsel)102e29386c8SJiri Olsa static void perf_probe_build_id(struct evsel *evsel)
103e29386c8SJiri Olsa {
104e29386c8SJiri Olsa evsel->core.attr.build_id = 1;
105e29386c8SJiri Olsa }
106e29386c8SJiri Olsa
perf_probe_cgroup(struct evsel * evsel)1074f2abe91SNamhyung Kim static void perf_probe_cgroup(struct evsel *evsel)
1084f2abe91SNamhyung Kim {
1094f2abe91SNamhyung Kim evsel->core.attr.cgroup = 1;
1104f2abe91SNamhyung Kim }
1114f2abe91SNamhyung Kim
perf_can_sample_identifier(void)11240c7d246SArnaldo Carvalho de Melo bool perf_can_sample_identifier(void)
11340c7d246SArnaldo Carvalho de Melo {
11440c7d246SArnaldo Carvalho de Melo return perf_probe_api(perf_probe_sample_identifier);
11540c7d246SArnaldo Carvalho de Melo }
11640c7d246SArnaldo Carvalho de Melo
perf_can_comm_exec(void)11740c7d246SArnaldo Carvalho de Melo bool perf_can_comm_exec(void)
11840c7d246SArnaldo Carvalho de Melo {
11940c7d246SArnaldo Carvalho de Melo return perf_probe_api(perf_probe_comm_exec);
12040c7d246SArnaldo Carvalho de Melo }
12140c7d246SArnaldo Carvalho de Melo
perf_can_record_switch_events(void)12240c7d246SArnaldo Carvalho de Melo bool perf_can_record_switch_events(void)
12340c7d246SArnaldo Carvalho de Melo {
12440c7d246SArnaldo Carvalho de Melo return perf_probe_api(perf_probe_context_switch);
12540c7d246SArnaldo Carvalho de Melo }
12640c7d246SArnaldo Carvalho de Melo
perf_can_record_text_poke_events(void)127246eba8eSAdrian Hunter bool perf_can_record_text_poke_events(void)
128246eba8eSAdrian Hunter {
129246eba8eSAdrian Hunter return perf_probe_api(perf_probe_text_poke);
130246eba8eSAdrian Hunter }
131246eba8eSAdrian Hunter
perf_can_record_cpu_wide(void)13240c7d246SArnaldo Carvalho de Melo bool perf_can_record_cpu_wide(void)
13340c7d246SArnaldo Carvalho de Melo {
13440c7d246SArnaldo Carvalho de Melo struct perf_event_attr attr = {
13540c7d246SArnaldo Carvalho de Melo .type = PERF_TYPE_SOFTWARE,
13640c7d246SArnaldo Carvalho de Melo .config = PERF_COUNT_SW_CPU_CLOCK,
13740c7d246SArnaldo Carvalho de Melo .exclude_kernel = 1,
13840c7d246SArnaldo Carvalho de Melo };
13940c7d246SArnaldo Carvalho de Melo struct perf_cpu_map *cpus;
1406d18804bSIan Rogers struct perf_cpu cpu;
1416d18804bSIan Rogers int fd;
14240c7d246SArnaldo Carvalho de Melo
14340c7d246SArnaldo Carvalho de Melo cpus = perf_cpu_map__new(NULL);
14440c7d246SArnaldo Carvalho de Melo if (!cpus)
14540c7d246SArnaldo Carvalho de Melo return false;
1466d18804bSIan Rogers
14744028699SIan Rogers cpu = perf_cpu_map__cpu(cpus, 0);
14840c7d246SArnaldo Carvalho de Melo perf_cpu_map__put(cpus);
14940c7d246SArnaldo Carvalho de Melo
1506d18804bSIan Rogers fd = sys_perf_event_open(&attr, -1, cpu.cpu, -1, 0);
15140c7d246SArnaldo Carvalho de Melo if (fd < 0)
15240c7d246SArnaldo Carvalho de Melo return false;
15340c7d246SArnaldo Carvalho de Melo close(fd);
15440c7d246SArnaldo Carvalho de Melo
15540c7d246SArnaldo Carvalho de Melo return true;
15640c7d246SArnaldo Carvalho de Melo }
15740c7d246SArnaldo Carvalho de Melo
15840c7d246SArnaldo Carvalho de Melo /*
15940c7d246SArnaldo Carvalho de Melo * Architectures are expected to know if AUX area sampling is supported by the
16040c7d246SArnaldo Carvalho de Melo * hardware. Here we check for kernel support.
16140c7d246SArnaldo Carvalho de Melo */
perf_can_aux_sample(void)16240c7d246SArnaldo Carvalho de Melo bool perf_can_aux_sample(void)
16340c7d246SArnaldo Carvalho de Melo {
16440c7d246SArnaldo Carvalho de Melo struct perf_event_attr attr = {
16540c7d246SArnaldo Carvalho de Melo .size = sizeof(struct perf_event_attr),
16640c7d246SArnaldo Carvalho de Melo .exclude_kernel = 1,
16740c7d246SArnaldo Carvalho de Melo /*
16840c7d246SArnaldo Carvalho de Melo * Non-zero value causes the kernel to calculate the effective
16940c7d246SArnaldo Carvalho de Melo * attribute size up to that byte.
17040c7d246SArnaldo Carvalho de Melo */
17140c7d246SArnaldo Carvalho de Melo .aux_sample_size = 1,
17240c7d246SArnaldo Carvalho de Melo };
17340c7d246SArnaldo Carvalho de Melo int fd;
17440c7d246SArnaldo Carvalho de Melo
17540c7d246SArnaldo Carvalho de Melo fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
17640c7d246SArnaldo Carvalho de Melo /*
17740c7d246SArnaldo Carvalho de Melo * If the kernel attribute is big enough to contain aux_sample_size
17840c7d246SArnaldo Carvalho de Melo * then we assume that it is supported. We are relying on the kernel to
17940c7d246SArnaldo Carvalho de Melo * validate the attribute size before anything else that could be wrong.
18040c7d246SArnaldo Carvalho de Melo */
18140c7d246SArnaldo Carvalho de Melo if (fd < 0 && errno == E2BIG)
18240c7d246SArnaldo Carvalho de Melo return false;
18340c7d246SArnaldo Carvalho de Melo if (fd >= 0)
18440c7d246SArnaldo Carvalho de Melo close(fd);
18540c7d246SArnaldo Carvalho de Melo
18640c7d246SArnaldo Carvalho de Melo return true;
18740c7d246SArnaldo Carvalho de Melo }
188e29386c8SJiri Olsa
perf_can_record_build_id(void)189e29386c8SJiri Olsa bool perf_can_record_build_id(void)
190e29386c8SJiri Olsa {
191e29386c8SJiri Olsa return perf_probe_api(perf_probe_build_id);
192e29386c8SJiri Olsa }
1934f2abe91SNamhyung Kim
perf_can_record_cgroup(void)1944f2abe91SNamhyung Kim bool perf_can_record_cgroup(void)
1954f2abe91SNamhyung Kim {
1964f2abe91SNamhyung Kim return perf_probe_api(perf_probe_cgroup);
1974f2abe91SNamhyung Kim }
198