History

selftests/bpf: Avoid spurious spmc parallel selftest errors in libarena

The libarena parallel spmc selftest is nondeterministic by design. As a result it depends up to a point on the relative timing between the producer and consumer threads. This introduces the possibility for two kinds of spurious failures that this patch addresses. 1) Spurious timeouts. The test proceeds in phases, and threads use a common counter as a barrier to avoid proceeding to the next phase until all threads are ready to do so. If a thread takes too long to reach the barrier, the already waiting threads may time out. Increase the current timeout. The timeout's value is a balance between the maximum amount of time spent on the test and the possibility of spurious failures. Right now the timeout is too short. Err on the side of caution and significantly increase it to avoid spurious failures. 2) Spurious resize failures. Some selftests require the spmc queue to resize itself. This in turn requires for the producer side to be materially faster than the consumer side so that the queue gets full enough for a resize. However, in the benchmark the spmc queue's producer is outnumbered 3:1. To offset it we add busy waits for consume queues. However, we still see occasional failures due to the queue never resizing. Minimize the possibility for this in two ways: First, remove one of the consumers. The 2 consumers still exercise the "race between consumers" scenario. Second, increase the busy wait duration to decrease the rate by which the consumers act on the queue. While at it, also replace a stray invalid error value "153" with EINVAL.

Emil Tsalapatis committed 5 months ago

Commit 68f4e481 parent f1a660b1 file · +5 −9Browse files

Unified · Split

tools/testing/selftests/bpf/libarena/selftests/test_parallel_spmc.bpf.c+5−9
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <libarena/asan.h>7#include <libarena/asan.h>
8#include <libarena/spmc.h>8#include <libarena/spmc.h>
9 9
10#define TEST_SPMC_THREADS 410#define TEST_SPMC_THREADS 3
11#define TEST_SPMC_STEALERS (TEST_SPMC_THREADS - 1)11#define TEST_SPMC_STEALERS (TEST_SPMC_THREADS - 1)
12 12
13/* 13/*
@@ -17,7 +17,7 @@ · 3 unmodified lines
17 * and operations are wait-free we just spin around the quiescence17 * and operations are wait-free we just spin around the quiescence
18 * point instead. If we time out, we just fail the benchmark.18 * point instead. If we time out, we just fail the benchmark.
19 */19 */
20#define TEST_SPMC_SYNC_SPINS (1U << 18)20#define TEST_SPMC_SYNC_SPINS BPF_MAX_LOOPS
21 21
22/*22/*
23 * We track all the values we retrieve from the queue23 * We track all the values we retrieve from the queue
@@ -61,7 +61,7 @@ static volatile u64 round_steals; · 37 unmodified lines
61 * We have multiple stealers and a single owner. We sometimes want the owner61 * We have multiple stealers and a single owner. We sometimes want the owner
62 * to successfully outproduce the stealers, we add a busy loop in them.62 * to successfully outproduce the stealers, we add a busy loop in them.
63 */63 */
64#define TEST_SPMC_WASTE_ROUNDS (1024)64#define TEST_SPMC_WASTE_ROUNDS (1UL << 12)
65 65
66/*66/*
67 * The spmc data structure depends on the runtime fully67 * The spmc data structure depends on the runtime fully
@@ -112,10 +112,6 @@ static bool spmc_tests_enabled(void) · 44 unmodified lines
112 { \112 { \
113 return spmc_##prefix##_stealer(); \113 return spmc_##prefix##_stealer(); \
114 } \114 } \
115 SEC("syscall") int parallel_test_spmc_##prefix##__3(void) \
116 { \
117 return spmc_##prefix##_stealer(); \
118 }
119 115
120static int spmc_common_init(u64 total)116static int spmc_common_init(u64 total)
121{117{
@@ -452,10 +448,10 @@ static int spmc_resize_owner(void) · 330 unmodified lines
452 resized = true;448 resized = true;
453 }449 }
454 450
455 /* Did we get to resize while racing/ */451 /* Did we get to resize while racing? */
456 if (!resized) {452 if (!resized) {
457 test_abort = true;453 test_abort = true;
458 return -153;454 return -EINVAL;
459 }455 }
460 456
461 /* 457 /*