xref: /openbmc/linux/samples/bpf/trace_event_user.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21c47910eSAlexei Starovoitov /* Copyright (c) 2016 Facebook
31c47910eSAlexei Starovoitov  */
41c47910eSAlexei Starovoitov #include <stdio.h>
51c47910eSAlexei Starovoitov #include <unistd.h>
61c47910eSAlexei Starovoitov #include <stdlib.h>
71c47910eSAlexei Starovoitov #include <stdbool.h>
81c47910eSAlexei Starovoitov #include <string.h>
91c47910eSAlexei Starovoitov #include <linux/perf_event.h>
101c47910eSAlexei Starovoitov #include <linux/bpf.h>
111c47910eSAlexei Starovoitov #include <signal.h>
121c47910eSAlexei Starovoitov #include <errno.h>
131c47910eSAlexei Starovoitov #include <sys/resource.h>
14aa5e2af6SDaniel T. Lee #include <bpf/bpf.h>
157cf245a3SToke Høiland-Jørgensen #include <bpf/libbpf.h>
16205c8adaSJoe Stringer #include "perf-sys.h"
1728dbf861SYonghong Song #include "trace_helpers.h"
181c47910eSAlexei Starovoitov 
191c47910eSAlexei Starovoitov #define SAMPLE_FREQ 50
201c47910eSAlexei Starovoitov 
21aa5e2af6SDaniel T. Lee static int pid;
22aa5e2af6SDaniel T. Lee /* counts, stackmap */
23aa5e2af6SDaniel T. Lee static int map_fd[2];
24aa5e2af6SDaniel T. Lee struct bpf_program *prog;
251c47910eSAlexei Starovoitov static bool sys_read_seen, sys_write_seen;
261c47910eSAlexei Starovoitov 
print_ksym(__u64 addr)271c47910eSAlexei Starovoitov static void print_ksym(__u64 addr)
281c47910eSAlexei Starovoitov {
291c47910eSAlexei Starovoitov 	struct ksym *sym;
301c47910eSAlexei Starovoitov 
311c47910eSAlexei Starovoitov 	if (!addr)
321c47910eSAlexei Starovoitov 		return;
331c47910eSAlexei Starovoitov 	sym = ksym_search(addr);
34e67b2c71SDaniel T. Lee 	if (!sym) {
35e67b2c71SDaniel T. Lee 		printf("ksym not found. Is kallsyms loaded?\n");
36e67b2c71SDaniel T. Lee 		return;
37e67b2c71SDaniel T. Lee 	}
38e67b2c71SDaniel T. Lee 
391c47910eSAlexei Starovoitov 	printf("%s;", sym->name);
40bba1b2a8SDaniel T. Lee 	if (!strstr(sym->name, "sys_read"))
411c47910eSAlexei Starovoitov 		sys_read_seen = true;
42bba1b2a8SDaniel T. Lee 	else if (!strstr(sym->name, "sys_write"))
431c47910eSAlexei Starovoitov 		sys_write_seen = true;
441c47910eSAlexei Starovoitov }
451c47910eSAlexei Starovoitov 
print_addr(__u64 addr)461c47910eSAlexei Starovoitov static void print_addr(__u64 addr)
471c47910eSAlexei Starovoitov {
481c47910eSAlexei Starovoitov 	if (!addr)
491c47910eSAlexei Starovoitov 		return;
501c47910eSAlexei Starovoitov 	printf("%llx;", addr);
511c47910eSAlexei Starovoitov }
521c47910eSAlexei Starovoitov 
531c47910eSAlexei Starovoitov #define TASK_COMM_LEN 16
541c47910eSAlexei Starovoitov 
551c47910eSAlexei Starovoitov struct key_t {
561c47910eSAlexei Starovoitov 	char comm[TASK_COMM_LEN];
571c47910eSAlexei Starovoitov 	__u32 kernstack;
581c47910eSAlexei Starovoitov 	__u32 userstack;
591c47910eSAlexei Starovoitov };
601c47910eSAlexei Starovoitov 
print_stack(struct key_t * key,__u64 count)611c47910eSAlexei Starovoitov static void print_stack(struct key_t *key, __u64 count)
621c47910eSAlexei Starovoitov {
631c47910eSAlexei Starovoitov 	__u64 ip[PERF_MAX_STACK_DEPTH] = {};
641c47910eSAlexei Starovoitov 	static bool warned;
651c47910eSAlexei Starovoitov 	int i;
661c47910eSAlexei Starovoitov 
671c47910eSAlexei Starovoitov 	printf("%3lld %s;", count, key->comm);
68d40fc181SJoe Stringer 	if (bpf_map_lookup_elem(map_fd[1], &key->kernstack, ip) != 0) {
691c47910eSAlexei Starovoitov 		printf("---;");
701c47910eSAlexei Starovoitov 	} else {
711c47910eSAlexei Starovoitov 		for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--)
721c47910eSAlexei Starovoitov 			print_ksym(ip[i]);
731c47910eSAlexei Starovoitov 	}
741c47910eSAlexei Starovoitov 	printf("-;");
75d40fc181SJoe Stringer 	if (bpf_map_lookup_elem(map_fd[1], &key->userstack, ip) != 0) {
761c47910eSAlexei Starovoitov 		printf("---;");
771c47910eSAlexei Starovoitov 	} else {
781c47910eSAlexei Starovoitov 		for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--)
791c47910eSAlexei Starovoitov 			print_addr(ip[i]);
801c47910eSAlexei Starovoitov 	}
8141e9a804STeng Qin 	if (count < 6)
8241e9a804STeng Qin 		printf("\r");
8341e9a804STeng Qin 	else
841c47910eSAlexei Starovoitov 		printf("\n");
851c47910eSAlexei Starovoitov 
861c47910eSAlexei Starovoitov 	if (key->kernstack == -EEXIST && !warned) {
871c47910eSAlexei Starovoitov 		printf("stackmap collisions seen. Consider increasing size\n");
881c47910eSAlexei Starovoitov 		warned = true;
891c47910eSAlexei Starovoitov 	} else if ((int)key->kernstack < 0 && (int)key->userstack < 0) {
901c47910eSAlexei Starovoitov 		printf("err stackid %d %d\n", key->kernstack, key->userstack);
911c47910eSAlexei Starovoitov 	}
921c47910eSAlexei Starovoitov }
931c47910eSAlexei Starovoitov 
err_exit(int err)94aa5e2af6SDaniel T. Lee static void err_exit(int err)
951c47910eSAlexei Starovoitov {
96aa5e2af6SDaniel T. Lee 	kill(pid, SIGKILL);
97aa5e2af6SDaniel T. Lee 	exit(err);
981c47910eSAlexei Starovoitov }
991c47910eSAlexei Starovoitov 
print_stacks(void)1001c47910eSAlexei Starovoitov static void print_stacks(void)
1011c47910eSAlexei Starovoitov {
1021c47910eSAlexei Starovoitov 	struct key_t key = {}, next_key;
1031c47910eSAlexei Starovoitov 	__u64 value;
1041c47910eSAlexei Starovoitov 	__u32 stackid = 0, next_id;
105aa5e2af6SDaniel T. Lee 	int error = 1, fd = map_fd[0], stack_map = map_fd[1];
1061c47910eSAlexei Starovoitov 
1071c47910eSAlexei Starovoitov 	sys_read_seen = sys_write_seen = false;
108d40fc181SJoe Stringer 	while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
109d40fc181SJoe Stringer 		bpf_map_lookup_elem(fd, &next_key, &value);
1101c47910eSAlexei Starovoitov 		print_stack(&next_key, value);
111d40fc181SJoe Stringer 		bpf_map_delete_elem(fd, &next_key);
1121c47910eSAlexei Starovoitov 		key = next_key;
1131c47910eSAlexei Starovoitov 	}
11441e9a804STeng Qin 	printf("\n");
1151c47910eSAlexei Starovoitov 	if (!sys_read_seen || !sys_write_seen) {
1161c47910eSAlexei Starovoitov 		printf("BUG kernel stack doesn't contain sys_read() and sys_write()\n");
117aa5e2af6SDaniel T. Lee 		err_exit(error);
1181c47910eSAlexei Starovoitov 	}
1191c47910eSAlexei Starovoitov 
1201c47910eSAlexei Starovoitov 	/* clear stack map */
121d40fc181SJoe Stringer 	while (bpf_map_get_next_key(stack_map, &stackid, &next_id) == 0) {
122d40fc181SJoe Stringer 		bpf_map_delete_elem(stack_map, &next_id);
1231c47910eSAlexei Starovoitov 		stackid = next_id;
1241c47910eSAlexei Starovoitov 	}
1251c47910eSAlexei Starovoitov }
1261c47910eSAlexei Starovoitov 
generate_load(void)127492b7e89STaeung Song static inline int generate_load(void)
128492b7e89STaeung Song {
129492b7e89STaeung Song 	if (system("dd if=/dev/zero of=/dev/null count=5000k status=none") < 0) {
130492b7e89STaeung Song 		printf("failed to generate some load with dd: %s\n", strerror(errno));
131492b7e89STaeung Song 		return -1;
132492b7e89STaeung Song 	}
133492b7e89STaeung Song 
134492b7e89STaeung Song 	return 0;
135492b7e89STaeung Song }
136492b7e89STaeung Song 
test_perf_event_all_cpu(struct perf_event_attr * attr)1371c47910eSAlexei Starovoitov static void test_perf_event_all_cpu(struct perf_event_attr *attr)
1381c47910eSAlexei Starovoitov {
139aa5e2af6SDaniel T. Lee 	int nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
140aa5e2af6SDaniel T. Lee 	struct bpf_link **links = calloc(nr_cpus, sizeof(struct bpf_link *));
141aa5e2af6SDaniel T. Lee 	int i, pmu_fd, error = 1;
142aa5e2af6SDaniel T. Lee 
143aa5e2af6SDaniel T. Lee 	if (!links) {
144aa5e2af6SDaniel T. Lee 		printf("malloc of links failed\n");
145aa5e2af6SDaniel T. Lee 		goto err;
146aa5e2af6SDaniel T. Lee 	}
1471c47910eSAlexei Starovoitov 
14881b9cf80SYonghong Song 	/* system wide perf event, no need to inherit */
14981b9cf80SYonghong Song 	attr->inherit = 0;
15081b9cf80SYonghong Song 
1511c47910eSAlexei Starovoitov 	/* open perf_event on all cpus */
1521c47910eSAlexei Starovoitov 	for (i = 0; i < nr_cpus; i++) {
153aa5e2af6SDaniel T. Lee 		pmu_fd = sys_perf_event_open(attr, -1, i, -1, 0);
154aa5e2af6SDaniel T. Lee 		if (pmu_fd < 0) {
155205c8adaSJoe Stringer 			printf("sys_perf_event_open failed\n");
1561c47910eSAlexei Starovoitov 			goto all_cpu_err;
1571c47910eSAlexei Starovoitov 		}
158aa5e2af6SDaniel T. Lee 		links[i] = bpf_program__attach_perf_event(prog, pmu_fd);
159*0efdcefbSDaniel T. Lee 		if (libbpf_get_error(links[i])) {
160aa5e2af6SDaniel T. Lee 			printf("bpf_program__attach_perf_event failed\n");
161aa5e2af6SDaniel T. Lee 			links[i] = NULL;
162aa5e2af6SDaniel T. Lee 			close(pmu_fd);
163aa5e2af6SDaniel T. Lee 			goto all_cpu_err;
164aa5e2af6SDaniel T. Lee 		}
1651c47910eSAlexei Starovoitov 	}
166492b7e89STaeung Song 
167aa5e2af6SDaniel T. Lee 	if (generate_load() < 0)
168492b7e89STaeung Song 		goto all_cpu_err;
169aa5e2af6SDaniel T. Lee 
1701c47910eSAlexei Starovoitov 	print_stacks();
171aa5e2af6SDaniel T. Lee 	error = 0;
1721c47910eSAlexei Starovoitov all_cpu_err:
173aa5e2af6SDaniel T. Lee 	for (i--; i >= 0; i--)
174aa5e2af6SDaniel T. Lee 		bpf_link__destroy(links[i]);
175aa5e2af6SDaniel T. Lee err:
176aa5e2af6SDaniel T. Lee 	free(links);
17741e9a804STeng Qin 	if (error)
178aa5e2af6SDaniel T. Lee 		err_exit(error);
1791c47910eSAlexei Starovoitov }
1801c47910eSAlexei Starovoitov 
test_perf_event_task(struct perf_event_attr * attr)1811c47910eSAlexei Starovoitov static void test_perf_event_task(struct perf_event_attr *attr)
1821c47910eSAlexei Starovoitov {
183aa5e2af6SDaniel T. Lee 	struct bpf_link *link = NULL;
184aa5e2af6SDaniel T. Lee 	int pmu_fd, error = 1;
1851c47910eSAlexei Starovoitov 
18681b9cf80SYonghong Song 	/* per task perf event, enable inherit so the "dd ..." command can be traced properly.
18781b9cf80SYonghong Song 	 * Enabling inherit will cause bpf_perf_prog_read_time helper failure.
18881b9cf80SYonghong Song 	 */
18981b9cf80SYonghong Song 	attr->inherit = 1;
19081b9cf80SYonghong Song 
1911c47910eSAlexei Starovoitov 	/* open task bound event */
192205c8adaSJoe Stringer 	pmu_fd = sys_perf_event_open(attr, 0, -1, -1, 0);
1931c47910eSAlexei Starovoitov 	if (pmu_fd < 0) {
194205c8adaSJoe Stringer 		printf("sys_perf_event_open failed\n");
195492b7e89STaeung Song 		goto err;
196492b7e89STaeung Song 	}
197aa5e2af6SDaniel T. Lee 	link = bpf_program__attach_perf_event(prog, pmu_fd);
198*0efdcefbSDaniel T. Lee 	if (libbpf_get_error(link)) {
199aa5e2af6SDaniel T. Lee 		printf("bpf_program__attach_perf_event failed\n");
200aa5e2af6SDaniel T. Lee 		link = NULL;
2011c47910eSAlexei Starovoitov 		close(pmu_fd);
202aa5e2af6SDaniel T. Lee 		goto err;
203aa5e2af6SDaniel T. Lee 	}
204aa5e2af6SDaniel T. Lee 
205aa5e2af6SDaniel T. Lee 	if (generate_load() < 0)
206aa5e2af6SDaniel T. Lee 		goto err;
207aa5e2af6SDaniel T. Lee 
208aa5e2af6SDaniel T. Lee 	print_stacks();
209aa5e2af6SDaniel T. Lee 	error = 0;
210aa5e2af6SDaniel T. Lee err:
211aa5e2af6SDaniel T. Lee 	bpf_link__destroy(link);
212492b7e89STaeung Song 	if (error)
213aa5e2af6SDaniel T. Lee 		err_exit(error);
2141c47910eSAlexei Starovoitov }
2151c47910eSAlexei Starovoitov 
test_bpf_perf_event(void)2161c47910eSAlexei Starovoitov static void test_bpf_perf_event(void)
2171c47910eSAlexei Starovoitov {
2181c47910eSAlexei Starovoitov 	struct perf_event_attr attr_type_hw = {
2191c47910eSAlexei Starovoitov 		.sample_freq = SAMPLE_FREQ,
2201c47910eSAlexei Starovoitov 		.freq = 1,
2211c47910eSAlexei Starovoitov 		.type = PERF_TYPE_HARDWARE,
2221c47910eSAlexei Starovoitov 		.config = PERF_COUNT_HW_CPU_CYCLES,
2231c47910eSAlexei Starovoitov 	};
2241c47910eSAlexei Starovoitov 	struct perf_event_attr attr_type_sw = {
2251c47910eSAlexei Starovoitov 		.sample_freq = SAMPLE_FREQ,
2261c47910eSAlexei Starovoitov 		.freq = 1,
2271c47910eSAlexei Starovoitov 		.type = PERF_TYPE_SOFTWARE,
2281c47910eSAlexei Starovoitov 		.config = PERF_COUNT_SW_CPU_CLOCK,
2291c47910eSAlexei Starovoitov 	};
23041e9a804STeng Qin 	struct perf_event_attr attr_hw_cache_l1d = {
23141e9a804STeng Qin 		.sample_freq = SAMPLE_FREQ,
23241e9a804STeng Qin 		.freq = 1,
23341e9a804STeng Qin 		.type = PERF_TYPE_HW_CACHE,
23441e9a804STeng Qin 		.config =
23541e9a804STeng Qin 			PERF_COUNT_HW_CACHE_L1D |
23641e9a804STeng Qin 			(PERF_COUNT_HW_CACHE_OP_READ << 8) |
23741e9a804STeng Qin 			(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
23841e9a804STeng Qin 	};
23941e9a804STeng Qin 	struct perf_event_attr attr_hw_cache_branch_miss = {
24041e9a804STeng Qin 		.sample_freq = SAMPLE_FREQ,
24141e9a804STeng Qin 		.freq = 1,
24241e9a804STeng Qin 		.type = PERF_TYPE_HW_CACHE,
24341e9a804STeng Qin 		.config =
24441e9a804STeng Qin 			PERF_COUNT_HW_CACHE_BPU |
24541e9a804STeng Qin 			(PERF_COUNT_HW_CACHE_OP_READ << 8) |
24641e9a804STeng Qin 			(PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
24741e9a804STeng Qin 	};
24841e9a804STeng Qin 	struct perf_event_attr attr_type_raw = {
24941e9a804STeng Qin 		.sample_freq = SAMPLE_FREQ,
25041e9a804STeng Qin 		.freq = 1,
25141e9a804STeng Qin 		.type = PERF_TYPE_RAW,
25241e9a804STeng Qin 		/* Intel Instruction Retired */
25341e9a804STeng Qin 		.config = 0xc0,
25441e9a804STeng Qin 	};
25512fe1225STeng Qin 	struct perf_event_attr attr_type_raw_lock_load = {
25612fe1225STeng Qin 		.sample_freq = SAMPLE_FREQ,
25712fe1225STeng Qin 		.freq = 1,
25812fe1225STeng Qin 		.type = PERF_TYPE_RAW,
25912fe1225STeng Qin 		/* Intel MEM_UOPS_RETIRED.LOCK_LOADS */
26012fe1225STeng Qin 		.config = 0x21d0,
26112fe1225STeng Qin 		/* Request to record lock address from PEBS */
26212fe1225STeng Qin 		.sample_type = PERF_SAMPLE_ADDR,
26312fe1225STeng Qin 		/* Record address value requires precise event */
26412fe1225STeng Qin 		.precise_ip = 2,
26512fe1225STeng Qin 	};
2661c47910eSAlexei Starovoitov 
26741e9a804STeng Qin 	printf("Test HW_CPU_CYCLES\n");
2681c47910eSAlexei Starovoitov 	test_perf_event_all_cpu(&attr_type_hw);
2691c47910eSAlexei Starovoitov 	test_perf_event_task(&attr_type_hw);
27041e9a804STeng Qin 
27141e9a804STeng Qin 	printf("Test SW_CPU_CLOCK\n");
2721c47910eSAlexei Starovoitov 	test_perf_event_all_cpu(&attr_type_sw);
2731c47910eSAlexei Starovoitov 	test_perf_event_task(&attr_type_sw);
27441e9a804STeng Qin 
27541e9a804STeng Qin 	printf("Test HW_CACHE_L1D\n");
27641e9a804STeng Qin 	test_perf_event_all_cpu(&attr_hw_cache_l1d);
27741e9a804STeng Qin 	test_perf_event_task(&attr_hw_cache_l1d);
27841e9a804STeng Qin 
27941e9a804STeng Qin 	printf("Test HW_CACHE_BPU\n");
28041e9a804STeng Qin 	test_perf_event_all_cpu(&attr_hw_cache_branch_miss);
28141e9a804STeng Qin 	test_perf_event_task(&attr_hw_cache_branch_miss);
28241e9a804STeng Qin 
28341e9a804STeng Qin 	printf("Test Instruction Retired\n");
28441e9a804STeng Qin 	test_perf_event_all_cpu(&attr_type_raw);
28541e9a804STeng Qin 	test_perf_event_task(&attr_type_raw);
28641e9a804STeng Qin 
28712fe1225STeng Qin 	printf("Test Lock Load\n");
28812fe1225STeng Qin 	test_perf_event_all_cpu(&attr_type_raw_lock_load);
28912fe1225STeng Qin 	test_perf_event_task(&attr_type_raw_lock_load);
29012fe1225STeng Qin 
29141e9a804STeng Qin 	printf("*** PASS ***\n");
2921c47910eSAlexei Starovoitov }
2931c47910eSAlexei Starovoitov 
2941c47910eSAlexei Starovoitov 
main(int argc,char ** argv)2951c47910eSAlexei Starovoitov int main(int argc, char **argv)
2961c47910eSAlexei Starovoitov {
297aa5e2af6SDaniel T. Lee 	struct bpf_object *obj = NULL;
2981c47910eSAlexei Starovoitov 	char filename[256];
299aa5e2af6SDaniel T. Lee 	int error = 1;
3001c47910eSAlexei Starovoitov 
3011c47910eSAlexei Starovoitov 	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
3021c47910eSAlexei Starovoitov 
303aa5e2af6SDaniel T. Lee 	signal(SIGINT, err_exit);
304aa5e2af6SDaniel T. Lee 	signal(SIGTERM, err_exit);
3051c47910eSAlexei Starovoitov 
3061c47910eSAlexei Starovoitov 	if (load_kallsyms()) {
3071c47910eSAlexei Starovoitov 		printf("failed to process /proc/kallsyms\n");
308aa5e2af6SDaniel T. Lee 		goto cleanup;
3091c47910eSAlexei Starovoitov 	}
3101c47910eSAlexei Starovoitov 
311aa5e2af6SDaniel T. Lee 	obj = bpf_object__open_file(filename, NULL);
312*0efdcefbSDaniel T. Lee 	if (libbpf_get_error(obj)) {
313aa5e2af6SDaniel T. Lee 		printf("opening BPF object file failed\n");
314aa5e2af6SDaniel T. Lee 		obj = NULL;
315aa5e2af6SDaniel T. Lee 		goto cleanup;
3161c47910eSAlexei Starovoitov 	}
3171c47910eSAlexei Starovoitov 
318aa5e2af6SDaniel T. Lee 	prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
319aa5e2af6SDaniel T. Lee 	if (!prog) {
320aa5e2af6SDaniel T. Lee 		printf("finding a prog in obj file failed\n");
321aa5e2af6SDaniel T. Lee 		goto cleanup;
322aa5e2af6SDaniel T. Lee 	}
323aa5e2af6SDaniel T. Lee 
324aa5e2af6SDaniel T. Lee 	/* load BPF program */
325aa5e2af6SDaniel T. Lee 	if (bpf_object__load(obj)) {
326aa5e2af6SDaniel T. Lee 		printf("loading BPF object file failed\n");
327aa5e2af6SDaniel T. Lee 		goto cleanup;
328aa5e2af6SDaniel T. Lee 	}
329aa5e2af6SDaniel T. Lee 
330aa5e2af6SDaniel T. Lee 	map_fd[0] = bpf_object__find_map_fd_by_name(obj, "counts");
331aa5e2af6SDaniel T. Lee 	map_fd[1] = bpf_object__find_map_fd_by_name(obj, "stackmap");
332aa5e2af6SDaniel T. Lee 	if (map_fd[0] < 0 || map_fd[1] < 0) {
333aa5e2af6SDaniel T. Lee 		printf("finding a counts/stackmap map in obj file failed\n");
334aa5e2af6SDaniel T. Lee 		goto cleanup;
335aa5e2af6SDaniel T. Lee 	}
336aa5e2af6SDaniel T. Lee 
337aa5e2af6SDaniel T. Lee 	pid = fork();
338aa5e2af6SDaniel T. Lee 	if (pid == 0) {
3391c47910eSAlexei Starovoitov 		read_trace_pipe();
3401c47910eSAlexei Starovoitov 		return 0;
341aa5e2af6SDaniel T. Lee 	} else if (pid == -1) {
342aa5e2af6SDaniel T. Lee 		printf("couldn't spawn process\n");
343aa5e2af6SDaniel T. Lee 		goto cleanup;
3441c47910eSAlexei Starovoitov 	}
345aa5e2af6SDaniel T. Lee 
3461c47910eSAlexei Starovoitov 	test_bpf_perf_event();
347aa5e2af6SDaniel T. Lee 	error = 0;
348aa5e2af6SDaniel T. Lee 
349aa5e2af6SDaniel T. Lee cleanup:
350aa5e2af6SDaniel T. Lee 	bpf_object__close(obj);
351aa5e2af6SDaniel T. Lee 	err_exit(error);
3521c47910eSAlexei Starovoitov }
353