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