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