Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2019 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : :
8 : : #include <rte_eal.h>
9 : : #include <rte_lcore.h>
10 : : #include <rte_debug.h>
11 : : #include <rte_memzone.h>
12 : : #include <rte_timer.h>
13 : : #include <rte_cycles.h>
14 : : #include <rte_mempool.h>
15 : : #include <rte_pause.h>
16 : : #include <rte_random.h>
17 : : #include <rte_stdatomic.h>
18 : :
19 : : #include "test.h"
20 : :
21 : : #ifdef RTE_EXEC_ENV_WINDOWS
22 : : int
23 : : test_timer_secondary(void)
24 : : {
25 : : printf("timer_secondary not supported on Windows, skipping test\n");
26 : : return TEST_SKIPPED;
27 : : }
28 : : #else
29 : :
30 : : #include "process.h"
31 : :
32 : : #define NUM_TIMERS_MAX (1 << 20) /* ~1M timers */
33 : : #define NUM_TIMERS_MIN (1 << 14) /* 16K minimum */
34 : : #define NUM_LCORES_NEEDED 3
35 : : #define TEST_INFO_MZ_NAME "test_timer_info_mz"
36 : : #define MSECPERSEC 1E3
37 : :
38 : : #define launch_proc(ARGV) process_dup(ARGV, RTE_DIM(ARGV), __func__)
39 : :
40 : : struct test_info {
41 : : unsigned int main_lcore;
42 : : unsigned int mgr_lcore;
43 : : unsigned int sec_lcore;
44 : : unsigned int num_timers;
45 : : uint32_t timer_data_id;
46 : : RTE_ATOMIC(unsigned int) expected_count;
47 : : RTE_ATOMIC(unsigned int) expired_count;
48 : : struct rte_mempool *tim_mempool;
49 : : struct rte_timer *expired_timers[NUM_TIMERS_MAX];
50 : : int expired_timers_idx;
51 : : RTE_ATOMIC(int) exit_flag;
52 : : };
53 : :
54 : : static int
55 : 0 : timer_secondary_spawn_wait(unsigned int lcore)
56 : : {
57 : : char core_str[10];
58 : : const char *prefix;
59 : :
60 : 0 : prefix = file_prefix_arg();
61 [ # # ]: 0 : if (prefix == NULL)
62 : : return -1;
63 : :
64 : 0 : char const *argv[] = {
65 : : prgname,
66 : : "-l", core_str,
67 : : "--proc-type=secondary",
68 : : prefix
69 : : };
70 : :
71 : : snprintf(core_str, sizeof(core_str), "%u", lcore);
72 : :
73 : 0 : return launch_proc(argv);
74 : : }
75 : :
76 : : static void
77 : 0 : handle_expired_timer(struct rte_timer *tim)
78 : : {
79 : 0 : struct test_info *test_info = tim->arg;
80 : :
81 : 0 : rte_atomic_fetch_add_explicit(&test_info->expired_count, 1,
82 : : rte_memory_order_relaxed);
83 : 0 : test_info->expired_timers[test_info->expired_timers_idx++] = tim;
84 : 0 : }
85 : :
86 : : static int
87 : 0 : timer_manage_loop(void *arg)
88 : : {
89 : : #define TICK_MSECS 1
90 : 0 : uint64_t tick_cycles = TICK_MSECS * rte_get_timer_hz() / MSECPERSEC;
91 : : uint64_t prev_tsc = 0, cur_tsc, diff_tsc;
92 : : struct test_info *test_info = arg;
93 : :
94 [ # # ]: 0 : while (!rte_atomic_load_explicit(&test_info->exit_flag,
95 : : rte_memory_order_acquire)) {
96 : : cur_tsc = rte_rdtsc();
97 : 0 : diff_tsc = cur_tsc - prev_tsc;
98 : :
99 [ # # ]: 0 : if (diff_tsc > tick_cycles) {
100 : : /* Scan timer list for expired timers */
101 : 0 : rte_timer_alt_manage(test_info->timer_data_id,
102 : : NULL,
103 : : 0,
104 : : handle_expired_timer);
105 : :
106 : : /* Return expired timer objects back to mempool */
107 : 0 : rte_mempool_put_bulk(test_info->tim_mempool,
108 : 0 : (void **)test_info->expired_timers,
109 [ # # ]: 0 : test_info->expired_timers_idx);
110 : :
111 : 0 : test_info->expired_timers_idx = 0;
112 : :
113 : : prev_tsc = cur_tsc;
114 : : }
115 : :
116 : : rte_pause();
117 : : }
118 : :
119 : 0 : return 0;
120 : : }
121 : :
122 : : int
123 : 1 : test_timer_secondary(void)
124 : : {
125 : 1 : int proc_type = rte_eal_process_type();
126 : : const struct rte_memzone *mz;
127 : : struct test_info *test_info;
128 : : int ret;
129 : :
130 [ + - ]: 1 : if (proc_type == RTE_PROC_PRIMARY) {
131 [ + - ]: 1 : if (rte_lcore_count() < NUM_LCORES_NEEDED) {
132 : : printf("Not enough cores for test_timer_secondary, expecting at least %u\n",
133 : : NUM_LCORES_NEEDED);
134 : 1 : return TEST_SKIPPED;
135 : : }
136 : :
137 : 0 : mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info),
138 : : SOCKET_ID_ANY, 0);
139 [ # # ]: 0 : TEST_ASSERT_NOT_NULL(mz, "Couldn't allocate memory for "
140 : : "test data");
141 : 0 : test_info = mz->addr;
142 : :
143 : 0 : test_info->num_timers = test_scale_iterations(NUM_TIMERS_MAX, NUM_TIMERS_MIN);
144 : :
145 : 0 : test_info->tim_mempool = rte_mempool_create("test_timer_mp",
146 : : test_info->num_timers, sizeof(struct rte_timer), 0, 0,
147 : 0 : NULL, NULL, NULL, NULL, rte_socket_id(), 0);
148 : :
149 : 0 : ret = rte_timer_data_alloc(&test_info->timer_data_id);
150 [ # # ]: 0 : TEST_ASSERT_SUCCESS(ret, "Failed to allocate timer data "
151 : : "instance");
152 : :
153 : : unsigned int *main_lcorep = &test_info->main_lcore;
154 : : unsigned int *mgr_lcorep = &test_info->mgr_lcore;
155 : : unsigned int *sec_lcorep = &test_info->sec_lcore;
156 : :
157 : 0 : *main_lcorep = rte_get_main_lcore();
158 : 0 : *mgr_lcorep = rte_get_next_lcore(*main_lcorep, 1, 1);
159 : 0 : *sec_lcorep = rte_get_next_lcore(*mgr_lcorep, 1, 1);
160 : :
161 : 0 : ret = rte_eal_remote_launch(timer_manage_loop,
162 : : (void *)test_info,
163 : : *mgr_lcorep);
164 [ # # ]: 0 : TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop");
165 : :
166 : 0 : ret = timer_secondary_spawn_wait(*sec_lcorep);
167 : : /* must set exit flag even on error case, so check ret later */
168 : :
169 : : rte_delay_ms(500);
170 : 0 : rte_atomic_store_explicit(&test_info->exit_flag, 1,
171 : : rte_memory_order_release);
172 : :
173 [ # # ]: 0 : TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed");
174 : 0 : rte_eal_wait_lcore(*mgr_lcorep);
175 : :
176 : : #ifdef RTE_LIBRTE_TIMER_DEBUG
177 : : rte_timer_alt_dump_stats(test_info->timer_data_id, stdout);
178 : : #endif
179 : :
180 : 0 : return rte_atomic_load_explicit(&test_info->expected_count,
181 : : rte_memory_order_relaxed) ==
182 : 0 : rte_atomic_load_explicit(&test_info->expired_count,
183 : : rte_memory_order_relaxed) ?
184 [ # # ]: 0 : TEST_SUCCESS : TEST_FAILED;
185 : :
186 [ # # ]: 0 : } else if (proc_type == RTE_PROC_SECONDARY) {
187 : : uint64_t ticks, timeout_ms;
188 : : struct rte_timer *tim;
189 : : unsigned int i;
190 : :
191 : 0 : mz = rte_memzone_lookup(TEST_INFO_MZ_NAME);
192 [ # # ]: 0 : TEST_ASSERT_NOT_NULL(mz, "Couldn't lookup memzone for "
193 : : "test info");
194 : 0 : test_info = mz->addr;
195 : :
196 [ # # ]: 0 : for (i = 0; i < test_info->num_timers; i++) {
197 [ # # ]: 0 : ret = rte_mempool_get(test_info->tim_mempool, (void **)&tim);
198 [ # # ]: 0 : TEST_ASSERT_SUCCESS(ret, "Couldn't get timer from mempool");
199 : :
200 : 0 : rte_timer_init(tim);
201 : :
202 : : /* generate timeouts between 10 and 80 ms */
203 : 0 : timeout_ms = ((rte_rand() & 0x7) + 1) * 10;
204 : 0 : ticks = timeout_ms * rte_get_timer_hz() / MSECPERSEC;
205 : :
206 : 0 : ret = rte_timer_alt_reset(test_info->timer_data_id,
207 : : tim, ticks, SINGLE,
208 : : test_info->mgr_lcore, NULL,
209 : : test_info);
210 [ # # ]: 0 : if (ret < 0)
211 : : return TEST_FAILED;
212 : :
213 : 0 : rte_atomic_fetch_add_explicit(&test_info->expected_count,
214 : : 1, rte_memory_order_relaxed);
215 : :
216 : : /* randomly leave timer running or stop it */
217 [ # # ]: 0 : if (rte_rand() & 1)
218 : 0 : continue;
219 : :
220 : 0 : ret = rte_timer_alt_stop(test_info->timer_data_id,
221 : : tim);
222 [ # # ]: 0 : if (ret == 0) {
223 : 0 : rte_atomic_fetch_sub_explicit(&test_info->expected_count,
224 : : 1, rte_memory_order_relaxed);
225 [ # # ]: 0 : rte_mempool_put(test_info->tim_mempool,
226 : : (void *)tim);
227 : : }
228 : :
229 : : }
230 : :
231 : : return TEST_SUCCESS;
232 : : }
233 : :
234 : : return TEST_FAILED;
235 : : }
236 : :
237 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
238 : :
239 : 276 : REGISTER_FAST_TEST(timer_secondary_autotest, NOHUGE_SKIP, ASAN_SKIP, test_timer_secondary);
|