xref: /openbmc/linux/tools/perf/util/perf_api_probe.c (revision 806731a9)
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