11da4864cSSong Liu // SPDX-License-Identifier: GPL-2.0
21da4864cSSong Liu // Copyright (c) 2020 Facebook
31da4864cSSong Liu #define _GNU_SOURCE
41da4864cSSong Liu #include <pthread.h>
51da4864cSSong Liu #include <sched.h>
61da4864cSSong Liu #include <test_progs.h>
71da4864cSSong Liu #include "perf_event_stackmap.skel.h"
81da4864cSSong Liu 
91da4864cSSong Liu #ifndef noinline
101da4864cSSong Liu #define noinline __attribute__((noinline))
111da4864cSSong Liu #endif
121da4864cSSong Liu 
func_1(void)131da4864cSSong Liu noinline int func_1(void)
141da4864cSSong Liu {
151da4864cSSong Liu 	static int val = 1;
161da4864cSSong Liu 
171da4864cSSong Liu 	val += 1;
181da4864cSSong Liu 
191da4864cSSong Liu 	usleep(100);
201da4864cSSong Liu 	return val;
211da4864cSSong Liu }
221da4864cSSong Liu 
func_2(void)231da4864cSSong Liu noinline int func_2(void)
241da4864cSSong Liu {
251da4864cSSong Liu 	return func_1();
261da4864cSSong Liu }
271da4864cSSong Liu 
func_3(void)281da4864cSSong Liu noinline int func_3(void)
291da4864cSSong Liu {
301da4864cSSong Liu 	return func_2();
311da4864cSSong Liu }
321da4864cSSong Liu 
func_4(void)331da4864cSSong Liu noinline int func_4(void)
341da4864cSSong Liu {
351da4864cSSong Liu 	return func_3();
361da4864cSSong Liu }
371da4864cSSong Liu 
func_5(void)381da4864cSSong Liu noinline int func_5(void)
391da4864cSSong Liu {
401da4864cSSong Liu 	return func_4();
411da4864cSSong Liu }
421da4864cSSong Liu 
func_6(void)431da4864cSSong Liu noinline int func_6(void)
441da4864cSSong Liu {
451da4864cSSong Liu 	int i, val = 1;
461da4864cSSong Liu 
471da4864cSSong Liu 	for (i = 0; i < 100; i++)
481da4864cSSong Liu 		val += func_5();
491da4864cSSong Liu 
501da4864cSSong Liu 	return val;
511da4864cSSong Liu }
521da4864cSSong Liu 
test_perf_event_stackmap(void)531da4864cSSong Liu void test_perf_event_stackmap(void)
541da4864cSSong Liu {
551da4864cSSong Liu 	struct perf_event_attr attr = {
561da4864cSSong Liu 		/* .type = PERF_TYPE_SOFTWARE, */
571da4864cSSong Liu 		.type = PERF_TYPE_HARDWARE,
581da4864cSSong Liu 		.config = PERF_COUNT_HW_CPU_CYCLES,
591da4864cSSong Liu 		.precise_ip = 2,
601da4864cSSong Liu 		.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_BRANCH_STACK |
611da4864cSSong Liu 			PERF_SAMPLE_CALLCHAIN,
621da4864cSSong Liu 		.branch_sample_type = PERF_SAMPLE_BRANCH_USER |
631da4864cSSong Liu 			PERF_SAMPLE_BRANCH_NO_FLAGS |
641da4864cSSong Liu 			PERF_SAMPLE_BRANCH_NO_CYCLES |
651da4864cSSong Liu 			PERF_SAMPLE_BRANCH_CALL_STACK,
66*de6d014aSSong Liu 		.freq = 1,
67*de6d014aSSong Liu 		.sample_freq = read_perf_max_sample_freq(),
681da4864cSSong Liu 		.size = sizeof(struct perf_event_attr),
691da4864cSSong Liu 	};
701da4864cSSong Liu 	struct perf_event_stackmap *skel;
711da4864cSSong Liu 	__u32 duration = 0;
721da4864cSSong Liu 	cpu_set_t cpu_set;
731da4864cSSong Liu 	int pmu_fd, err;
741da4864cSSong Liu 
751da4864cSSong Liu 	skel = perf_event_stackmap__open();
761da4864cSSong Liu 
771da4864cSSong Liu 	if (CHECK(!skel, "skel_open", "skeleton open failed\n"))
781da4864cSSong Liu 		return;
791da4864cSSong Liu 
801da4864cSSong Liu 	err = perf_event_stackmap__load(skel);
811da4864cSSong Liu 	if (CHECK(err, "skel_load", "skeleton load failed: %d\n", err))
821da4864cSSong Liu 		goto cleanup;
831da4864cSSong Liu 
841da4864cSSong Liu 	CPU_ZERO(&cpu_set);
851da4864cSSong Liu 	CPU_SET(0, &cpu_set);
861da4864cSSong Liu 	err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
871da4864cSSong Liu 	if (CHECK(err, "set_affinity", "err %d, errno %d\n", err, errno))
881da4864cSSong Liu 		goto cleanup;
891da4864cSSong Liu 
901da4864cSSong Liu 	pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */,
911da4864cSSong Liu 			 0 /* cpu 0 */, -1 /* group id */,
921da4864cSSong Liu 			 0 /* flags */);
931da4864cSSong Liu 	if (pmu_fd < 0) {
941da4864cSSong Liu 		printf("%s:SKIP:cpu doesn't support the event\n", __func__);
951da4864cSSong Liu 		test__skip();
961da4864cSSong Liu 		goto cleanup;
971da4864cSSong Liu 	}
981da4864cSSong Liu 
991da4864cSSong Liu 	skel->links.oncpu = bpf_program__attach_perf_event(skel->progs.oncpu,
1001da4864cSSong Liu 							   pmu_fd);
101bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel->links.oncpu, "attach_perf_event")) {
1021da4864cSSong Liu 		close(pmu_fd);
1031da4864cSSong Liu 		goto cleanup;
1041da4864cSSong Liu 	}
1051da4864cSSong Liu 
1061da4864cSSong Liu 	/* create kernel and user stack traces for testing */
1071da4864cSSong Liu 	func_6();
1081da4864cSSong Liu 
1091da4864cSSong Liu 	CHECK(skel->data->stackid_kernel != 2, "get_stackid_kernel", "failed\n");
1101da4864cSSong Liu 	CHECK(skel->data->stackid_user != 2, "get_stackid_user", "failed\n");
1111da4864cSSong Liu 	CHECK(skel->data->stack_kernel != 2, "get_stack_kernel", "failed\n");
1121da4864cSSong Liu 	CHECK(skel->data->stack_user != 2, "get_stack_user", "failed\n");
1131da4864cSSong Liu 
1141da4864cSSong Liu cleanup:
1151da4864cSSong Liu 	perf_event_stackmap__destroy(skel);
1161da4864cSSong Liu }
117