xref: /dpdk/app/test/test_timer_secondary.c (revision 200bc52e5aa0d72e70464c9cd22b55cf536ed13c)
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_atomic.h>
13 #include <rte_timer.h>
14 #include <rte_cycles.h>
15 #include <rte_mempool.h>
16 #include <rte_random.h>
17 
18 #include "test.h"
19 #include "process.h"
20 
21 #define NUM_TIMERS		(1 << 20) /* ~1M timers */
22 #define NUM_LCORES_NEEDED	3
23 #define TEST_INFO_MZ_NAME	"test_timer_info_mz"
24 #define MSECPERSEC		1E3
25 
26 #define launch_proc(ARGV) \
27 	process_dup(ARGV, sizeof(ARGV)/(sizeof(ARGV[0])), __func__)
28 
29 struct test_info {
30 	unsigned int mstr_lcore;
31 	unsigned int mgr_lcore;
32 	unsigned int sec_lcore;
33 	uint32_t timer_data_id;
34 	volatile int expected_count;
35 	volatile int expired_count;
36 	struct rte_mempool *tim_mempool;
37 	struct rte_timer *expired_timers[NUM_TIMERS];
38 	int expired_timers_idx;
39 	volatile int exit_flag;
40 };
41 
42 static int
43 timer_secondary_spawn_wait(unsigned int lcore)
44 {
45 	char coremask[10];
46 #ifdef RTE_EXEC_ENV_LINUXAPP
47 	char tmp[PATH_MAX] = {0};
48 	char prefix[PATH_MAX] = {0};
49 
50 	get_current_prefix(tmp, sizeof(tmp));
51 
52 	snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp);
53 #else
54 	const char *prefix = "";
55 #endif
56 	char const *argv[] = {
57 		prgname,
58 		"-c", coremask,
59 		"--proc-type=secondary",
60 		prefix
61 	};
62 
63 	snprintf(coremask, sizeof(coremask), "%x", (1 << lcore));
64 
65 	return launch_proc(argv);
66 }
67 
68 static void
69 handle_expired_timer(struct rte_timer *tim)
70 {
71 	struct test_info *test_info = tim->arg;
72 
73 	test_info->expired_count++;
74 	test_info->expired_timers[test_info->expired_timers_idx++] = tim;
75 }
76 
77 static int
78 timer_manage_loop(void *arg)
79 {
80 #define TICK_MSECS 1
81 	uint64_t tick_cycles = TICK_MSECS * rte_get_timer_hz() / MSECPERSEC;
82 	uint64_t prev_tsc = 0, cur_tsc, diff_tsc;
83 	struct test_info *test_info = arg;
84 
85 	while (!test_info->exit_flag) {
86 		cur_tsc = rte_rdtsc();
87 		diff_tsc = cur_tsc - prev_tsc;
88 
89 		if (diff_tsc > tick_cycles) {
90 			/* Scan timer list for expired timers */
91 			rte_timer_alt_manage(test_info->timer_data_id,
92 					     NULL,
93 					     0,
94 					     handle_expired_timer);
95 
96 			/* Return expired timer objects back to mempool */
97 			rte_mempool_put_bulk(test_info->tim_mempool,
98 					     (void **)test_info->expired_timers,
99 					     test_info->expired_timers_idx);
100 
101 			test_info->expired_timers_idx = 0;
102 
103 			prev_tsc = cur_tsc;
104 		}
105 
106 		rte_pause();
107 	}
108 
109 	return 0;
110 }
111 
112 int
113 test_timer_secondary(void)
114 {
115 	int proc_type = rte_eal_process_type();
116 	const struct rte_memzone *mz;
117 	struct test_info *test_info;
118 	int ret;
119 
120 	if (proc_type == RTE_PROC_PRIMARY) {
121 		mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info),
122 					 SOCKET_ID_ANY, 0);
123 		test_info = mz->addr;
124 		TEST_ASSERT_NOT_NULL(test_info, "Couldn't allocate memory for "
125 				     "test data");
126 
127 		TEST_ASSERT(rte_lcore_count() >= NUM_LCORES_NEEDED,
128 			    "at least %d lcores needed to run tests",
129 			    NUM_LCORES_NEEDED);
130 
131 		test_info->tim_mempool = rte_mempool_create("test_timer_mp",
132 				NUM_TIMERS, sizeof(struct rte_timer), 0, 0,
133 				NULL, NULL, NULL, NULL, rte_socket_id(), 0);
134 
135 		ret = rte_timer_data_alloc(&test_info->timer_data_id);
136 		TEST_ASSERT_SUCCESS(ret, "Failed to allocate timer data "
137 				    "instance");
138 
139 		unsigned int *mstr_lcorep = &test_info->mstr_lcore;
140 		unsigned int *mgr_lcorep = &test_info->mgr_lcore;
141 		unsigned int *sec_lcorep = &test_info->sec_lcore;
142 
143 		*mstr_lcorep = rte_get_master_lcore();
144 		*mgr_lcorep = rte_get_next_lcore(*mstr_lcorep, 1, 1);
145 		*sec_lcorep = rte_get_next_lcore(*mgr_lcorep, 1, 1);
146 
147 		ret = rte_eal_remote_launch(timer_manage_loop,
148 					    (void *)test_info,
149 					    *mgr_lcorep);
150 		TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop");
151 
152 		ret = timer_secondary_spawn_wait(*sec_lcorep);
153 		TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed");
154 
155 		rte_delay_ms(2000);
156 
157 		test_info->exit_flag = 1;
158 		rte_eal_wait_lcore(*mgr_lcorep);
159 
160 #ifdef RTE_LIBRTE_TIMER_DEBUG
161 		rte_timer_alt_dump_stats(test_info->timer_data_id, stdout);
162 #endif
163 
164 		return test_info->expected_count == test_info->expired_count ?
165 			TEST_SUCCESS : TEST_FAILED;
166 
167 	} else if (proc_type == RTE_PROC_SECONDARY) {
168 		uint64_t ticks, timeout_ms;
169 		struct rte_timer *tim;
170 		int i;
171 
172 		mz = rte_memzone_lookup(TEST_INFO_MZ_NAME);
173 		test_info = mz->addr;
174 		TEST_ASSERT_NOT_NULL(test_info, "Couldn't lookup memzone for "
175 				     "test info");
176 
177 		for (i = 0; i < NUM_TIMERS; i++) {
178 			rte_mempool_get(test_info->tim_mempool, (void **)&tim);
179 
180 			rte_timer_init(tim);
181 
182 			/* generate timeouts between 10 and 160 ms */
183 			timeout_ms = ((rte_rand() & 0xF) + 1) * 10;
184 			ticks = timeout_ms * rte_get_timer_hz() / MSECPERSEC;
185 
186 			ret = rte_timer_alt_reset(test_info->timer_data_id,
187 						  tim, ticks, SINGLE,
188 						  test_info->mgr_lcore, NULL,
189 						  test_info);
190 			if (ret < 0)
191 				return TEST_FAILED;
192 
193 			test_info->expected_count++;
194 
195 			/* randomly leave timer running or stop it */
196 			if (rte_rand() & 1)
197 				continue;
198 
199 			ret = rte_timer_alt_stop(test_info->timer_data_id,
200 						 tim);
201 			if (ret == 0) {
202 				test_info->expected_count--;
203 				rte_mempool_put(test_info->tim_mempool,
204 						(void *)tim);
205 			}
206 
207 		}
208 
209 		return TEST_SUCCESS;
210 	}
211 
212 	return TEST_FAILED;
213 }
214 
215 REGISTER_TEST_COMMAND(timer_secondary_autotest, test_timer_secondary);
216