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