xref: /dpdk/app/test/test_timer.c (revision b6a7e6852e9ab82ae0e05e2d2a0b83abca17de3b)
1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
3a9de470cSBruce Richardson  */
4a9de470cSBruce Richardson 
5a9de470cSBruce Richardson #include "test.h"
6a9de470cSBruce Richardson 
7a9de470cSBruce Richardson /*
8a9de470cSBruce Richardson  * Timer
9a9de470cSBruce Richardson  * =====
10a9de470cSBruce Richardson  *
11a9de470cSBruce Richardson  * #. Stress test 1.
12a9de470cSBruce Richardson  *
13a9de470cSBruce Richardson  *    The objective of the timer stress tests is to check that there are no
14a9de470cSBruce Richardson  *    race conditions in list and status management. This test launches,
15a9de470cSBruce Richardson  *    resets and stops the timer very often on many cores at the same
16a9de470cSBruce Richardson  *    time.
17a9de470cSBruce Richardson  *
18a9de470cSBruce Richardson  *    - Only one timer is used for this test.
19a9de470cSBruce Richardson  *    - On each core, the rte_timer_manage() function is called from the main
20a9de470cSBruce Richardson  *      loop every 3 microseconds.
21a9de470cSBruce Richardson  *    - In the main loop, the timer may be reset (randomly, with a
22a9de470cSBruce Richardson  *      probability of 0.5 %) 100 microseconds later on a random core, or
23a9de470cSBruce Richardson  *      stopped (with a probability of 0.5 % also).
24a9de470cSBruce Richardson  *    - In callback, the timer is can be reset (randomly, with a
25a9de470cSBruce Richardson  *      probability of 0.5 %) 100 microseconds later on the same core or
26a9de470cSBruce Richardson  *      on another core (same probability), or stopped (same
27a9de470cSBruce Richardson  *      probability).
28a9de470cSBruce Richardson  *
29a9de470cSBruce Richardson  * # Stress test 2.
30a9de470cSBruce Richardson  *
31a9de470cSBruce Richardson  *    The objective of this test is similar to the first in that it attempts
32a9de470cSBruce Richardson  *    to find if there are any race conditions in the timer library. However,
33a9de470cSBruce Richardson  *    it is less complex in terms of operations performed and duration, as it
34a9de470cSBruce Richardson  *    is designed to have a predictable outcome that can be tested.
35a9de470cSBruce Richardson  *
36a9de470cSBruce Richardson  *    - A set of timers is initialized for use by the test
37a9de470cSBruce Richardson  *    - All cores then simultaneously are set to schedule all the timers at
38a9de470cSBruce Richardson  *      the same time, so conflicts should occur.
39a9de470cSBruce Richardson  *    - Then there is a delay while we wait for the timers to expire
40cb056611SStephen Hemminger  *    - Then the main lcore calls timer_manage() and we check that all
41a9de470cSBruce Richardson  *      timers have had their callbacks called exactly once - no more no less.
42a9de470cSBruce Richardson  *    - Then we repeat the process, except after setting up the timers, we have
43a9de470cSBruce Richardson  *      all cores randomly reschedule them.
44a9de470cSBruce Richardson  *    - Again we check that the expected number of callbacks has occurred when
45a9de470cSBruce Richardson  *      we call timer-manage.
46a9de470cSBruce Richardson  *
47a9de470cSBruce Richardson  * #. Basic test.
48a9de470cSBruce Richardson  *
49a9de470cSBruce Richardson  *    This test performs basic functional checks of the timers. The test
50a9de470cSBruce Richardson  *    uses four different timers that are loaded and stopped under
51a9de470cSBruce Richardson  *    specific conditions in specific contexts.
52a9de470cSBruce Richardson  *
53a9de470cSBruce Richardson  *    - Four timers are used for this test.
54a9de470cSBruce Richardson  *    - On each core, the rte_timer_manage() function is called from main loop
55a9de470cSBruce Richardson  *      every 3 microseconds.
56a9de470cSBruce Richardson  *
57a9de470cSBruce Richardson  *    The autotest python script checks that the behavior is correct:
58a9de470cSBruce Richardson  *
59a9de470cSBruce Richardson  *    - timer0
60a9de470cSBruce Richardson  *
61cb056611SStephen Hemminger  *      - At initialization, timer0 is loaded by the main core, on main core
62a9de470cSBruce Richardson  *        in "single" mode (time = 1 second).
63a9de470cSBruce Richardson  *      - In the first 19 callbacks, timer0 is reloaded on the same core,
64a9de470cSBruce Richardson  *        then, it is explicitly stopped at the 20th call.
65a9de470cSBruce Richardson  *      - At t=25s, timer0 is reloaded once by timer2.
66a9de470cSBruce Richardson  *
67a9de470cSBruce Richardson  *    - timer1
68a9de470cSBruce Richardson  *
69cb056611SStephen Hemminger  *      - At initialization, timer1 is loaded by the main core, on the
70cb056611SStephen Hemminger  *        main core in "single" mode (time = 2 seconds).
71a9de470cSBruce Richardson  *      - In the first 9 callbacks, timer1 is reloaded on another
72a9de470cSBruce Richardson  *        core. After the 10th callback, timer1 is not reloaded anymore.
73a9de470cSBruce Richardson  *
74a9de470cSBruce Richardson  *    - timer2
75a9de470cSBruce Richardson  *
76cb056611SStephen Hemminger  *      - At initialization, timer2 is loaded by the main core, on the
77cb056611SStephen Hemminger  *        main core in "periodical" mode (time = 1 second).
78a9de470cSBruce Richardson  *      - In the callback, when t=25s, it stops timer3 and reloads timer0
79a9de470cSBruce Richardson  *        on the current core.
80a9de470cSBruce Richardson  *
81a9de470cSBruce Richardson  *    - timer3
82a9de470cSBruce Richardson  *
83cb056611SStephen Hemminger  *      - At initialization, timer3 is loaded by the main core, on
84a9de470cSBruce Richardson  *        another core in "periodical" mode (time = 1 second).
85a9de470cSBruce Richardson  *      - It is stopped at t=25s by timer2.
86a9de470cSBruce Richardson  */
87a9de470cSBruce Richardson 
88a9de470cSBruce Richardson #include <stdio.h>
89a9de470cSBruce Richardson #include <stdarg.h>
90a9de470cSBruce Richardson #include <string.h>
91a9de470cSBruce Richardson #include <stdlib.h>
92a9de470cSBruce Richardson #include <stdint.h>
93a9de470cSBruce Richardson #include <inttypes.h>
94a9de470cSBruce Richardson #include <sys/queue.h>
95a9de470cSBruce Richardson #include <math.h>
96a9de470cSBruce Richardson 
97a9de470cSBruce Richardson #include <rte_common.h>
98a9de470cSBruce Richardson #include <rte_log.h>
99a9de470cSBruce Richardson #include <rte_memory.h>
100a9de470cSBruce Richardson #include <rte_launch.h>
101a9de470cSBruce Richardson #include <rte_cycles.h>
102a9de470cSBruce Richardson #include <rte_eal.h>
103a9de470cSBruce Richardson #include <rte_per_lcore.h>
104a9de470cSBruce Richardson #include <rte_lcore.h>
105a9de470cSBruce Richardson #include <rte_timer.h>
106a9de470cSBruce Richardson #include <rte_random.h>
107a9de470cSBruce Richardson #include <rte_malloc.h>
108a9de470cSBruce Richardson #include <rte_pause.h>
109a9de470cSBruce Richardson 
110a9de470cSBruce Richardson #define TEST_DURATION_S 1 /* in seconds */
111a9de470cSBruce Richardson #define NB_TIMER 4
112a9de470cSBruce Richardson 
113a9de470cSBruce Richardson #define RTE_LOGTYPE_TESTTIMER RTE_LOGTYPE_USER3
114a9de470cSBruce Richardson 
115a9de470cSBruce Richardson static volatile uint64_t end_time;
116a9de470cSBruce Richardson static volatile int test_failed;
117a9de470cSBruce Richardson 
118a9de470cSBruce Richardson struct mytimerinfo {
119a9de470cSBruce Richardson 	struct rte_timer tim;
120a9de470cSBruce Richardson 	unsigned id;
121a9de470cSBruce Richardson 	unsigned count;
122a9de470cSBruce Richardson };
123a9de470cSBruce Richardson 
124a9de470cSBruce Richardson static struct mytimerinfo mytiminfo[NB_TIMER];
125a9de470cSBruce Richardson 
126a9de470cSBruce Richardson static void timer_basic_cb(struct rte_timer *tim, void *arg);
127a9de470cSBruce Richardson 
128a9de470cSBruce Richardson static void
mytimer_reset(struct mytimerinfo * timinfo,uint64_t ticks,enum rte_timer_type type,unsigned tim_lcore,rte_timer_cb_t fct)129a9de470cSBruce Richardson mytimer_reset(struct mytimerinfo *timinfo, uint64_t ticks,
130a9de470cSBruce Richardson 	      enum rte_timer_type type, unsigned tim_lcore,
131a9de470cSBruce Richardson 	      rte_timer_cb_t fct)
132a9de470cSBruce Richardson {
133a9de470cSBruce Richardson 	rte_timer_reset_sync(&timinfo->tim, ticks, type, tim_lcore,
134a9de470cSBruce Richardson 			     fct, timinfo);
135a9de470cSBruce Richardson }
136a9de470cSBruce Richardson 
137a9de470cSBruce Richardson /* timer callback for stress tests */
138a9de470cSBruce Richardson static void
timer_stress_cb(__rte_unused struct rte_timer * tim,__rte_unused void * arg)139f2fc83b4SThomas Monjalon timer_stress_cb(__rte_unused struct rte_timer *tim,
140f2fc83b4SThomas Monjalon 		__rte_unused void *arg)
141a9de470cSBruce Richardson {
142a9de470cSBruce Richardson 	long r;
143a9de470cSBruce Richardson 	unsigned lcore_id = rte_lcore_id();
144a9de470cSBruce Richardson 	uint64_t hz = rte_get_timer_hz();
145a9de470cSBruce Richardson 
146a9de470cSBruce Richardson 	if (rte_timer_pending(tim))
147a9de470cSBruce Richardson 		return;
148a9de470cSBruce Richardson 
149a9de470cSBruce Richardson 	r = rte_rand();
150a9de470cSBruce Richardson 	if ((r & 0xff) == 0) {
151a9de470cSBruce Richardson 		mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
152a9de470cSBruce Richardson 			      timer_stress_cb);
153a9de470cSBruce Richardson 	}
154a9de470cSBruce Richardson 	else if ((r & 0xff) == 1) {
155a9de470cSBruce Richardson 		mytimer_reset(&mytiminfo[0], hz, SINGLE,
156a9de470cSBruce Richardson 			      rte_get_next_lcore(lcore_id, 0, 1),
157a9de470cSBruce Richardson 			      timer_stress_cb);
158a9de470cSBruce Richardson 	}
159a9de470cSBruce Richardson 	else if ((r & 0xff) == 2) {
160a9de470cSBruce Richardson 		rte_timer_stop(&mytiminfo[0].tim);
161a9de470cSBruce Richardson 	}
162a9de470cSBruce Richardson }
163a9de470cSBruce Richardson 
164a9de470cSBruce Richardson static int
timer_stress_main_loop(__rte_unused void * arg)165f2fc83b4SThomas Monjalon timer_stress_main_loop(__rte_unused void *arg)
166a9de470cSBruce Richardson {
167a9de470cSBruce Richardson 	uint64_t hz = rte_get_timer_hz();
168a9de470cSBruce Richardson 	unsigned lcore_id = rte_lcore_id();
169a9de470cSBruce Richardson 	uint64_t cur_time;
170a9de470cSBruce Richardson 	int64_t diff = 0;
171a9de470cSBruce Richardson 	long r;
172a9de470cSBruce Richardson 
173a9de470cSBruce Richardson 	while (diff >= 0) {
174a9de470cSBruce Richardson 
175a9de470cSBruce Richardson 		/* call the timer handler on each core */
176a9de470cSBruce Richardson 		rte_timer_manage();
177a9de470cSBruce Richardson 
178a9de470cSBruce Richardson 		/* simulate the processing of a packet
179a9de470cSBruce Richardson 		 * (1 us = 2000 cycles at 2 Ghz) */
180a9de470cSBruce Richardson 		rte_delay_us(1);
181a9de470cSBruce Richardson 
182a9de470cSBruce Richardson 		/* randomly stop or reset timer */
183a9de470cSBruce Richardson 		r = rte_rand();
184a9de470cSBruce Richardson 		lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
185a9de470cSBruce Richardson 		if ((r & 0xff) == 0) {
186a9de470cSBruce Richardson 			/* 100 us */
187a9de470cSBruce Richardson 			mytimer_reset(&mytiminfo[0], hz/10000, SINGLE, lcore_id,
188a9de470cSBruce Richardson 				      timer_stress_cb);
189a9de470cSBruce Richardson 		}
190a9de470cSBruce Richardson 		else if ((r & 0xff) == 1) {
191a9de470cSBruce Richardson 			rte_timer_stop_sync(&mytiminfo[0].tim);
192a9de470cSBruce Richardson 		}
193a9de470cSBruce Richardson 		cur_time = rte_get_timer_cycles();
194a9de470cSBruce Richardson 		diff = end_time - cur_time;
195a9de470cSBruce Richardson 	}
196a9de470cSBruce Richardson 
197a9de470cSBruce Richardson 	lcore_id = rte_lcore_id();
198a9de470cSBruce Richardson 	RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
199a9de470cSBruce Richardson 
200a9de470cSBruce Richardson 	return 0;
201a9de470cSBruce Richardson }
202a9de470cSBruce Richardson 
203cb056611SStephen Hemminger /* Need to synchronize worker lcores through multiple steps. */
204cb056611SStephen Hemminger enum { WORKER_WAITING = 1, WORKER_RUN_SIGNAL, WORKER_RUNNING, WORKER_FINISHED };
RTE_ATOMIC(uint16_t)205*b6a7e685STyler Retzlaff static RTE_ATOMIC(uint16_t) lcore_state[RTE_MAX_LCORE];
206a9de470cSBruce Richardson 
207a9de470cSBruce Richardson static void
208cb056611SStephen Hemminger main_init_workers(void)
209a9de470cSBruce Richardson {
210a9de470cSBruce Richardson 	unsigned i;
211a9de470cSBruce Richardson 
212cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
213*b6a7e685STyler Retzlaff 		rte_atomic_store_explicit(&lcore_state[i], WORKER_WAITING,
214*b6a7e685STyler Retzlaff 				rte_memory_order_relaxed);
215a9de470cSBruce Richardson 	}
216a9de470cSBruce Richardson }
217a9de470cSBruce Richardson 
218a9de470cSBruce Richardson static void
main_start_workers(void)219cb056611SStephen Hemminger main_start_workers(void)
220a9de470cSBruce Richardson {
221a9de470cSBruce Richardson 	unsigned i;
222a9de470cSBruce Richardson 
223cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
224*b6a7e685STyler Retzlaff 		rte_atomic_store_explicit(&lcore_state[i], WORKER_RUN_SIGNAL,
225*b6a7e685STyler Retzlaff 				rte_memory_order_release);
226a9de470cSBruce Richardson 	}
227cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
228*b6a7e685STyler Retzlaff 		rte_wait_until_equal_16((uint16_t *)(uintptr_t)&lcore_state[i], WORKER_RUNNING,
229*b6a7e685STyler Retzlaff 				rte_memory_order_acquire);
230a9de470cSBruce Richardson 	}
231a9de470cSBruce Richardson }
232a9de470cSBruce Richardson 
233a9de470cSBruce Richardson static void
main_wait_for_workers(void)234cb056611SStephen Hemminger main_wait_for_workers(void)
235a9de470cSBruce Richardson {
236a9de470cSBruce Richardson 	unsigned i;
237a9de470cSBruce Richardson 
238cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
239*b6a7e685STyler Retzlaff 		rte_wait_until_equal_16((uint16_t *)(uintptr_t)&lcore_state[i], WORKER_FINISHED,
240*b6a7e685STyler Retzlaff 				rte_memory_order_acquire);
241a9de470cSBruce Richardson 	}
242a9de470cSBruce Richardson }
243a9de470cSBruce Richardson 
244a9de470cSBruce Richardson static void
worker_wait_to_start(void)245cb056611SStephen Hemminger worker_wait_to_start(void)
246a9de470cSBruce Richardson {
247a9de470cSBruce Richardson 	unsigned lcore_id = rte_lcore_id();
248a9de470cSBruce Richardson 
249*b6a7e685STyler Retzlaff 	rte_wait_until_equal_16((uint16_t *)(uintptr_t)&lcore_state[lcore_id], WORKER_RUN_SIGNAL,
250*b6a7e685STyler Retzlaff 			rte_memory_order_acquire);
251*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&lcore_state[lcore_id], WORKER_RUNNING,
252*b6a7e685STyler Retzlaff 			rte_memory_order_release);
253a9de470cSBruce Richardson }
254a9de470cSBruce Richardson 
255a9de470cSBruce Richardson static void
worker_finish(void)256cb056611SStephen Hemminger worker_finish(void)
257a9de470cSBruce Richardson {
258a9de470cSBruce Richardson 	unsigned lcore_id = rte_lcore_id();
259a9de470cSBruce Richardson 
260*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&lcore_state[lcore_id], WORKER_FINISHED,
261*b6a7e685STyler Retzlaff 			rte_memory_order_release);
262a9de470cSBruce Richardson }
263a9de470cSBruce Richardson 
264a9de470cSBruce Richardson 
265a9de470cSBruce Richardson static volatile int cb_count = 0;
266a9de470cSBruce Richardson 
267a9de470cSBruce Richardson /* callback for second stress test. will only be called
268cb056611SStephen Hemminger  * on main lcore
269cb056611SStephen Hemminger  */
270a9de470cSBruce Richardson static void
timer_stress2_cb(struct rte_timer * tim __rte_unused,void * arg __rte_unused)271a9de470cSBruce Richardson timer_stress2_cb(struct rte_timer *tim __rte_unused, void *arg __rte_unused)
272a9de470cSBruce Richardson {
273a9de470cSBruce Richardson 	cb_count++;
274a9de470cSBruce Richardson }
275a9de470cSBruce Richardson 
276a9de470cSBruce Richardson #define NB_STRESS2_TIMERS 8192
277a9de470cSBruce Richardson 
278a9de470cSBruce Richardson static int
timer_stress2_main_loop(__rte_unused void * arg)279f2fc83b4SThomas Monjalon timer_stress2_main_loop(__rte_unused void *arg)
280a9de470cSBruce Richardson {
281a9de470cSBruce Richardson 	static struct rte_timer *timers;
282a9de470cSBruce Richardson 	int i, ret;
283a9de470cSBruce Richardson 	uint64_t delay = rte_get_timer_hz() / 20;
284cb056611SStephen Hemminger 	unsigned int lcore_id = rte_lcore_id();
285cb056611SStephen Hemminger 	unsigned int main_lcore = rte_get_main_lcore();
286a9de470cSBruce Richardson 	int32_t my_collisions = 0;
287*b6a7e685STyler Retzlaff 	static RTE_ATOMIC(uint32_t) collisions;
288a9de470cSBruce Richardson 
289cb056611SStephen Hemminger 	if (lcore_id == main_lcore) {
290a9de470cSBruce Richardson 		cb_count = 0;
291a9de470cSBruce Richardson 		test_failed = 0;
292*b6a7e685STyler Retzlaff 		rte_atomic_store_explicit(&collisions, 0, rte_memory_order_relaxed);
293a9de470cSBruce Richardson 		timers = rte_malloc(NULL, sizeof(*timers) * NB_STRESS2_TIMERS, 0);
294a9de470cSBruce Richardson 		if (timers == NULL) {
295a9de470cSBruce Richardson 			printf("Test Failed\n");
296a9de470cSBruce Richardson 			printf("- Cannot allocate memory for timers\n" );
297a9de470cSBruce Richardson 			test_failed = 1;
298cb056611SStephen Hemminger 			main_start_workers();
299a9de470cSBruce Richardson 			goto cleanup;
300a9de470cSBruce Richardson 		}
301a9de470cSBruce Richardson 		for (i = 0; i < NB_STRESS2_TIMERS; i++)
302a9de470cSBruce Richardson 			rte_timer_init(&timers[i]);
303cb056611SStephen Hemminger 		main_start_workers();
304a9de470cSBruce Richardson 	} else {
305cb056611SStephen Hemminger 		worker_wait_to_start();
306a9de470cSBruce Richardson 		if (test_failed)
307a9de470cSBruce Richardson 			goto cleanup;
308a9de470cSBruce Richardson 	}
309a9de470cSBruce Richardson 
310cb056611SStephen Hemminger 	/* have all cores schedule all timers on main lcore */
311a9de470cSBruce Richardson 	for (i = 0; i < NB_STRESS2_TIMERS; i++) {
312cb056611SStephen Hemminger 		ret = rte_timer_reset(&timers[i], delay, SINGLE, main_lcore,
313a9de470cSBruce Richardson 				timer_stress2_cb, NULL);
314a9de470cSBruce Richardson 		/* there will be collisions when multiple cores simultaneously
315a9de470cSBruce Richardson 		 * configure the same timers */
316a9de470cSBruce Richardson 		if (ret != 0)
317a9de470cSBruce Richardson 			my_collisions++;
318a9de470cSBruce Richardson 	}
319a9de470cSBruce Richardson 	if (my_collisions != 0)
320*b6a7e685STyler Retzlaff 		rte_atomic_fetch_add_explicit(&collisions, my_collisions, rte_memory_order_relaxed);
321a9de470cSBruce Richardson 
322a9de470cSBruce Richardson 	/* wait long enough for timers to expire */
323a9de470cSBruce Richardson 	rte_delay_ms(100);
324a9de470cSBruce Richardson 
325a9de470cSBruce Richardson 	/* all cores rendezvous */
326cb056611SStephen Hemminger 	if (lcore_id == main_lcore) {
327cb056611SStephen Hemminger 		main_wait_for_workers();
328a9de470cSBruce Richardson 	} else {
329cb056611SStephen Hemminger 		worker_finish();
330a9de470cSBruce Richardson 	}
331a9de470cSBruce Richardson 
332a9de470cSBruce Richardson 	/* now check that we get the right number of callbacks */
333cb056611SStephen Hemminger 	if (lcore_id == main_lcore) {
334*b6a7e685STyler Retzlaff 		my_collisions = rte_atomic_load_explicit(&collisions, rte_memory_order_relaxed);
335a9de470cSBruce Richardson 		if (my_collisions != 0)
336a9de470cSBruce Richardson 			printf("- %d timer reset collisions (OK)\n", my_collisions);
337a9de470cSBruce Richardson 		rte_timer_manage();
338a9de470cSBruce Richardson 		if (cb_count != NB_STRESS2_TIMERS) {
339a9de470cSBruce Richardson 			printf("Test Failed\n");
340a9de470cSBruce Richardson 			printf("- Stress test 2, part 1 failed\n");
341a9de470cSBruce Richardson 			printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS,
342a9de470cSBruce Richardson 					cb_count);
343a9de470cSBruce Richardson 			test_failed = 1;
344cb056611SStephen Hemminger 			main_start_workers();
345a9de470cSBruce Richardson 			goto cleanup;
346a9de470cSBruce Richardson 		}
347a9de470cSBruce Richardson 		cb_count = 0;
348a9de470cSBruce Richardson 
349a9de470cSBruce Richardson 		/* proceed */
350cb056611SStephen Hemminger 		main_start_workers();
351a9de470cSBruce Richardson 	} else {
352a9de470cSBruce Richardson 		/* proceed */
353cb056611SStephen Hemminger 		worker_wait_to_start();
354a9de470cSBruce Richardson 		if (test_failed)
355a9de470cSBruce Richardson 			goto cleanup;
356a9de470cSBruce Richardson 	}
357a9de470cSBruce Richardson 
358a9de470cSBruce Richardson 	/* now test again, just stop and restart timers at random after init*/
359a9de470cSBruce Richardson 	for (i = 0; i < NB_STRESS2_TIMERS; i++)
360cb056611SStephen Hemminger 		rte_timer_reset(&timers[i], delay, SINGLE, main_lcore,
361a9de470cSBruce Richardson 				timer_stress2_cb, NULL);
362a9de470cSBruce Richardson 
363a9de470cSBruce Richardson 	/* pick random timer to reset, stopping them first half the time */
364a9de470cSBruce Richardson 	for (i = 0; i < 100000; i++) {
365a9de470cSBruce Richardson 		int r = rand() % NB_STRESS2_TIMERS;
366a9de470cSBruce Richardson 		if (i % 2)
367a9de470cSBruce Richardson 			rte_timer_stop(&timers[r]);
368cb056611SStephen Hemminger 		rte_timer_reset(&timers[r], delay, SINGLE, main_lcore,
369a9de470cSBruce Richardson 				timer_stress2_cb, NULL);
370a9de470cSBruce Richardson 	}
371a9de470cSBruce Richardson 
372a9de470cSBruce Richardson 	/* wait long enough for timers to expire */
373a9de470cSBruce Richardson 	rte_delay_ms(100);
374a9de470cSBruce Richardson 
375a9de470cSBruce Richardson 	/* now check that we get the right number of callbacks */
376cb056611SStephen Hemminger 	if (lcore_id == main_lcore) {
377cb056611SStephen Hemminger 		main_wait_for_workers();
378a9de470cSBruce Richardson 
379a9de470cSBruce Richardson 		rte_timer_manage();
380a9de470cSBruce Richardson 		if (cb_count != NB_STRESS2_TIMERS) {
381a9de470cSBruce Richardson 			printf("Test Failed\n");
382a9de470cSBruce Richardson 			printf("- Stress test 2, part 2 failed\n");
383a9de470cSBruce Richardson 			printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS,
384a9de470cSBruce Richardson 					cb_count);
385a9de470cSBruce Richardson 			test_failed = 1;
386a9de470cSBruce Richardson 		} else {
387a9de470cSBruce Richardson 			printf("Test OK\n");
388a9de470cSBruce Richardson 		}
389a9de470cSBruce Richardson 	}
390a9de470cSBruce Richardson 
391a9de470cSBruce Richardson cleanup:
392cb056611SStephen Hemminger 	if (lcore_id == main_lcore) {
393cb056611SStephen Hemminger 		main_wait_for_workers();
394a9de470cSBruce Richardson 		if (timers != NULL) {
395a9de470cSBruce Richardson 			rte_free(timers);
396a9de470cSBruce Richardson 			timers = NULL;
397a9de470cSBruce Richardson 		}
398a9de470cSBruce Richardson 	} else {
399cb056611SStephen Hemminger 		worker_finish();
400a9de470cSBruce Richardson 	}
401a9de470cSBruce Richardson 
402a9de470cSBruce Richardson 	return 0;
403a9de470cSBruce Richardson }
404a9de470cSBruce Richardson 
405a9de470cSBruce Richardson /* timer callback for basic tests */
406a9de470cSBruce Richardson static void
timer_basic_cb(struct rte_timer * tim,void * arg)407a9de470cSBruce Richardson timer_basic_cb(struct rte_timer *tim, void *arg)
408a9de470cSBruce Richardson {
409a9de470cSBruce Richardson 	struct mytimerinfo *timinfo = arg;
410a9de470cSBruce Richardson 	uint64_t hz = rte_get_timer_hz();
411a9de470cSBruce Richardson 	unsigned lcore_id = rte_lcore_id();
412a9de470cSBruce Richardson 	uint64_t cur_time = rte_get_timer_cycles();
413a9de470cSBruce Richardson 
414a9de470cSBruce Richardson 	if (rte_timer_pending(tim))
415a9de470cSBruce Richardson 		return;
416a9de470cSBruce Richardson 
417a9de470cSBruce Richardson 	timinfo->count ++;
418a9de470cSBruce Richardson 
419a9de470cSBruce Richardson 	RTE_LOG(INFO, TESTTIMER,
420a9de470cSBruce Richardson 		"%"PRIu64": callback id=%u count=%u on core %u\n",
421a9de470cSBruce Richardson 		cur_time, timinfo->id, timinfo->count, lcore_id);
422a9de470cSBruce Richardson 
423a9de470cSBruce Richardson 	/* reload timer 0 on same core */
424a9de470cSBruce Richardson 	if (timinfo->id == 0 && timinfo->count < 20) {
425a9de470cSBruce Richardson 		mytimer_reset(timinfo, hz, SINGLE, lcore_id, timer_basic_cb);
426a9de470cSBruce Richardson 		return;
427a9de470cSBruce Richardson 	}
428a9de470cSBruce Richardson 
429a9de470cSBruce Richardson 	/* reload timer 1 on next core */
430a9de470cSBruce Richardson 	if (timinfo->id == 1 && timinfo->count < 10) {
431a9de470cSBruce Richardson 		mytimer_reset(timinfo, hz*2, SINGLE,
432a9de470cSBruce Richardson 			      rte_get_next_lcore(lcore_id, 0, 1),
433a9de470cSBruce Richardson 			      timer_basic_cb);
434a9de470cSBruce Richardson 		return;
435a9de470cSBruce Richardson 	}
436a9de470cSBruce Richardson 
4374a6672c2SStephen Hemminger 	/* Explicitly stop timer 0. Once stop() called, we can even
438a9de470cSBruce Richardson 	 * erase the content of the structure: it is not referenced
439a9de470cSBruce Richardson 	 * anymore by any code (in case of dynamic structure, it can
440a9de470cSBruce Richardson 	 * be freed) */
441a9de470cSBruce Richardson 	if (timinfo->id == 0 && timinfo->count == 20) {
442a9de470cSBruce Richardson 
443a9de470cSBruce Richardson 		/* stop_sync() is not needed, because we know that the
444a9de470cSBruce Richardson 		 * status of timer is only modified by this core */
445a9de470cSBruce Richardson 		rte_timer_stop(tim);
446a9de470cSBruce Richardson 		memset(tim, 0xAA, sizeof(struct rte_timer));
447a9de470cSBruce Richardson 		return;
448a9de470cSBruce Richardson 	}
449a9de470cSBruce Richardson 
450a9de470cSBruce Richardson 	/* stop timer3, and restart a new timer0 (it was removed 5
451a9de470cSBruce Richardson 	 * seconds ago) for a single shot */
452a9de470cSBruce Richardson 	if (timinfo->id == 2 && timinfo->count == 25) {
453a9de470cSBruce Richardson 		rte_timer_stop_sync(&mytiminfo[3].tim);
454a9de470cSBruce Richardson 
455a9de470cSBruce Richardson 		/* need to reinit because structure was erased with 0xAA */
456a9de470cSBruce Richardson 		rte_timer_init(&mytiminfo[0].tim);
457a9de470cSBruce Richardson 		mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
458a9de470cSBruce Richardson 			      timer_basic_cb);
459a9de470cSBruce Richardson 	}
460a9de470cSBruce Richardson }
461a9de470cSBruce Richardson 
462a9de470cSBruce Richardson static int
timer_basic_main_loop(__rte_unused void * arg)463f2fc83b4SThomas Monjalon timer_basic_main_loop(__rte_unused void *arg)
464a9de470cSBruce Richardson {
465a9de470cSBruce Richardson 	uint64_t hz = rte_get_timer_hz();
466a9de470cSBruce Richardson 	unsigned lcore_id = rte_lcore_id();
467a9de470cSBruce Richardson 	uint64_t cur_time;
468a9de470cSBruce Richardson 	int64_t diff = 0;
469a9de470cSBruce Richardson 
470a9de470cSBruce Richardson 	/* launch all timers on core 0 */
471cb056611SStephen Hemminger 	if (lcore_id == rte_get_main_lcore()) {
472a9de470cSBruce Richardson 		mytimer_reset(&mytiminfo[0], hz/4, SINGLE, lcore_id,
473a9de470cSBruce Richardson 			      timer_basic_cb);
474a9de470cSBruce Richardson 		mytimer_reset(&mytiminfo[1], hz/2, SINGLE, lcore_id,
475a9de470cSBruce Richardson 			      timer_basic_cb);
476a9de470cSBruce Richardson 		mytimer_reset(&mytiminfo[2], hz/4, PERIODICAL, lcore_id,
477a9de470cSBruce Richardson 			      timer_basic_cb);
478a9de470cSBruce Richardson 		mytimer_reset(&mytiminfo[3], hz/4, PERIODICAL,
479a9de470cSBruce Richardson 			      rte_get_next_lcore(lcore_id, 0, 1),
480a9de470cSBruce Richardson 			      timer_basic_cb);
481a9de470cSBruce Richardson 	}
482a9de470cSBruce Richardson 
483a9de470cSBruce Richardson 	while (diff >= 0) {
484a9de470cSBruce Richardson 
485a9de470cSBruce Richardson 		/* call the timer handler on each core */
486a9de470cSBruce Richardson 		rte_timer_manage();
487a9de470cSBruce Richardson 
488a9de470cSBruce Richardson 		/* simulate the processing of a packet
489a9de470cSBruce Richardson 		 * (3 us = 6000 cycles at 2 Ghz) */
490a9de470cSBruce Richardson 		rte_delay_us(3);
491a9de470cSBruce Richardson 
492a9de470cSBruce Richardson 		cur_time = rte_get_timer_cycles();
493a9de470cSBruce Richardson 		diff = end_time - cur_time;
494a9de470cSBruce Richardson 	}
495a9de470cSBruce Richardson 	RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
496a9de470cSBruce Richardson 
497a9de470cSBruce Richardson 	return 0;
498a9de470cSBruce Richardson }
499a9de470cSBruce Richardson 
500a9de470cSBruce Richardson static int
timer_sanity_check(void)501a9de470cSBruce Richardson timer_sanity_check(void)
502a9de470cSBruce Richardson {
503a9de470cSBruce Richardson #ifdef RTE_LIBEAL_USE_HPET
504a9de470cSBruce Richardson 	if (eal_timer_source != EAL_TIMER_HPET) {
505a9de470cSBruce Richardson 		printf("Not using HPET, can't sanity check timer sources\n");
506a9de470cSBruce Richardson 		return 0;
507a9de470cSBruce Richardson 	}
508a9de470cSBruce Richardson 
509a9de470cSBruce Richardson 	const uint64_t t_hz = rte_get_tsc_hz();
510a9de470cSBruce Richardson 	const uint64_t h_hz = rte_get_hpet_hz();
511a9de470cSBruce Richardson 	printf("Hertz values: TSC = %"PRIu64", HPET = %"PRIu64"\n", t_hz, h_hz);
512a9de470cSBruce Richardson 
513a9de470cSBruce Richardson 	const uint64_t tsc_start = rte_get_tsc_cycles();
514a9de470cSBruce Richardson 	const uint64_t hpet_start = rte_get_hpet_cycles();
515a9de470cSBruce Richardson 	rte_delay_ms(100); /* delay 1/10 second */
516a9de470cSBruce Richardson 	const uint64_t tsc_end = rte_get_tsc_cycles();
517a9de470cSBruce Richardson 	const uint64_t hpet_end = rte_get_hpet_cycles();
518a9de470cSBruce Richardson 	printf("Measured cycles: TSC = %"PRIu64", HPET = %"PRIu64"\n",
519a9de470cSBruce Richardson 			tsc_end-tsc_start, hpet_end-hpet_start);
520a9de470cSBruce Richardson 
521a9de470cSBruce Richardson 	const double tsc_time = (double)(tsc_end - tsc_start)/t_hz;
522a9de470cSBruce Richardson 	const double hpet_time = (double)(hpet_end - hpet_start)/h_hz;
523a9de470cSBruce Richardson 	/* get the percentage that the times differ by */
524a9de470cSBruce Richardson 	const double time_diff = fabs(tsc_time - hpet_time)*100/tsc_time;
525a9de470cSBruce Richardson 	printf("Measured time: TSC = %.4f, HPET = %.4f\n", tsc_time, hpet_time);
526a9de470cSBruce Richardson 
527a9de470cSBruce Richardson 	printf("Elapsed time measured by TSC and HPET differ by %f%%\n",
528a9de470cSBruce Richardson 			time_diff);
529a9de470cSBruce Richardson 	if (time_diff > 0.1) {
530a9de470cSBruce Richardson 		printf("Error times differ by >0.1%%");
531a9de470cSBruce Richardson 		return -1;
532a9de470cSBruce Richardson 	}
533a9de470cSBruce Richardson #endif
534a9de470cSBruce Richardson 	return 0;
535a9de470cSBruce Richardson }
536a9de470cSBruce Richardson 
537a9de470cSBruce Richardson static int
test_timer(void)538a9de470cSBruce Richardson test_timer(void)
539a9de470cSBruce Richardson {
540a9de470cSBruce Richardson 	unsigned i;
541a9de470cSBruce Richardson 	uint64_t cur_time;
542a9de470cSBruce Richardson 	uint64_t hz;
543a9de470cSBruce Richardson 
544e0f4a0edSDavid Marchand 	if (rte_lcore_count() < 2) {
545e0f4a0edSDavid Marchand 		printf("Not enough cores for timer_autotest, expecting at least 2\n");
546e0f4a0edSDavid Marchand 		return TEST_SKIPPED;
547e0f4a0edSDavid Marchand 	}
548e0f4a0edSDavid Marchand 
549a9de470cSBruce Richardson 	/* sanity check our timer sources and timer config values */
550a9de470cSBruce Richardson 	if (timer_sanity_check() < 0) {
551a9de470cSBruce Richardson 		printf("Timer sanity checks failed\n");
552a9de470cSBruce Richardson 		return TEST_FAILED;
553a9de470cSBruce Richardson 	}
554a9de470cSBruce Richardson 
555a9de470cSBruce Richardson 	/* init timer */
556a9de470cSBruce Richardson 	for (i=0; i<NB_TIMER; i++) {
557a9de470cSBruce Richardson 		memset(&mytiminfo[i], 0, sizeof(struct mytimerinfo));
558a9de470cSBruce Richardson 		mytiminfo[i].id = i;
559a9de470cSBruce Richardson 		rte_timer_init(&mytiminfo[i].tim);
560a9de470cSBruce Richardson 	}
561a9de470cSBruce Richardson 
562a9de470cSBruce Richardson 	/* calculate the "end of test" time */
563a9de470cSBruce Richardson 	cur_time = rte_get_timer_cycles();
564a9de470cSBruce Richardson 	hz = rte_get_timer_hz();
565a9de470cSBruce Richardson 	end_time = cur_time + (hz * TEST_DURATION_S);
566a9de470cSBruce Richardson 
567a9de470cSBruce Richardson 	/* start other cores */
568a9de470cSBruce Richardson 	printf("Start timer stress tests\n");
569cb056611SStephen Hemminger 	rte_eal_mp_remote_launch(timer_stress_main_loop, NULL, CALL_MAIN);
570a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
571a9de470cSBruce Richardson 
572a9de470cSBruce Richardson 	/* stop timer 0 used for stress test */
573a9de470cSBruce Richardson 	rte_timer_stop_sync(&mytiminfo[0].tim);
574a9de470cSBruce Richardson 
575a9de470cSBruce Richardson 	/* run a second, slightly different set of stress tests */
576a9de470cSBruce Richardson 	printf("\nStart timer stress tests 2\n");
577a9de470cSBruce Richardson 	test_failed = 0;
578827aa9c6SJoyce Kong 	main_init_workers();
579cb056611SStephen Hemminger 	rte_eal_mp_remote_launch(timer_stress2_main_loop, NULL, CALL_MAIN);
580a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
581a9de470cSBruce Richardson 	if (test_failed)
582a9de470cSBruce Richardson 		return TEST_FAILED;
583a9de470cSBruce Richardson 
584a9de470cSBruce Richardson 	/* calculate the "end of test" time */
585a9de470cSBruce Richardson 	cur_time = rte_get_timer_cycles();
586a9de470cSBruce Richardson 	hz = rte_get_timer_hz();
587a9de470cSBruce Richardson 	end_time = cur_time + (hz * TEST_DURATION_S);
588a9de470cSBruce Richardson 
589a9de470cSBruce Richardson 	/* start other cores */
590a9de470cSBruce Richardson 	printf("\nStart timer basic tests\n");
591cb056611SStephen Hemminger 	rte_eal_mp_remote_launch(timer_basic_main_loop, NULL, CALL_MAIN);
592a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
593a9de470cSBruce Richardson 
594a9de470cSBruce Richardson 	/* stop all timers */
595a9de470cSBruce Richardson 	for (i=0; i<NB_TIMER; i++) {
596a9de470cSBruce Richardson 		rte_timer_stop_sync(&mytiminfo[i].tim);
597a9de470cSBruce Richardson 	}
598a9de470cSBruce Richardson 
599a9de470cSBruce Richardson 	rte_timer_dump_stats(stdout);
600a9de470cSBruce Richardson 
601a9de470cSBruce Richardson 	return TEST_SUCCESS;
602a9de470cSBruce Richardson }
603a9de470cSBruce Richardson 
604e0a8442cSBruce Richardson REGISTER_FAST_TEST(timer_autotest, false, true, test_timer);
605