xref: /f-stack/dpdk/app/test/test_timer.c (revision 2d9fd380)
14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang  * Copyright(c) 2010-2014 Intel Corporation
34418919fSjohnjiang  */
44418919fSjohnjiang 
54418919fSjohnjiang #include "test.h"
64418919fSjohnjiang 
74418919fSjohnjiang /*
84418919fSjohnjiang  * Timer
94418919fSjohnjiang  * =====
104418919fSjohnjiang  *
114418919fSjohnjiang  * #. Stress test 1.
124418919fSjohnjiang  *
134418919fSjohnjiang  *    The objective of the timer stress tests is to check that there are no
144418919fSjohnjiang  *    race conditions in list and status management. This test launches,
154418919fSjohnjiang  *    resets and stops the timer very often on many cores at the same
164418919fSjohnjiang  *    time.
174418919fSjohnjiang  *
184418919fSjohnjiang  *    - Only one timer is used for this test.
194418919fSjohnjiang  *    - On each core, the rte_timer_manage() function is called from the main
204418919fSjohnjiang  *      loop every 3 microseconds.
214418919fSjohnjiang  *    - In the main loop, the timer may be reset (randomly, with a
224418919fSjohnjiang  *      probability of 0.5 %) 100 microseconds later on a random core, or
234418919fSjohnjiang  *      stopped (with a probability of 0.5 % also).
244418919fSjohnjiang  *    - In callback, the timer is can be reset (randomly, with a
254418919fSjohnjiang  *      probability of 0.5 %) 100 microseconds later on the same core or
264418919fSjohnjiang  *      on another core (same probability), or stopped (same
274418919fSjohnjiang  *      probability).
284418919fSjohnjiang  *
294418919fSjohnjiang  * # Stress test 2.
304418919fSjohnjiang  *
314418919fSjohnjiang  *    The objective of this test is similar to the first in that it attempts
324418919fSjohnjiang  *    to find if there are any race conditions in the timer library. However,
334418919fSjohnjiang  *    it is less complex in terms of operations performed and duration, as it
344418919fSjohnjiang  *    is designed to have a predictable outcome that can be tested.
354418919fSjohnjiang  *
364418919fSjohnjiang  *    - A set of timers is initialized for use by the test
374418919fSjohnjiang  *    - All cores then simultaneously are set to schedule all the timers at
384418919fSjohnjiang  *      the same time, so conflicts should occur.
394418919fSjohnjiang  *    - Then there is a delay while we wait for the timers to expire
40*2d9fd380Sjfb8856606  *    - Then the main lcore calls timer_manage() and we check that all
414418919fSjohnjiang  *      timers have had their callbacks called exactly once - no more no less.
424418919fSjohnjiang  *    - Then we repeat the process, except after setting up the timers, we have
434418919fSjohnjiang  *      all cores randomly reschedule them.
444418919fSjohnjiang  *    - Again we check that the expected number of callbacks has occurred when
454418919fSjohnjiang  *      we call timer-manage.
464418919fSjohnjiang  *
474418919fSjohnjiang  * #. Basic test.
484418919fSjohnjiang  *
494418919fSjohnjiang  *    This test performs basic functional checks of the timers. The test
504418919fSjohnjiang  *    uses four different timers that are loaded and stopped under
514418919fSjohnjiang  *    specific conditions in specific contexts.
524418919fSjohnjiang  *
534418919fSjohnjiang  *    - Four timers are used for this test.
544418919fSjohnjiang  *    - On each core, the rte_timer_manage() function is called from main loop
554418919fSjohnjiang  *      every 3 microseconds.
564418919fSjohnjiang  *
574418919fSjohnjiang  *    The autotest python script checks that the behavior is correct:
584418919fSjohnjiang  *
594418919fSjohnjiang  *    - timer0
604418919fSjohnjiang  *
61*2d9fd380Sjfb8856606  *      - At initialization, timer0 is loaded by the main core, on main core
624418919fSjohnjiang  *        in "single" mode (time = 1 second).
634418919fSjohnjiang  *      - In the first 19 callbacks, timer0 is reloaded on the same core,
644418919fSjohnjiang  *        then, it is explicitly stopped at the 20th call.
654418919fSjohnjiang  *      - At t=25s, timer0 is reloaded once by timer2.
664418919fSjohnjiang  *
674418919fSjohnjiang  *    - timer1
684418919fSjohnjiang  *
69*2d9fd380Sjfb8856606  *      - At initialization, timer1 is loaded by the main core, on the
70*2d9fd380Sjfb8856606  *        main core in "single" mode (time = 2 seconds).
714418919fSjohnjiang  *      - In the first 9 callbacks, timer1 is reloaded on another
724418919fSjohnjiang  *        core. After the 10th callback, timer1 is not reloaded anymore.
734418919fSjohnjiang  *
744418919fSjohnjiang  *    - timer2
754418919fSjohnjiang  *
76*2d9fd380Sjfb8856606  *      - At initialization, timer2 is loaded by the main core, on the
77*2d9fd380Sjfb8856606  *        main core in "periodical" mode (time = 1 second).
784418919fSjohnjiang  *      - In the callback, when t=25s, it stops timer3 and reloads timer0
794418919fSjohnjiang  *        on the current core.
804418919fSjohnjiang  *
814418919fSjohnjiang  *    - timer3
824418919fSjohnjiang  *
83*2d9fd380Sjfb8856606  *      - At initialization, timer3 is loaded by the main core, on
844418919fSjohnjiang  *        another core in "periodical" mode (time = 1 second).
854418919fSjohnjiang  *      - It is stopped at t=25s by timer2.
864418919fSjohnjiang  */
874418919fSjohnjiang 
884418919fSjohnjiang #include <stdio.h>
894418919fSjohnjiang #include <stdarg.h>
904418919fSjohnjiang #include <string.h>
914418919fSjohnjiang #include <stdlib.h>
924418919fSjohnjiang #include <stdint.h>
934418919fSjohnjiang #include <inttypes.h>
944418919fSjohnjiang #include <sys/queue.h>
954418919fSjohnjiang #include <math.h>
964418919fSjohnjiang 
974418919fSjohnjiang #include <rte_common.h>
984418919fSjohnjiang #include <rte_log.h>
994418919fSjohnjiang #include <rte_memory.h>
1004418919fSjohnjiang #include <rte_launch.h>
1014418919fSjohnjiang #include <rte_cycles.h>
1024418919fSjohnjiang #include <rte_eal.h>
1034418919fSjohnjiang #include <rte_per_lcore.h>
1044418919fSjohnjiang #include <rte_lcore.h>
1054418919fSjohnjiang #include <rte_atomic.h>
1064418919fSjohnjiang #include <rte_timer.h>
1074418919fSjohnjiang #include <rte_random.h>
1084418919fSjohnjiang #include <rte_malloc.h>
1094418919fSjohnjiang #include <rte_pause.h>
1104418919fSjohnjiang 
1114418919fSjohnjiang #define TEST_DURATION_S 1 /* in seconds */
1124418919fSjohnjiang #define NB_TIMER 4
1134418919fSjohnjiang 
1144418919fSjohnjiang #define RTE_LOGTYPE_TESTTIMER RTE_LOGTYPE_USER3
1154418919fSjohnjiang 
1164418919fSjohnjiang static volatile uint64_t end_time;
1174418919fSjohnjiang static volatile int test_failed;
1184418919fSjohnjiang 
1194418919fSjohnjiang struct mytimerinfo {
1204418919fSjohnjiang 	struct rte_timer tim;
1214418919fSjohnjiang 	unsigned id;
1224418919fSjohnjiang 	unsigned count;
1234418919fSjohnjiang };
1244418919fSjohnjiang 
1254418919fSjohnjiang static struct mytimerinfo mytiminfo[NB_TIMER];
1264418919fSjohnjiang 
1274418919fSjohnjiang static void timer_basic_cb(struct rte_timer *tim, void *arg);
1284418919fSjohnjiang 
1294418919fSjohnjiang static void
mytimer_reset(struct mytimerinfo * timinfo,uint64_t ticks,enum rte_timer_type type,unsigned tim_lcore,rte_timer_cb_t fct)1304418919fSjohnjiang mytimer_reset(struct mytimerinfo *timinfo, uint64_t ticks,
1314418919fSjohnjiang 	      enum rte_timer_type type, unsigned tim_lcore,
1324418919fSjohnjiang 	      rte_timer_cb_t fct)
1334418919fSjohnjiang {
1344418919fSjohnjiang 	rte_timer_reset_sync(&timinfo->tim, ticks, type, tim_lcore,
1354418919fSjohnjiang 			     fct, timinfo);
1364418919fSjohnjiang }
1374418919fSjohnjiang 
1384418919fSjohnjiang /* timer callback for stress tests */
1394418919fSjohnjiang static void
timer_stress_cb(__rte_unused struct rte_timer * tim,__rte_unused void * arg)140*2d9fd380Sjfb8856606 timer_stress_cb(__rte_unused struct rte_timer *tim,
141*2d9fd380Sjfb8856606 		__rte_unused void *arg)
1424418919fSjohnjiang {
1434418919fSjohnjiang 	long r;
1444418919fSjohnjiang 	unsigned lcore_id = rte_lcore_id();
1454418919fSjohnjiang 	uint64_t hz = rte_get_timer_hz();
1464418919fSjohnjiang 
1474418919fSjohnjiang 	if (rte_timer_pending(tim))
1484418919fSjohnjiang 		return;
1494418919fSjohnjiang 
1504418919fSjohnjiang 	r = rte_rand();
1514418919fSjohnjiang 	if ((r & 0xff) == 0) {
1524418919fSjohnjiang 		mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
1534418919fSjohnjiang 			      timer_stress_cb);
1544418919fSjohnjiang 	}
1554418919fSjohnjiang 	else if ((r & 0xff) == 1) {
1564418919fSjohnjiang 		mytimer_reset(&mytiminfo[0], hz, SINGLE,
1574418919fSjohnjiang 			      rte_get_next_lcore(lcore_id, 0, 1),
1584418919fSjohnjiang 			      timer_stress_cb);
1594418919fSjohnjiang 	}
1604418919fSjohnjiang 	else if ((r & 0xff) == 2) {
1614418919fSjohnjiang 		rte_timer_stop(&mytiminfo[0].tim);
1624418919fSjohnjiang 	}
1634418919fSjohnjiang }
1644418919fSjohnjiang 
1654418919fSjohnjiang static int
timer_stress_main_loop(__rte_unused void * arg)166*2d9fd380Sjfb8856606 timer_stress_main_loop(__rte_unused void *arg)
1674418919fSjohnjiang {
1684418919fSjohnjiang 	uint64_t hz = rte_get_timer_hz();
1694418919fSjohnjiang 	unsigned lcore_id = rte_lcore_id();
1704418919fSjohnjiang 	uint64_t cur_time;
1714418919fSjohnjiang 	int64_t diff = 0;
1724418919fSjohnjiang 	long r;
1734418919fSjohnjiang 
1744418919fSjohnjiang 	while (diff >= 0) {
1754418919fSjohnjiang 
1764418919fSjohnjiang 		/* call the timer handler on each core */
1774418919fSjohnjiang 		rte_timer_manage();
1784418919fSjohnjiang 
1794418919fSjohnjiang 		/* simulate the processing of a packet
1804418919fSjohnjiang 		 * (1 us = 2000 cycles at 2 Ghz) */
1814418919fSjohnjiang 		rte_delay_us(1);
1824418919fSjohnjiang 
1834418919fSjohnjiang 		/* randomly stop or reset timer */
1844418919fSjohnjiang 		r = rte_rand();
1854418919fSjohnjiang 		lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
1864418919fSjohnjiang 		if ((r & 0xff) == 0) {
1874418919fSjohnjiang 			/* 100 us */
1884418919fSjohnjiang 			mytimer_reset(&mytiminfo[0], hz/10000, SINGLE, lcore_id,
1894418919fSjohnjiang 				      timer_stress_cb);
1904418919fSjohnjiang 		}
1914418919fSjohnjiang 		else if ((r & 0xff) == 1) {
1924418919fSjohnjiang 			rte_timer_stop_sync(&mytiminfo[0].tim);
1934418919fSjohnjiang 		}
1944418919fSjohnjiang 		cur_time = rte_get_timer_cycles();
1954418919fSjohnjiang 		diff = end_time - cur_time;
1964418919fSjohnjiang 	}
1974418919fSjohnjiang 
1984418919fSjohnjiang 	lcore_id = rte_lcore_id();
1994418919fSjohnjiang 	RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
2004418919fSjohnjiang 
2014418919fSjohnjiang 	return 0;
2024418919fSjohnjiang }
2034418919fSjohnjiang 
204*2d9fd380Sjfb8856606 /* Need to synchronize worker lcores through multiple steps. */
205*2d9fd380Sjfb8856606 enum { WORKER_WAITING = 1, WORKER_RUN_SIGNAL, WORKER_RUNNING, WORKER_FINISHED };
206*2d9fd380Sjfb8856606 static rte_atomic16_t lcore_state[RTE_MAX_LCORE];
2074418919fSjohnjiang 
2084418919fSjohnjiang static void
main_init_workers(void)209*2d9fd380Sjfb8856606 main_init_workers(void)
2104418919fSjohnjiang {
2114418919fSjohnjiang 	unsigned i;
2124418919fSjohnjiang 
213*2d9fd380Sjfb8856606 	RTE_LCORE_FOREACH_WORKER(i) {
214*2d9fd380Sjfb8856606 		rte_atomic16_set(&lcore_state[i], WORKER_WAITING);
2154418919fSjohnjiang 	}
2164418919fSjohnjiang }
2174418919fSjohnjiang 
2184418919fSjohnjiang static void
main_start_workers(void)219*2d9fd380Sjfb8856606 main_start_workers(void)
2204418919fSjohnjiang {
2214418919fSjohnjiang 	unsigned i;
2224418919fSjohnjiang 
223*2d9fd380Sjfb8856606 	RTE_LCORE_FOREACH_WORKER(i) {
224*2d9fd380Sjfb8856606 		rte_atomic16_set(&lcore_state[i], WORKER_RUN_SIGNAL);
2254418919fSjohnjiang 	}
226*2d9fd380Sjfb8856606 	RTE_LCORE_FOREACH_WORKER(i) {
227*2d9fd380Sjfb8856606 		while (rte_atomic16_read(&lcore_state[i]) != WORKER_RUNNING)
2284418919fSjohnjiang 			rte_pause();
2294418919fSjohnjiang 	}
2304418919fSjohnjiang }
2314418919fSjohnjiang 
2324418919fSjohnjiang static void
main_wait_for_workers(void)233*2d9fd380Sjfb8856606 main_wait_for_workers(void)
2344418919fSjohnjiang {
2354418919fSjohnjiang 	unsigned i;
2364418919fSjohnjiang 
237*2d9fd380Sjfb8856606 	RTE_LCORE_FOREACH_WORKER(i) {
238*2d9fd380Sjfb8856606 		while (rte_atomic16_read(&lcore_state[i]) != WORKER_FINISHED)
2394418919fSjohnjiang 			rte_pause();
2404418919fSjohnjiang 	}
2414418919fSjohnjiang }
2424418919fSjohnjiang 
2434418919fSjohnjiang static void
worker_wait_to_start(void)244*2d9fd380Sjfb8856606 worker_wait_to_start(void)
2454418919fSjohnjiang {
2464418919fSjohnjiang 	unsigned lcore_id = rte_lcore_id();
2474418919fSjohnjiang 
248*2d9fd380Sjfb8856606 	while (rte_atomic16_read(&lcore_state[lcore_id]) != WORKER_RUN_SIGNAL)
2494418919fSjohnjiang 		rte_pause();
250*2d9fd380Sjfb8856606 	rte_atomic16_set(&lcore_state[lcore_id], WORKER_RUNNING);
2514418919fSjohnjiang }
2524418919fSjohnjiang 
2534418919fSjohnjiang static void
worker_finish(void)254*2d9fd380Sjfb8856606 worker_finish(void)
2554418919fSjohnjiang {
2564418919fSjohnjiang 	unsigned lcore_id = rte_lcore_id();
2574418919fSjohnjiang 
258*2d9fd380Sjfb8856606 	rte_atomic16_set(&lcore_state[lcore_id], WORKER_FINISHED);
2594418919fSjohnjiang }
2604418919fSjohnjiang 
2614418919fSjohnjiang 
2624418919fSjohnjiang static volatile int cb_count = 0;
2634418919fSjohnjiang 
2644418919fSjohnjiang /* callback for second stress test. will only be called
265*2d9fd380Sjfb8856606  * on main lcore
266*2d9fd380Sjfb8856606  */
2674418919fSjohnjiang static void
timer_stress2_cb(struct rte_timer * tim __rte_unused,void * arg __rte_unused)2684418919fSjohnjiang timer_stress2_cb(struct rte_timer *tim __rte_unused, void *arg __rte_unused)
2694418919fSjohnjiang {
2704418919fSjohnjiang 	cb_count++;
2714418919fSjohnjiang }
2724418919fSjohnjiang 
2734418919fSjohnjiang #define NB_STRESS2_TIMERS 8192
2744418919fSjohnjiang 
2754418919fSjohnjiang static int
timer_stress2_main_loop(__rte_unused void * arg)276*2d9fd380Sjfb8856606 timer_stress2_main_loop(__rte_unused void *arg)
2774418919fSjohnjiang {
2784418919fSjohnjiang 	static struct rte_timer *timers;
2794418919fSjohnjiang 	int i, ret;
2804418919fSjohnjiang 	uint64_t delay = rte_get_timer_hz() / 20;
281*2d9fd380Sjfb8856606 	unsigned int lcore_id = rte_lcore_id();
282*2d9fd380Sjfb8856606 	unsigned int main_lcore = rte_get_main_lcore();
2834418919fSjohnjiang 	int32_t my_collisions = 0;
2844418919fSjohnjiang 	static rte_atomic32_t collisions;
2854418919fSjohnjiang 
286*2d9fd380Sjfb8856606 	if (lcore_id == main_lcore) {
2874418919fSjohnjiang 		cb_count = 0;
2884418919fSjohnjiang 		test_failed = 0;
2894418919fSjohnjiang 		rte_atomic32_set(&collisions, 0);
290*2d9fd380Sjfb8856606 		main_init_workers();
2914418919fSjohnjiang 		timers = rte_malloc(NULL, sizeof(*timers) * NB_STRESS2_TIMERS, 0);
2924418919fSjohnjiang 		if (timers == NULL) {
2934418919fSjohnjiang 			printf("Test Failed\n");
2944418919fSjohnjiang 			printf("- Cannot allocate memory for timers\n" );
2954418919fSjohnjiang 			test_failed = 1;
296*2d9fd380Sjfb8856606 			main_start_workers();
2974418919fSjohnjiang 			goto cleanup;
2984418919fSjohnjiang 		}
2994418919fSjohnjiang 		for (i = 0; i < NB_STRESS2_TIMERS; i++)
3004418919fSjohnjiang 			rte_timer_init(&timers[i]);
301*2d9fd380Sjfb8856606 		main_start_workers();
3024418919fSjohnjiang 	} else {
303*2d9fd380Sjfb8856606 		worker_wait_to_start();
3044418919fSjohnjiang 		if (test_failed)
3054418919fSjohnjiang 			goto cleanup;
3064418919fSjohnjiang 	}
3074418919fSjohnjiang 
308*2d9fd380Sjfb8856606 	/* have all cores schedule all timers on main lcore */
3094418919fSjohnjiang 	for (i = 0; i < NB_STRESS2_TIMERS; i++) {
310*2d9fd380Sjfb8856606 		ret = rte_timer_reset(&timers[i], delay, SINGLE, main_lcore,
3114418919fSjohnjiang 				timer_stress2_cb, NULL);
3124418919fSjohnjiang 		/* there will be collisions when multiple cores simultaneously
3134418919fSjohnjiang 		 * configure the same timers */
3144418919fSjohnjiang 		if (ret != 0)
3154418919fSjohnjiang 			my_collisions++;
3164418919fSjohnjiang 	}
3174418919fSjohnjiang 	if (my_collisions != 0)
3184418919fSjohnjiang 		rte_atomic32_add(&collisions, my_collisions);
3194418919fSjohnjiang 
3204418919fSjohnjiang 	/* wait long enough for timers to expire */
3214418919fSjohnjiang 	rte_delay_ms(100);
3224418919fSjohnjiang 
3234418919fSjohnjiang 	/* all cores rendezvous */
324*2d9fd380Sjfb8856606 	if (lcore_id == main_lcore) {
325*2d9fd380Sjfb8856606 		main_wait_for_workers();
3264418919fSjohnjiang 	} else {
327*2d9fd380Sjfb8856606 		worker_finish();
3284418919fSjohnjiang 	}
3294418919fSjohnjiang 
3304418919fSjohnjiang 	/* now check that we get the right number of callbacks */
331*2d9fd380Sjfb8856606 	if (lcore_id == main_lcore) {
3324418919fSjohnjiang 		my_collisions = rte_atomic32_read(&collisions);
3334418919fSjohnjiang 		if (my_collisions != 0)
3344418919fSjohnjiang 			printf("- %d timer reset collisions (OK)\n", my_collisions);
3354418919fSjohnjiang 		rte_timer_manage();
3364418919fSjohnjiang 		if (cb_count != NB_STRESS2_TIMERS) {
3374418919fSjohnjiang 			printf("Test Failed\n");
3384418919fSjohnjiang 			printf("- Stress test 2, part 1 failed\n");
3394418919fSjohnjiang 			printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS,
3404418919fSjohnjiang 					cb_count);
3414418919fSjohnjiang 			test_failed = 1;
342*2d9fd380Sjfb8856606 			main_start_workers();
3434418919fSjohnjiang 			goto cleanup;
3444418919fSjohnjiang 		}
3454418919fSjohnjiang 		cb_count = 0;
3464418919fSjohnjiang 
3474418919fSjohnjiang 		/* proceed */
348*2d9fd380Sjfb8856606 		main_start_workers();
3494418919fSjohnjiang 	} else {
3504418919fSjohnjiang 		/* proceed */
351*2d9fd380Sjfb8856606 		worker_wait_to_start();
3524418919fSjohnjiang 		if (test_failed)
3534418919fSjohnjiang 			goto cleanup;
3544418919fSjohnjiang 	}
3554418919fSjohnjiang 
3564418919fSjohnjiang 	/* now test again, just stop and restart timers at random after init*/
3574418919fSjohnjiang 	for (i = 0; i < NB_STRESS2_TIMERS; i++)
358*2d9fd380Sjfb8856606 		rte_timer_reset(&timers[i], delay, SINGLE, main_lcore,
3594418919fSjohnjiang 				timer_stress2_cb, NULL);
3604418919fSjohnjiang 
3614418919fSjohnjiang 	/* pick random timer to reset, stopping them first half the time */
3624418919fSjohnjiang 	for (i = 0; i < 100000; i++) {
3634418919fSjohnjiang 		int r = rand() % NB_STRESS2_TIMERS;
3644418919fSjohnjiang 		if (i % 2)
3654418919fSjohnjiang 			rte_timer_stop(&timers[r]);
366*2d9fd380Sjfb8856606 		rte_timer_reset(&timers[r], delay, SINGLE, main_lcore,
3674418919fSjohnjiang 				timer_stress2_cb, NULL);
3684418919fSjohnjiang 	}
3694418919fSjohnjiang 
3704418919fSjohnjiang 	/* wait long enough for timers to expire */
3714418919fSjohnjiang 	rte_delay_ms(100);
3724418919fSjohnjiang 
3734418919fSjohnjiang 	/* now check that we get the right number of callbacks */
374*2d9fd380Sjfb8856606 	if (lcore_id == main_lcore) {
375*2d9fd380Sjfb8856606 		main_wait_for_workers();
3764418919fSjohnjiang 
3774418919fSjohnjiang 		rte_timer_manage();
3784418919fSjohnjiang 		if (cb_count != NB_STRESS2_TIMERS) {
3794418919fSjohnjiang 			printf("Test Failed\n");
3804418919fSjohnjiang 			printf("- Stress test 2, part 2 failed\n");
3814418919fSjohnjiang 			printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS,
3824418919fSjohnjiang 					cb_count);
3834418919fSjohnjiang 			test_failed = 1;
3844418919fSjohnjiang 		} else {
3854418919fSjohnjiang 			printf("Test OK\n");
3864418919fSjohnjiang 		}
3874418919fSjohnjiang 	}
3884418919fSjohnjiang 
3894418919fSjohnjiang cleanup:
390*2d9fd380Sjfb8856606 	if (lcore_id == main_lcore) {
391*2d9fd380Sjfb8856606 		main_wait_for_workers();
3924418919fSjohnjiang 		if (timers != NULL) {
3934418919fSjohnjiang 			rte_free(timers);
3944418919fSjohnjiang 			timers = NULL;
3954418919fSjohnjiang 		}
3964418919fSjohnjiang 	} else {
397*2d9fd380Sjfb8856606 		worker_finish();
3984418919fSjohnjiang 	}
3994418919fSjohnjiang 
4004418919fSjohnjiang 	return 0;
4014418919fSjohnjiang }
4024418919fSjohnjiang 
4034418919fSjohnjiang /* timer callback for basic tests */
4044418919fSjohnjiang static void
timer_basic_cb(struct rte_timer * tim,void * arg)4054418919fSjohnjiang timer_basic_cb(struct rte_timer *tim, void *arg)
4064418919fSjohnjiang {
4074418919fSjohnjiang 	struct mytimerinfo *timinfo = arg;
4084418919fSjohnjiang 	uint64_t hz = rte_get_timer_hz();
4094418919fSjohnjiang 	unsigned lcore_id = rte_lcore_id();
4104418919fSjohnjiang 	uint64_t cur_time = rte_get_timer_cycles();
4114418919fSjohnjiang 
4124418919fSjohnjiang 	if (rte_timer_pending(tim))
4134418919fSjohnjiang 		return;
4144418919fSjohnjiang 
4154418919fSjohnjiang 	timinfo->count ++;
4164418919fSjohnjiang 
4174418919fSjohnjiang 	RTE_LOG(INFO, TESTTIMER,
4184418919fSjohnjiang 		"%"PRIu64": callback id=%u count=%u on core %u\n",
4194418919fSjohnjiang 		cur_time, timinfo->id, timinfo->count, lcore_id);
4204418919fSjohnjiang 
4214418919fSjohnjiang 	/* reload timer 0 on same core */
4224418919fSjohnjiang 	if (timinfo->id == 0 && timinfo->count < 20) {
4234418919fSjohnjiang 		mytimer_reset(timinfo, hz, SINGLE, lcore_id, timer_basic_cb);
4244418919fSjohnjiang 		return;
4254418919fSjohnjiang 	}
4264418919fSjohnjiang 
4274418919fSjohnjiang 	/* reload timer 1 on next core */
4284418919fSjohnjiang 	if (timinfo->id == 1 && timinfo->count < 10) {
4294418919fSjohnjiang 		mytimer_reset(timinfo, hz*2, SINGLE,
4304418919fSjohnjiang 			      rte_get_next_lcore(lcore_id, 0, 1),
4314418919fSjohnjiang 			      timer_basic_cb);
4324418919fSjohnjiang 		return;
4334418919fSjohnjiang 	}
4344418919fSjohnjiang 
4354418919fSjohnjiang 	/* Explicitelly stop timer 0. Once stop() called, we can even
4364418919fSjohnjiang 	 * erase the content of the structure: it is not referenced
4374418919fSjohnjiang 	 * anymore by any code (in case of dynamic structure, it can
4384418919fSjohnjiang 	 * be freed) */
4394418919fSjohnjiang 	if (timinfo->id == 0 && timinfo->count == 20) {
4404418919fSjohnjiang 
4414418919fSjohnjiang 		/* stop_sync() is not needed, because we know that the
4424418919fSjohnjiang 		 * status of timer is only modified by this core */
4434418919fSjohnjiang 		rte_timer_stop(tim);
4444418919fSjohnjiang 		memset(tim, 0xAA, sizeof(struct rte_timer));
4454418919fSjohnjiang 		return;
4464418919fSjohnjiang 	}
4474418919fSjohnjiang 
4484418919fSjohnjiang 	/* stop timer3, and restart a new timer0 (it was removed 5
4494418919fSjohnjiang 	 * seconds ago) for a single shot */
4504418919fSjohnjiang 	if (timinfo->id == 2 && timinfo->count == 25) {
4514418919fSjohnjiang 		rte_timer_stop_sync(&mytiminfo[3].tim);
4524418919fSjohnjiang 
4534418919fSjohnjiang 		/* need to reinit because structure was erased with 0xAA */
4544418919fSjohnjiang 		rte_timer_init(&mytiminfo[0].tim);
4554418919fSjohnjiang 		mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
4564418919fSjohnjiang 			      timer_basic_cb);
4574418919fSjohnjiang 	}
4584418919fSjohnjiang }
4594418919fSjohnjiang 
4604418919fSjohnjiang static int
timer_basic_main_loop(__rte_unused void * arg)461*2d9fd380Sjfb8856606 timer_basic_main_loop(__rte_unused void *arg)
4624418919fSjohnjiang {
4634418919fSjohnjiang 	uint64_t hz = rte_get_timer_hz();
4644418919fSjohnjiang 	unsigned lcore_id = rte_lcore_id();
4654418919fSjohnjiang 	uint64_t cur_time;
4664418919fSjohnjiang 	int64_t diff = 0;
4674418919fSjohnjiang 
4684418919fSjohnjiang 	/* launch all timers on core 0 */
469*2d9fd380Sjfb8856606 	if (lcore_id == rte_get_main_lcore()) {
4704418919fSjohnjiang 		mytimer_reset(&mytiminfo[0], hz/4, SINGLE, lcore_id,
4714418919fSjohnjiang 			      timer_basic_cb);
4724418919fSjohnjiang 		mytimer_reset(&mytiminfo[1], hz/2, SINGLE, lcore_id,
4734418919fSjohnjiang 			      timer_basic_cb);
4744418919fSjohnjiang 		mytimer_reset(&mytiminfo[2], hz/4, PERIODICAL, lcore_id,
4754418919fSjohnjiang 			      timer_basic_cb);
4764418919fSjohnjiang 		mytimer_reset(&mytiminfo[3], hz/4, PERIODICAL,
4774418919fSjohnjiang 			      rte_get_next_lcore(lcore_id, 0, 1),
4784418919fSjohnjiang 			      timer_basic_cb);
4794418919fSjohnjiang 	}
4804418919fSjohnjiang 
4814418919fSjohnjiang 	while (diff >= 0) {
4824418919fSjohnjiang 
4834418919fSjohnjiang 		/* call the timer handler on each core */
4844418919fSjohnjiang 		rte_timer_manage();
4854418919fSjohnjiang 
4864418919fSjohnjiang 		/* simulate the processing of a packet
4874418919fSjohnjiang 		 * (3 us = 6000 cycles at 2 Ghz) */
4884418919fSjohnjiang 		rte_delay_us(3);
4894418919fSjohnjiang 
4904418919fSjohnjiang 		cur_time = rte_get_timer_cycles();
4914418919fSjohnjiang 		diff = end_time - cur_time;
4924418919fSjohnjiang 	}
4934418919fSjohnjiang 	RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
4944418919fSjohnjiang 
4954418919fSjohnjiang 	return 0;
4964418919fSjohnjiang }
4974418919fSjohnjiang 
4984418919fSjohnjiang static int
timer_sanity_check(void)4994418919fSjohnjiang timer_sanity_check(void)
5004418919fSjohnjiang {
5014418919fSjohnjiang #ifdef RTE_LIBEAL_USE_HPET
5024418919fSjohnjiang 	if (eal_timer_source != EAL_TIMER_HPET) {
5034418919fSjohnjiang 		printf("Not using HPET, can't sanity check timer sources\n");
5044418919fSjohnjiang 		return 0;
5054418919fSjohnjiang 	}
5064418919fSjohnjiang 
5074418919fSjohnjiang 	const uint64_t t_hz = rte_get_tsc_hz();
5084418919fSjohnjiang 	const uint64_t h_hz = rte_get_hpet_hz();
5094418919fSjohnjiang 	printf("Hertz values: TSC = %"PRIu64", HPET = %"PRIu64"\n", t_hz, h_hz);
5104418919fSjohnjiang 
5114418919fSjohnjiang 	const uint64_t tsc_start = rte_get_tsc_cycles();
5124418919fSjohnjiang 	const uint64_t hpet_start = rte_get_hpet_cycles();
5134418919fSjohnjiang 	rte_delay_ms(100); /* delay 1/10 second */
5144418919fSjohnjiang 	const uint64_t tsc_end = rte_get_tsc_cycles();
5154418919fSjohnjiang 	const uint64_t hpet_end = rte_get_hpet_cycles();
5164418919fSjohnjiang 	printf("Measured cycles: TSC = %"PRIu64", HPET = %"PRIu64"\n",
5174418919fSjohnjiang 			tsc_end-tsc_start, hpet_end-hpet_start);
5184418919fSjohnjiang 
5194418919fSjohnjiang 	const double tsc_time = (double)(tsc_end - tsc_start)/t_hz;
5204418919fSjohnjiang 	const double hpet_time = (double)(hpet_end - hpet_start)/h_hz;
5214418919fSjohnjiang 	/* get the percentage that the times differ by */
5224418919fSjohnjiang 	const double time_diff = fabs(tsc_time - hpet_time)*100/tsc_time;
5234418919fSjohnjiang 	printf("Measured time: TSC = %.4f, HPET = %.4f\n", tsc_time, hpet_time);
5244418919fSjohnjiang 
5254418919fSjohnjiang 	printf("Elapsed time measured by TSC and HPET differ by %f%%\n",
5264418919fSjohnjiang 			time_diff);
5274418919fSjohnjiang 	if (time_diff > 0.1) {
5284418919fSjohnjiang 		printf("Error times differ by >0.1%%");
5294418919fSjohnjiang 		return -1;
5304418919fSjohnjiang 	}
5314418919fSjohnjiang #endif
5324418919fSjohnjiang 	return 0;
5334418919fSjohnjiang }
5344418919fSjohnjiang 
5354418919fSjohnjiang static int
test_timer(void)5364418919fSjohnjiang test_timer(void)
5374418919fSjohnjiang {
5384418919fSjohnjiang 	unsigned i;
5394418919fSjohnjiang 	uint64_t cur_time;
5404418919fSjohnjiang 	uint64_t hz;
5414418919fSjohnjiang 
5424418919fSjohnjiang 	if (rte_lcore_count() < 2) {
5434418919fSjohnjiang 		printf("Not enough cores for timer_autotest, expecting at least 2\n");
5444418919fSjohnjiang 		return TEST_SKIPPED;
5454418919fSjohnjiang 	}
5464418919fSjohnjiang 
5474418919fSjohnjiang 	/* sanity check our timer sources and timer config values */
5484418919fSjohnjiang 	if (timer_sanity_check() < 0) {
5494418919fSjohnjiang 		printf("Timer sanity checks failed\n");
5504418919fSjohnjiang 		return TEST_FAILED;
5514418919fSjohnjiang 	}
5524418919fSjohnjiang 
5534418919fSjohnjiang 	/* init timer */
5544418919fSjohnjiang 	for (i=0; i<NB_TIMER; i++) {
5554418919fSjohnjiang 		memset(&mytiminfo[i], 0, sizeof(struct mytimerinfo));
5564418919fSjohnjiang 		mytiminfo[i].id = i;
5574418919fSjohnjiang 		rte_timer_init(&mytiminfo[i].tim);
5584418919fSjohnjiang 	}
5594418919fSjohnjiang 
5604418919fSjohnjiang 	/* calculate the "end of test" time */
5614418919fSjohnjiang 	cur_time = rte_get_timer_cycles();
5624418919fSjohnjiang 	hz = rte_get_timer_hz();
5634418919fSjohnjiang 	end_time = cur_time + (hz * TEST_DURATION_S);
5644418919fSjohnjiang 
5654418919fSjohnjiang 	/* start other cores */
5664418919fSjohnjiang 	printf("Start timer stress tests\n");
567*2d9fd380Sjfb8856606 	rte_eal_mp_remote_launch(timer_stress_main_loop, NULL, CALL_MAIN);
5684418919fSjohnjiang 	rte_eal_mp_wait_lcore();
5694418919fSjohnjiang 
5704418919fSjohnjiang 	/* stop timer 0 used for stress test */
5714418919fSjohnjiang 	rte_timer_stop_sync(&mytiminfo[0].tim);
5724418919fSjohnjiang 
5734418919fSjohnjiang 	/* run a second, slightly different set of stress tests */
5744418919fSjohnjiang 	printf("\nStart timer stress tests 2\n");
5754418919fSjohnjiang 	test_failed = 0;
576*2d9fd380Sjfb8856606 	rte_eal_mp_remote_launch(timer_stress2_main_loop, NULL, CALL_MAIN);
5774418919fSjohnjiang 	rte_eal_mp_wait_lcore();
5784418919fSjohnjiang 	if (test_failed)
5794418919fSjohnjiang 		return TEST_FAILED;
5804418919fSjohnjiang 
5814418919fSjohnjiang 	/* calculate the "end of test" time */
5824418919fSjohnjiang 	cur_time = rte_get_timer_cycles();
5834418919fSjohnjiang 	hz = rte_get_timer_hz();
5844418919fSjohnjiang 	end_time = cur_time + (hz * TEST_DURATION_S);
5854418919fSjohnjiang 
5864418919fSjohnjiang 	/* start other cores */
5874418919fSjohnjiang 	printf("\nStart timer basic tests\n");
588*2d9fd380Sjfb8856606 	rte_eal_mp_remote_launch(timer_basic_main_loop, NULL, CALL_MAIN);
5894418919fSjohnjiang 	rte_eal_mp_wait_lcore();
5904418919fSjohnjiang 
5914418919fSjohnjiang 	/* stop all timers */
5924418919fSjohnjiang 	for (i=0; i<NB_TIMER; i++) {
5934418919fSjohnjiang 		rte_timer_stop_sync(&mytiminfo[i].tim);
5944418919fSjohnjiang 	}
5954418919fSjohnjiang 
5964418919fSjohnjiang 	rte_timer_dump_stats(stdout);
5974418919fSjohnjiang 
5984418919fSjohnjiang 	return TEST_SUCCESS;
5994418919fSjohnjiang }
6004418919fSjohnjiang 
6014418919fSjohnjiang REGISTER_TEST_COMMAND(timer_autotest, test_timer);
602