at master 3.8 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3#include <test_progs.h> 4#include <string.h> 5#include <stdio.h> 6#include "task_work.skel.h" 7#include "task_work_fail.skel.h" 8#include <linux/bpf.h> 9#include <linux/perf_event.h> 10#include <sys/syscall.h> 11#include <time.h> 12 13static int perf_event_open(__u32 type, __u64 config, int pid) 14{ 15 struct perf_event_attr attr = { 16 .type = type, 17 .config = config, 18 .size = sizeof(struct perf_event_attr), 19 .sample_period = 100000, 20 }; 21 22 return syscall(__NR_perf_event_open, &attr, pid, -1, -1, 0); 23} 24 25struct elem { 26 char data[128]; 27 struct bpf_task_work tw; 28}; 29 30static int verify_map(struct bpf_map *map, const char *expected_data) 31{ 32 int err; 33 struct elem value; 34 int processed_values = 0; 35 int k, sz; 36 37 sz = bpf_map__max_entries(map); 38 for (k = 0; k < sz; ++k) { 39 err = bpf_map__lookup_elem(map, &k, sizeof(int), &value, sizeof(struct elem), 0); 40 if (err) 41 continue; 42 if (!ASSERT_EQ(strcmp(expected_data, value.data), 0, "map data")) { 43 fprintf(stderr, "expected '%s', found '%s' in %s map", expected_data, 44 value.data, bpf_map__name(map)); 45 return 2; 46 } 47 processed_values++; 48 } 49 50 return processed_values == 0; 51} 52 53static void task_work_run(const char *prog_name, const char *map_name) 54{ 55 struct task_work *skel; 56 struct bpf_program *prog; 57 struct bpf_map *map; 58 struct bpf_link *link = NULL; 59 int err, pe_fd = -1, pid, status, pipefd[2]; 60 char user_string[] = "hello world"; 61 62 if (!ASSERT_NEQ(pipe(pipefd), -1, "pipe")) 63 return; 64 65 pid = fork(); 66 if (pid == 0) { 67 __u64 num = 1; 68 int i; 69 char buf; 70 71 close(pipefd[1]); 72 read(pipefd[0], &buf, sizeof(buf)); 73 close(pipefd[0]); 74 75 for (i = 0; i < 10000; ++i) 76 num *= time(0) % 7; 77 (void)num; 78 exit(0); 79 } 80 if (!ASSERT_GT(pid, 0, "fork() failed")) { 81 close(pipefd[0]); 82 close(pipefd[1]); 83 return; 84 } 85 86 skel = task_work__open(); 87 if (!ASSERT_OK_PTR(skel, "task_work__open")) 88 return; 89 90 bpf_object__for_each_program(prog, skel->obj) { 91 bpf_program__set_autoload(prog, false); 92 } 93 94 prog = bpf_object__find_program_by_name(skel->obj, prog_name); 95 if (!ASSERT_OK_PTR(prog, "prog_name")) 96 goto cleanup; 97 bpf_program__set_autoload(prog, true); 98 skel->bss->user_ptr = (char *)user_string; 99 100 err = task_work__load(skel); 101 if (!ASSERT_OK(err, "skel_load")) 102 goto cleanup; 103 104 pe_fd = perf_event_open(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES, pid); 105 if (pe_fd == -1 && (errno == ENOENT || errno == EOPNOTSUPP)) { 106 printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n", __func__); 107 test__skip(); 108 goto cleanup; 109 } 110 if (!ASSERT_NEQ(pe_fd, -1, "pe_fd")) { 111 fprintf(stderr, "perf_event_open errno: %d, pid: %d\n", errno, pid); 112 goto cleanup; 113 } 114 115 link = bpf_program__attach_perf_event(prog, pe_fd); 116 if (!ASSERT_OK_PTR(link, "attach_perf_event")) 117 goto cleanup; 118 119 /* perf event fd ownership is passed to bpf_link */ 120 pe_fd = -1; 121 close(pipefd[0]); 122 write(pipefd[1], user_string, 1); 123 close(pipefd[1]); 124 /* Wait to collect some samples */ 125 waitpid(pid, &status, 0); 126 pid = 0; 127 map = bpf_object__find_map_by_name(skel->obj, map_name); 128 if (!ASSERT_OK_PTR(map, "find map_name")) 129 goto cleanup; 130 if (!ASSERT_OK(verify_map(map, user_string), "verify map")) 131 goto cleanup; 132cleanup: 133 if (pe_fd >= 0) 134 close(pe_fd); 135 bpf_link__destroy(link); 136 task_work__destroy(skel); 137 if (pid > 0) { 138 close(pipefd[0]); 139 write(pipefd[1], user_string, 1); 140 close(pipefd[1]); 141 waitpid(pid, &status, 0); 142 } 143} 144 145void test_task_work(void) 146{ 147 if (test__start_subtest("test_task_work_hash_map")) 148 task_work_run("oncpu_hash_map", "hmap"); 149 150 if (test__start_subtest("test_task_work_array_map")) 151 task_work_run("oncpu_array_map", "arrmap"); 152 153 if (test__start_subtest("test_task_work_lru_map")) 154 task_work_run("oncpu_lru_map", "lrumap"); 155 156 RUN_TESTS(task_work_fail); 157}