Skip to content

Commit 386f6c7

Browse files
Christopher Friedtnashif
authored andcommitted
tests: posix: eventfd: add stress test
This test simply counts how many times `eventfd_read()` and `eventfd_write()` can be called on an `eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)` file descriptor. Prior to the recent changes in `eventfd`, we were seeing approximately < 1000 writes / s. However, the previous `eventfd` implementation would fail this test with the result that the number of successful reads was far greater than the number of successful writes. This should be impossible, and with the recent `eventfd` changes that was fixed. Additionally, we are seeing an increase in over 40x for non-blocking eventfd reads and writes. ``` START - test_stress I: BOARD: qemu_riscv64_smp I: TEST_DURATION_S: 5 I: UPDATE_INTERVAL_S: 1 I: avg: 48537 reads/s I: avg: 48575 writes/s PASS - test_stress in 5.002 seconds ``` Signed-off-by: Christopher Friedt <[email protected]>
1 parent 3e27c7f commit 386f6c7

File tree

3 files changed

+156
-1
lines changed

3 files changed

+156
-1
lines changed

tests/posix/eventfd/Kconfig

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright (c) 2023, Meta
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
source "Kconfig.zephyr"
6+
7+
config TEST_DURATION_S
8+
int "Number of seconds to run the test"
9+
range 1 21600
10+
default 5
11+
help
12+
Duration for the test, in seconds. The range has a reblatively high
13+
upper bound because we should expect that eventfd_read() and
14+
eventfd_write() are stable enough to run for an arbitrarily long
15+
period of time without encountering any race conditions.
16+
17+
config TEST_TIMEOUT_S
18+
int "Number of seconds to run the test"
19+
range 1 21600
20+
default 10
21+
22+
config TEST_STACK_SIZE
23+
int "Size of each thread stack in this test"
24+
default 2048
25+
help
26+
The minimal stack size required to run a no-op thread.
27+
28+
config TEST_EXTRA_ASSERTIONS
29+
bool "Add extra assertions into the hot path"
30+
help
31+
In order to get a true benchmark, there should be as few branches
32+
as possible on the hot path. Say 'y' here to add extra assertions
33+
on the hot path as well to verify functionality.
34+
35+
config TEST_EXTRA_QUIET
36+
bool "Do not print out regular reports"
37+
help
38+
In order to get a true benchmark, there should be as few branches
39+
as possible on the hot path. Say 'y' here to skip reporting.
40+
41+
module = EVENTFD_TEST
42+
module-str = eventfd
43+
source "subsys/logging/Kconfig.template.log_config"

tests/posix/eventfd/src/blocking.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ ZTEST_F(eventfd, test_unset_poll_event_block)
7171
eventfd_poll_unset_common(fixture->fd);
7272
}
7373

74-
K_THREAD_STACK_DEFINE(thread_stack, 2048);
74+
K_THREAD_STACK_DEFINE(thread_stack, CONFIG_TEST_STACK_SIZE);
7575

7676
static void thread_fun(void *arg1, void *arg2, void *arg3)
7777
{

tests/posix/eventfd/src/stress.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (c) 2023, Meta
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "_main.h"
8+
9+
/* update interval for printing stats */
10+
#if CONFIG_TEST_DURATION_S >= 60
11+
#define UPDATE_INTERVAL_S 10
12+
#elif CONFIG_TEST_DURATION_S >= 30
13+
#define UPDATE_INTERVAL_S 5
14+
#else
15+
#define UPDATE_INTERVAL_S 1
16+
#endif
17+
18+
enum th_id {
19+
WRITER,
20+
READER,
21+
};
22+
23+
typedef int (*eventfd_op_t)(int fd);
24+
25+
static size_t count[2];
26+
static struct k_thread th[2];
27+
static const char *msg[2] = {
28+
[READER] = "reads",
29+
[WRITER] = "writes",
30+
};
31+
32+
static int read_op(int fd);
33+
static int write_op(int fd);
34+
35+
static const eventfd_op_t op[2] = {
36+
[READER] = read_op,
37+
[WRITER] = write_op,
38+
};
39+
static K_THREAD_STACK_ARRAY_DEFINE(th_stack, 2, CONFIG_TEST_STACK_SIZE);
40+
41+
static int read_op(int fd)
42+
{
43+
eventfd_t value;
44+
45+
return eventfd_read(fd, &value);
46+
}
47+
48+
static int write_op(int fd)
49+
{
50+
return eventfd_write(fd, 1);
51+
}
52+
53+
static void th_fun(void *arg1, void *arg2, void *arg3)
54+
{
55+
56+
int ret;
57+
uint64_t now;
58+
uint64_t end;
59+
uint64_t report;
60+
enum th_id id = POINTER_TO_UINT(arg1);
61+
struct eventfd_fixture *fixture = arg2;
62+
const uint64_t report_ms = UPDATE_INTERVAL_S * MSEC_PER_SEC;
63+
const uint64_t end_ms = CONFIG_TEST_DURATION_S * MSEC_PER_SEC;
64+
65+
for (now = k_uptime_get(), end = now + end_ms, report = now + report_ms; now < end;
66+
now = k_uptime_get()) {
67+
68+
ret = op[id](fixture->fd);
69+
if (IS_ENABLED(CONFIG_TEST_EXTRA_ASSERTIONS)) {
70+
zassert_true(ret == 0 || (ret == -1 && errno == EAGAIN),
71+
"ret: %d errno: %d", ret, errno);
72+
}
73+
count[id] += (ret == 0);
74+
75+
if (!IS_ENABLED(CONFIG_TEST_EXTRA_QUIET)) {
76+
if (now >= report) {
77+
printk("%zu %s\n", count[id], msg[id]);
78+
report += report_ms;
79+
}
80+
}
81+
}
82+
83+
printk("avg: %zu %s/s\n", (size_t)((count[id] * MSEC_PER_SEC) / end_ms), msg[id]);
84+
}
85+
86+
ZTEST_F(eventfd, test_stress)
87+
{
88+
enum th_id i;
89+
enum th_id begin = MIN(READER, WRITER);
90+
enum th_id end = MAX(READER, WRITER) + 1;
91+
92+
printk("BOARD: %s\n", CONFIG_BOARD);
93+
printk("TEST_DURATION_S: %u\n", CONFIG_TEST_DURATION_S);
94+
printk("UPDATE_INTERVAL_S: %u\n", UPDATE_INTERVAL_S);
95+
96+
reopen(&fixture->fd, 0, EFD_NONBLOCK | EFD_SEMAPHORE);
97+
98+
for (i = begin; i < end; ++i) {
99+
k_thread_create(&th[i], th_stack[i], K_THREAD_STACK_SIZEOF(th_stack[0]), th_fun,
100+
UINT_TO_POINTER(i), fixture, NULL, K_LOWEST_APPLICATION_THREAD_PRIO,
101+
0, K_NO_WAIT);
102+
}
103+
104+
for (i = begin; i < end; ++i) {
105+
zassert_ok(k_thread_join(&th[i], K_FOREVER));
106+
}
107+
108+
zassert_true(count[READER] > 0, "read count is zero");
109+
zassert_true(count[WRITER] > 0, "write count is zero");
110+
zassert_true(count[WRITER] >= count[READER], "read count (%zu) > write count (%zu)",
111+
count[READER], count[WRITER]);
112+
}

0 commit comments

Comments
 (0)