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
read_op(int fd)41 static int read_op(int fd)
42 {
43 eventfd_t value;
44
45 return eventfd_read(fd, &value);
46 }
47
write_op(int fd)48 static int write_op(int fd)
49 {
50 return eventfd_write(fd, 1);
51 }
52
th_fun(void * arg1,void * arg2,void * arg3)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
ZTEST_F(eventfd,test_stress)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 }
113