1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2021 Facebook */ 3 #define _GNU_SOURCE 4 #include <pthread.h> 5 #include <sched.h> 6 #include <test_progs.h> 7 #include "testing_helpers.h" 8 #include "test_perf_link.skel.h" 9 10 #define BURN_TIMEOUT_MS 100 11 #define BURN_TIMEOUT_NS BURN_TIMEOUT_MS * 1000000 12 13 static void burn_cpu(void) 14 { 15 volatile int j = 0; 16 cpu_set_t cpu_set; 17 int i, err; 18 19 /* generate some branches on cpu 0 */ 20 CPU_ZERO(&cpu_set); 21 CPU_SET(0, &cpu_set); 22 err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set); 23 ASSERT_OK(err, "set_thread_affinity"); 24 25 /* spin the loop for a while (random high number) */ 26 for (i = 0; i < 1000000; ++i) 27 ++j; 28 } 29 30 /* TODO: often fails in concurrent mode */ 31 void serial_test_perf_link(void) 32 { 33 struct test_perf_link *skel = NULL; 34 struct perf_event_attr attr; 35 int pfd = -1, link_fd = -1, err; 36 int run_cnt_before, run_cnt_after; 37 struct bpf_link_info info; 38 __u32 info_len = sizeof(info); 39 __u64 timeout_time_ns; 40 41 /* create perf event */ 42 memset(&attr, 0, sizeof(attr)); 43 attr.size = sizeof(attr); 44 attr.type = PERF_TYPE_SOFTWARE; 45 attr.config = PERF_COUNT_SW_CPU_CLOCK; 46 attr.freq = 1; 47 attr.sample_freq = 1000; 48 pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); 49 if (!ASSERT_GE(pfd, 0, "perf_fd")) 50 goto cleanup; 51 52 skel = test_perf_link__open_and_load(); 53 if (!ASSERT_OK_PTR(skel, "skel_load")) 54 goto cleanup; 55 56 link_fd = bpf_link_create(bpf_program__fd(skel->progs.handler), pfd, 57 BPF_PERF_EVENT, NULL); 58 if (!ASSERT_GE(link_fd, 0, "link_fd")) 59 goto cleanup; 60 61 memset(&info, 0, sizeof(info)); 62 err = bpf_link_get_info_by_fd(link_fd, &info, &info_len); 63 if (!ASSERT_OK(err, "link_get_info")) 64 goto cleanup; 65 66 ASSERT_EQ(info.type, BPF_LINK_TYPE_PERF_EVENT, "link_type"); 67 ASSERT_GT(info.id, 0, "link_id"); 68 ASSERT_GT(info.prog_id, 0, "link_prog_id"); 69 70 /* ensure we get at least one perf_event prog execution */ 71 timeout_time_ns = get_time_ns() + BURN_TIMEOUT_NS; 72 while (true) { 73 burn_cpu(); 74 if (skel->bss->run_cnt > 0) 75 break; 76 if (!ASSERT_LT(get_time_ns(), timeout_time_ns, "run_cnt_timeout")) 77 break; 78 } 79 80 /* perf_event is still active, but we close link and BPF program 81 * shouldn't be executed anymore 82 */ 83 close(link_fd); 84 link_fd = -1; 85 86 /* make sure there are no stragglers */ 87 kern_sync_rcu(); 88 89 run_cnt_before = skel->bss->run_cnt; 90 burn_cpu(); 91 run_cnt_after = skel->bss->run_cnt; 92 93 ASSERT_EQ(run_cnt_before, run_cnt_after, "run_cnt_before_after"); 94 95 cleanup: 96 if (link_fd >= 0) 97 close(link_fd); 98 if (pfd >= 0) 99 close(pfd); 100 test_perf_link__destroy(skel); 101 } 102