Mykola Lysenko says: ==================== First patch reduces the sample_freq to 1000 to ensure test will work even when kernel.perf_event_max_sample_rate was reduced to 1000. Patches for send_signal and find_vma tune the test implementation to make sure needed thread is scheduled. Also, both tests will finish as soon as possible after the test condition is met. ====================
Unified · Split
| @@ -199,7 +199,7 @@ static void pe_subtest(struct test_bpf_cookie *skel) · 198 unmodified lines | |||
| 199 | attr.type = PERF_TYPE_SOFTWARE; | 199 | attr.type = PERF_TYPE_SOFTWARE; |
| 200 | attr.config = PERF_COUNT_SW_CPU_CLOCK; | 200 | attr.config = PERF_COUNT_SW_CPU_CLOCK; |
| 201 | attr.freq = 1; | 201 | attr.freq = 1; |
| 202 | attr.sample_freq = 4000; | 202 | attr.sample_freq = 1000; |
| 203 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); | 203 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); |
| 204 | if (!ASSERT_GE(pfd, 0, "perf_fd")) | 204 | if (!ASSERT_GE(pfd, 0, "perf_fd")) |
| 205 | goto cleanup; | 205 | goto cleanup; |
| @@ -7,12 +7,14 @@ · 6 unmodified lines | |||
| 7 | #include "find_vma_fail1.skel.h" | 7 | #include "find_vma_fail1.skel.h" |
| 8 | #include "find_vma_fail2.skel.h" | 8 | #include "find_vma_fail2.skel.h" |
| 9 | 9 | ||
| 10 | static void test_and_reset_skel(struct find_vma *skel, int expected_find_zero_ret) | 10 | static void test_and_reset_skel(struct find_vma *skel, int expected_find_zero_ret, bool need_test) |
| 11 | { | 11 | { |
| 12 | ASSERT_EQ(skel->bss->found_vm_exec, 1, "found_vm_exec"); | 12 | if (need_test) { |
| 13 | ASSERT_EQ(skel->data->find_addr_ret, 0, "find_addr_ret"); | 13 | ASSERT_EQ(skel->bss->found_vm_exec, 1, "found_vm_exec"); |
| 14 | ASSERT_EQ(skel->data->find_zero_ret, expected_find_zero_ret, "find_zero_ret"); | 14 | ASSERT_EQ(skel->data->find_addr_ret, 0, "find_addr_ret"); |
| 15 | ASSERT_OK_PTR(strstr(skel->bss->d_iname, "test_progs"), "find_test_progs"); | 15 | ASSERT_EQ(skel->data->find_zero_ret, expected_find_zero_ret, "find_zero_ret"); |
| 16 | ASSERT_OK_PTR(strstr(skel->bss->d_iname, "test_progs"), "find_test_progs"); | ||
| 17 | } | ||
| 16 | 18 | ||
| 17 | skel->bss->found_vm_exec = 0; | 19 | skel->bss->found_vm_exec = 0; |
| 18 | skel->data->find_addr_ret = -1; | 20 | skel->data->find_addr_ret = -1; |
| @@ -30,17 +32,26 @@ static int open_pe(void) · 11 unmodified lines | |||
| 30 | attr.type = PERF_TYPE_HARDWARE; | 32 | attr.type = PERF_TYPE_HARDWARE; |
| 31 | attr.config = PERF_COUNT_HW_CPU_CYCLES; | 33 | attr.config = PERF_COUNT_HW_CPU_CYCLES; |
| 32 | attr.freq = 1; | 34 | attr.freq = 1; |
| 33 | attr.sample_freq = 4000; | 35 | attr.sample_freq = 1000; |
| 34 | pfd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC); | 36 | pfd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC); |
| 35 | 37 | ||
| 36 | return pfd >= 0 ? pfd : -errno; | 38 | return pfd >= 0 ? pfd : -errno; |
| 37 | } | 39 | } |
| 38 | 40 | ||
| 41 | static bool find_vma_pe_condition(struct find_vma *skel) | ||
| 42 | { | ||
| 43 | return skel->bss->found_vm_exec == 0 || | ||
| 44 | skel->data->find_addr_ret != 0 || | ||
| 45 | skel->data->find_zero_ret == -1 || | ||
| 46 | strcmp(skel->bss->d_iname, "test_progs") != 0; | ||
| 47 | } | ||
| 48 | |||
| 39 | static void test_find_vma_pe(struct find_vma *skel) | 49 | static void test_find_vma_pe(struct find_vma *skel) |
| 40 | { | 50 | { |
| 41 | struct bpf_link *link = NULL; | 51 | struct bpf_link *link = NULL; |
| 42 | volatile int j = 0; | 52 | volatile int j = 0; |
| 43 | int pfd, i; | 53 | int pfd, i; |
| 54 | const int one_bn = 1000000000; | ||
| 44 | 55 | ||
| 45 | pfd = open_pe(); | 56 | pfd = open_pe(); |
| 46 | if (pfd < 0) { | 57 | if (pfd < 0) { |
| @@ -57,10 +68,10 @@ static void test_find_vma_pe(struct find_vma *skel) · 10 unmodified lines | |||
| 57 | if (!ASSERT_OK_PTR(link, "attach_perf_event")) | 68 | if (!ASSERT_OK_PTR(link, "attach_perf_event")) |
| 58 | goto cleanup; | 69 | goto cleanup; |
| 59 | 70 | ||
| 60 | for (i = 0; i < 1000000; ++i) | 71 | for (i = 0; i < one_bn && find_vma_pe_condition(skel); ++i) |
| 61 | ++j; | 72 | ++j; |
| 62 | 73 | ||
| 63 | test_and_reset_skel(skel, -EBUSY /* in nmi, irq_work is busy */); | 74 | test_and_reset_skel(skel, -EBUSY /* in nmi, irq_work is busy */, i == one_bn); |
| 64 | cleanup: | 75 | cleanup: |
| 65 | bpf_link__destroy(link); | 76 | bpf_link__destroy(link); |
| 66 | close(pfd); | 77 | close(pfd); |
| @@ -75,7 +86,7 @@ static void test_find_vma_kprobe(struct find_vma *skel) · 8 unmodified lines | |||
| 75 | return; | 86 | return; |
| 76 | 87 | ||
| 77 | getpgid(skel->bss->target_pid); | 88 | getpgid(skel->bss->target_pid); |
| 78 | test_and_reset_skel(skel, -ENOENT /* could not find vma for ptr 0 */); | 89 | test_and_reset_skel(skel, -ENOENT /* could not find vma for ptr 0 */, true); |
| 79 | } | 90 | } |
| 80 | 91 | ||
| 81 | static void test_illegal_write_vma(void) | 92 | static void test_illegal_write_vma(void) |
| @@ -108,7 +119,6 @@ void serial_test_find_vma(void) · 26 unmodified lines | |||
| 108 | skel->bss->addr = (__u64)(uintptr_t)test_find_vma_pe; | 119 | skel->bss->addr = (__u64)(uintptr_t)test_find_vma_pe; |
| 109 | 120 | ||
| 110 | test_find_vma_pe(skel); | 121 | test_find_vma_pe(skel); |
| 111 | usleep(100000); /* allow the irq_work to finish */ | ||
| 112 | test_find_vma_kprobe(skel); | 122 | test_find_vma_kprobe(skel); |
| 113 | 123 | ||
| 114 | find_vma__destroy(skel); | 124 | find_vma__destroy(skel); |
| @@ -110,7 +110,7 @@ static void test_perf_branches_hw(void) · 109 unmodified lines | |||
| 110 | attr.type = PERF_TYPE_HARDWARE; | 110 | attr.type = PERF_TYPE_HARDWARE; |
| 111 | attr.config = PERF_COUNT_HW_CPU_CYCLES; | 111 | attr.config = PERF_COUNT_HW_CPU_CYCLES; |
| 112 | attr.freq = 1; | 112 | attr.freq = 1; |
| 113 | attr.sample_freq = 4000; | 113 | attr.sample_freq = 1000; |
| 114 | attr.sample_type = PERF_SAMPLE_BRANCH_STACK; | 114 | attr.sample_type = PERF_SAMPLE_BRANCH_STACK; |
| 115 | attr.branch_sample_type = PERF_SAMPLE_BRANCH_USER | PERF_SAMPLE_BRANCH_ANY; | 115 | attr.branch_sample_type = PERF_SAMPLE_BRANCH_USER | PERF_SAMPLE_BRANCH_ANY; |
| 116 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); | 116 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); |
| @@ -151,7 +151,7 @@ static void test_perf_branches_no_hw(void) · 34 unmodified lines | |||
| 151 | attr.type = PERF_TYPE_SOFTWARE; | 151 | attr.type = PERF_TYPE_SOFTWARE; |
| 152 | attr.config = PERF_COUNT_SW_CPU_CLOCK; | 152 | attr.config = PERF_COUNT_SW_CPU_CLOCK; |
| 153 | attr.freq = 1; | 153 | attr.freq = 1; |
| 154 | attr.sample_freq = 4000; | 154 | attr.sample_freq = 1000; |
| 155 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); | 155 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); |
| 156 | if (CHECK(pfd < 0, "perf_event_open", "err %d\n", pfd)) | 156 | if (CHECK(pfd < 0, "perf_event_open", "err %d\n", pfd)) |
| 157 | return; | 157 | return; |
| @@ -39,7 +39,7 @@ void serial_test_perf_link(void) · 38 unmodified lines | |||
| 39 | attr.type = PERF_TYPE_SOFTWARE; | 39 | attr.type = PERF_TYPE_SOFTWARE; |
| 40 | attr.config = PERF_COUNT_SW_CPU_CLOCK; | 40 | attr.config = PERF_COUNT_SW_CPU_CLOCK; |
| 41 | attr.freq = 1; | 41 | attr.freq = 1; |
| 42 | attr.sample_freq = 4000; | 42 | attr.sample_freq = 1000; |
| 43 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); | 43 | pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); |
| 44 | if (!ASSERT_GE(pfd, 0, "perf_fd")) | 44 | if (!ASSERT_GE(pfd, 0, "perf_fd")) |
| 45 | goto cleanup; | 45 | goto cleanup; |
| @@ -4,11 +4,11 @@ · 3 unmodified lines | |||
| 4 | #include <sys/resource.h> | 4 | #include <sys/resource.h> |
| 5 | #include "test_send_signal_kern.skel.h" | 5 | #include "test_send_signal_kern.skel.h" |
| 6 | 6 | ||
| 7 | int sigusr1_received = 0; | 7 | static int sigusr1_received; |
| 8 | 8 | ||
| 9 | static void sigusr1_handler(int signum) | 9 | static void sigusr1_handler(int signum) |
| 10 | { | 10 | { |
| 11 | sigusr1_received++; | 11 | sigusr1_received = 1; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | static void test_send_signal_common(struct perf_event_attr *attr, | 14 | static void test_send_signal_common(struct perf_event_attr *attr, |
| @@ -40,9 +40,10 @@ static void test_send_signal_common(struct perf_event_attr *attr, · 25 unmodified lines | |||
| 40 | 40 | ||
| 41 | if (pid == 0) { | 41 | if (pid == 0) { |
| 42 | int old_prio; | 42 | int old_prio; |
| 43 | volatile int j = 0; | ||
| 43 | 44 | ||
| 44 | /* install signal handler and notify parent */ | 45 | /* install signal handler and notify parent */ |
| 45 | signal(SIGUSR1, sigusr1_handler); | 46 | ASSERT_NEQ(signal(SIGUSR1, sigusr1_handler), SIG_ERR, "signal"); |
| 46 | 47 | ||
| 47 | close(pipe_c2p[0]); /* close read */ | 48 | close(pipe_c2p[0]); /* close read */ |
| 48 | close(pipe_p2c[1]); /* close write */ | 49 | close(pipe_p2c[1]); /* close write */ |
| @@ -63,9 +64,11 @@ static void test_send_signal_common(struct perf_event_attr *attr, · 14 unmodified lines | |||
| 63 | ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read"); | 64 | ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read"); |
| 64 | 65 | ||
| 65 | /* wait a little for signal handler */ | 66 | /* wait a little for signal handler */ |
| 66 | sleep(1); | 67 | for (int i = 0; i < 100000000 && !sigusr1_received; i++) |
| 68 | j /= i + 1; | ||
| 67 | 69 | ||
| 68 | buf[0] = sigusr1_received ? '2' : '0'; | 70 | buf[0] = sigusr1_received ? '2' : '0'; |
| 71 | ASSERT_EQ(sigusr1_received, 1, "sigusr1_received"); | ||
| 69 | ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write"); | 72 | ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write"); |
| 70 | 73 | ||
| 71 | /* wait for parent notification and exit */ | 74 | /* wait for parent notification and exit */ |
| @@ -93,7 +96,7 @@ static void test_send_signal_common(struct perf_event_attr *attr, · 21 unmodified lines | |||
| 93 | goto destroy_skel; | 96 | goto destroy_skel; |
| 94 | } | 97 | } |
| 95 | } else { | 98 | } else { |
| 96 | pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1, | 99 | pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1 /* cpu */, |
| 97 | -1 /* group id */, 0 /* flags */); | 100 | -1 /* group id */, 0 /* flags */); |
| 98 | if (!ASSERT_GE(pmu_fd, 0, "perf_event_open")) { | 101 | if (!ASSERT_GE(pmu_fd, 0, "perf_event_open")) { |
| 99 | err = -1; | 102 | err = -1; |
| @@ -110,9 +113,9 @@ static void test_send_signal_common(struct perf_event_attr *attr, · 10 unmodified lines | |||
| 110 | ASSERT_EQ(read(pipe_c2p[0], buf, 1), 1, "pipe_read"); | 113 | ASSERT_EQ(read(pipe_c2p[0], buf, 1), 1, "pipe_read"); |
| 111 | 114 | ||
| 112 | /* trigger the bpf send_signal */ | 115 | /* trigger the bpf send_signal */ |
| 113 | skel->bss->pid = pid; | ||
| 114 | skel->bss->sig = SIGUSR1; | ||
| 115 | skel->bss->signal_thread = signal_thread; | 116 | skel->bss->signal_thread = signal_thread; |
| 117 | skel->bss->sig = SIGUSR1; | ||
| 118 | skel->bss->pid = pid; | ||
| 116 | 119 | ||
| 117 | /* notify child that bpf program can send_signal now */ | 120 | /* notify child that bpf program can send_signal now */ |
| 118 | ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write"); | 121 | ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write"); |
| @@ -10,7 +10,7 @@ static __always_inline int bpf_send_signal_test(void *ctx) · 9 unmodified lines | |||
| 10 | { | 10 | { |
| 11 | int ret; | 11 | int ret; |
| 12 | 12 | ||
| 13 | if (status != 0 || sig == 0 || pid == 0) | 13 | if (status != 0 || pid == 0) |
| 14 | return 0; | 14 | return 0; |
| 15 | 15 | ||
| 16 | if ((bpf_get_current_pid_tgid() >> 32) == pid) { | 16 | if ((bpf_get_current_pid_tgid() >> 32) == pid) { |