Skip to content

Commit 2dfc818

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
selftests/bpf: Add tests for arena spin lock
Add some basic selftests for qspinlock built over BPF arena using cond_break_label macro. Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 88d706b commit 2dfc818

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3+
#include <test_progs.h>
4+
#include <network_helpers.h>
5+
#include <sys/sysinfo.h>
6+
7+
struct qspinlock { int val; };
8+
typedef struct qspinlock arena_spinlock_t;
9+
10+
struct arena_qnode {
11+
unsigned long next;
12+
int count;
13+
int locked;
14+
};
15+
16+
#include "arena_spin_lock.skel.h"
17+
18+
static long cpu;
19+
static int repeat;
20+
21+
pthread_barrier_t barrier;
22+
23+
static void *spin_lock_thread(void *arg)
24+
{
25+
int err, prog_fd = *(u32 *)arg;
26+
LIBBPF_OPTS(bpf_test_run_opts, topts,
27+
.data_in = &pkt_v4,
28+
.data_size_in = sizeof(pkt_v4),
29+
.repeat = repeat,
30+
);
31+
cpu_set_t cpuset;
32+
33+
CPU_ZERO(&cpuset);
34+
CPU_SET(__sync_fetch_and_add(&cpu, 1), &cpuset);
35+
ASSERT_OK(pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset), "cpu affinity");
36+
37+
err = pthread_barrier_wait(&barrier);
38+
if (err != PTHREAD_BARRIER_SERIAL_THREAD && err != 0)
39+
ASSERT_FALSE(true, "pthread_barrier");
40+
41+
err = bpf_prog_test_run_opts(prog_fd, &topts);
42+
ASSERT_OK(err, "test_run err");
43+
ASSERT_EQ((int)topts.retval, 0, "test_run retval");
44+
45+
pthread_exit(arg);
46+
}
47+
48+
static void test_arena_spin_lock_size(int size)
49+
{
50+
LIBBPF_OPTS(bpf_test_run_opts, topts);
51+
struct arena_spin_lock *skel;
52+
pthread_t thread_id[16];
53+
int prog_fd, i, err;
54+
void *ret;
55+
56+
if (get_nprocs() < 2) {
57+
test__skip();
58+
return;
59+
}
60+
61+
skel = arena_spin_lock__open_and_load();
62+
if (!ASSERT_OK_PTR(skel, "arena_spin_lock__open_and_load"))
63+
return;
64+
if (skel->data->test_skip == 2) {
65+
test__skip();
66+
goto end;
67+
}
68+
skel->bss->cs_count = size;
69+
skel->bss->limit = repeat * 16;
70+
71+
ASSERT_OK(pthread_barrier_init(&barrier, NULL, 16), "barrier init");
72+
73+
prog_fd = bpf_program__fd(skel->progs.prog);
74+
for (i = 0; i < 16; i++) {
75+
err = pthread_create(&thread_id[i], NULL, &spin_lock_thread, &prog_fd);
76+
if (!ASSERT_OK(err, "pthread_create"))
77+
goto end_barrier;
78+
}
79+
80+
for (i = 0; i < 16; i++) {
81+
if (!ASSERT_OK(pthread_join(thread_id[i], &ret), "pthread_join"))
82+
goto end_barrier;
83+
if (!ASSERT_EQ(ret, &prog_fd, "ret == prog_fd"))
84+
goto end_barrier;
85+
}
86+
87+
ASSERT_EQ(skel->bss->counter, repeat * 16, "check counter value");
88+
89+
end_barrier:
90+
pthread_barrier_destroy(&barrier);
91+
end:
92+
arena_spin_lock__destroy(skel);
93+
return;
94+
}
95+
96+
void test_arena_spin_lock(void)
97+
{
98+
repeat = 1000;
99+
if (test__start_subtest("arena_spin_lock_1"))
100+
test_arena_spin_lock_size(1);
101+
cpu = 0;
102+
if (test__start_subtest("arena_spin_lock_1000"))
103+
test_arena_spin_lock_size(1000);
104+
cpu = 0;
105+
repeat = 100;
106+
if (test__start_subtest("arena_spin_lock_50000"))
107+
test_arena_spin_lock_size(50000);
108+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3+
#include <vmlinux.h>
4+
#include <bpf/bpf_tracing.h>
5+
#include <bpf/bpf_helpers.h>
6+
#include "bpf_misc.h"
7+
#include "bpf_arena_spin_lock.h"
8+
9+
struct {
10+
__uint(type, BPF_MAP_TYPE_ARENA);
11+
__uint(map_flags, BPF_F_MMAPABLE);
12+
__uint(max_entries, 100); /* number of pages */
13+
#ifdef __TARGET_ARCH_arm64
14+
__ulong(map_extra, 0x1ull << 32); /* start of mmap() region */
15+
#else
16+
__ulong(map_extra, 0x1ull << 44); /* start of mmap() region */
17+
#endif
18+
} arena SEC(".maps");
19+
20+
int cs_count;
21+
22+
#if defined(ENABLE_ATOMICS_TESTS) && defined(__BPF_FEATURE_ADDR_SPACE_CAST)
23+
arena_spinlock_t __arena lock;
24+
int test_skip = 1;
25+
#else
26+
int test_skip = 2;
27+
#endif
28+
29+
int counter;
30+
int limit;
31+
32+
SEC("tc")
33+
int prog(void *ctx)
34+
{
35+
int ret = -2;
36+
37+
#if defined(ENABLE_ATOMICS_TESTS) && defined(__BPF_FEATURE_ADDR_SPACE_CAST)
38+
unsigned long flags;
39+
40+
if ((ret = arena_spin_lock_irqsave(&lock, flags)))
41+
return ret;
42+
if (counter != limit)
43+
counter++;
44+
bpf_repeat(cs_count);
45+
ret = 0;
46+
arena_spin_unlock_irqrestore(&lock, flags);
47+
#endif
48+
return ret;
49+
}
50+
51+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)