xref: /dpdk/app/test/test_timer_secondary.c (revision 3c60274c0995a7a74c5550d2f5bbcfbd9d548515)
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
test_timer_secondary(void)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
timer_secondary_spawn_wait(unsigned int lcore)51 timer_secondary_spawn_wait(unsigned int lcore)
52 {
53 	char coremask[10];
54 #ifdef RTE_EXEC_ENV_LINUXAPP
55 	char tmp[PATH_MAX] = {0};
56 	char prefix[PATH_MAX] = {0};
57 
58 	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 	char const *argv[] = {
65 		prgname,
66 		"-c", coremask,
67 		"--proc-type=secondary",
68 		prefix
69 	};
70 
71 	snprintf(coremask, sizeof(coremask), "%x", (1 << lcore));
72 
73 	return launch_proc(argv);
74 }
75 
76 static void
handle_expired_timer(struct rte_timer * tim)77 handle_expired_timer(struct rte_timer *tim)
78 {
79 	struct test_info *test_info = tim->arg;
80 
81 	test_info->expired_count++;
82 	test_info->expired_timers[test_info->expired_timers_idx++] = tim;
83 }
84 
85 static int
timer_manage_loop(void * arg)86 timer_manage_loop(void *arg)
87 {
88 #define TICK_MSECS 1
89 	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 	while (!test_info->exit_flag) {
94 		cur_tsc = rte_rdtsc();
95 		diff_tsc = cur_tsc - prev_tsc;
96 
97 		if (diff_tsc > tick_cycles) {
98 			/* Scan timer list for expired timers */
99 			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 			rte_mempool_put_bulk(test_info->tim_mempool,
106 					     (void **)test_info->expired_timers,
107 					     test_info->expired_timers_idx);
108 
109 			test_info->expired_timers_idx = 0;
110 
111 			prev_tsc = cur_tsc;
112 		}
113 
114 		rte_pause();
115 	}
116 
117 	return 0;
118 }
119 
120 int
test_timer_secondary(void)121 test_timer_secondary(void)
122 {
123 	int proc_type = rte_eal_process_type();
124 	const struct rte_memzone *mz;
125 	struct test_info *test_info;
126 	int ret;
127 
128 	if (proc_type == RTE_PROC_PRIMARY) {
129 		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 			return TEST_SKIPPED;
133 		}
134 
135 		mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info),
136 					 SOCKET_ID_ANY, 0);
137 		TEST_ASSERT_NOT_NULL(mz, "Couldn't allocate memory for "
138 				     "test data");
139 		test_info = mz->addr;
140 
141 		test_info->tim_mempool = rte_mempool_create("test_timer_mp",
142 				NUM_TIMERS, sizeof(struct rte_timer), 0, 0,
143 				NULL, NULL, NULL, NULL, rte_socket_id(), 0);
144 
145 		ret = rte_timer_data_alloc(&test_info->timer_data_id);
146 		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 		*main_lcorep = rte_get_main_lcore();
154 		*mgr_lcorep = rte_get_next_lcore(*main_lcorep, 1, 1);
155 		*sec_lcorep = rte_get_next_lcore(*mgr_lcorep, 1, 1);
156 
157 		ret = rte_eal_remote_launch(timer_manage_loop,
158 					    (void *)test_info,
159 					    *mgr_lcorep);
160 		TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop");
161 
162 		ret = timer_secondary_spawn_wait(*sec_lcorep);
163 		TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed");
164 
165 		rte_delay_ms(2000);
166 
167 		test_info->exit_flag = 1;
168 		rte_eal_wait_lcore(*mgr_lcorep);
169 
170 #ifdef RTE_LIBRTE_TIMER_DEBUG
171 		rte_timer_alt_dump_stats(test_info->timer_data_id, stdout);
172 #endif
173 
174 		return test_info->expected_count == test_info->expired_count ?
175 			TEST_SUCCESS : TEST_FAILED;
176 
177 	} else if (proc_type == RTE_PROC_SECONDARY) {
178 		uint64_t ticks, timeout_ms;
179 		struct rte_timer *tim;
180 		int i;
181 
182 		mz = rte_memzone_lookup(TEST_INFO_MZ_NAME);
183 		TEST_ASSERT_NOT_NULL(mz, "Couldn't lookup memzone for "
184 				     "test info");
185 		test_info = mz->addr;
186 
187 		for (i = 0; i < NUM_TIMERS; i++) {
188 			rte_mempool_get(test_info->tim_mempool, (void **)&tim);
189 
190 			rte_timer_init(tim);
191 
192 			/* generate timeouts between 10 and 160 ms */
193 			timeout_ms = ((rte_rand() & 0xF) + 1) * 10;
194 			ticks = timeout_ms * rte_get_timer_hz() / MSECPERSEC;
195 
196 			ret = rte_timer_alt_reset(test_info->timer_data_id,
197 						  tim, ticks, SINGLE,
198 						  test_info->mgr_lcore, NULL,
199 						  test_info);
200 			if (ret < 0)
201 				return TEST_FAILED;
202 
203 			test_info->expected_count++;
204 
205 			/* randomly leave timer running or stop it */
206 			if (rte_rand() & 1)
207 				continue;
208 
209 			ret = rte_timer_alt_stop(test_info->timer_data_id,
210 						 tim);
211 			if (ret == 0) {
212 				test_info->expected_count--;
213 				rte_mempool_put(test_info->tim_mempool,
214 						(void *)tim);
215 			}
216 
217 		}
218 
219 		return TEST_SUCCESS;
220 	}
221 
222 	return TEST_FAILED;
223 }
224 
225 #endif /* !RTE_EXEC_ENV_WINDOWS */
226 
227 REGISTER_TEST_COMMAND(timer_secondary_autotest, test_timer_secondary);
228