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