15630257fSFerruh Yigit.. SPDX-License-Identifier: BSD-3-Clause 25630257fSFerruh Yigit Copyright(c) 2010-2014 Intel Corporation. 3d0dff9baSBernard Iremonger 4d0dff9baSBernard IremongerTimer Sample Application 5d0dff9baSBernard Iremonger======================== 6d0dff9baSBernard Iremonger 7e0c7c473SSiobhan ButlerThe Timer sample application is a simple application that demonstrates the use of a timer in a DPDK application. 8d0dff9baSBernard IremongerThis application prints some messages from different lcores regularly, demonstrating the use of timers. 9d0dff9baSBernard Iremonger 10d0dff9baSBernard IremongerCompiling the Application 11d0dff9baSBernard Iremonger------------------------- 12d0dff9baSBernard Iremonger 137cacb056SHerakliusz LipiecTo compile the sample application see :doc:`compiling`. 14d0dff9baSBernard Iremonger 157cacb056SHerakliusz LipiecThe application is located in the ``timer`` sub-directory. 16d0dff9baSBernard Iremonger 17d0dff9baSBernard IremongerRunning the Application 18d0dff9baSBernard Iremonger----------------------- 19d0dff9baSBernard Iremonger 20218c4e68SBruce RichardsonTo run the example in linux environment: 21d0dff9baSBernard Iremonger 22d0dff9baSBernard Iremonger.. code-block:: console 23d0dff9baSBernard Iremonger 2435b09d76SKeith Wiles $ ./build/timer -l 0-3 -n 4 25d0dff9baSBernard Iremonger 26e0c7c473SSiobhan ButlerRefer to the *DPDK Getting Started Guide* for general information on running applications and 27d0dff9baSBernard Iremongerthe Environment Abstraction Layer (EAL) options. 28d0dff9baSBernard Iremonger 29d0dff9baSBernard IremongerExplanation 30d0dff9baSBernard Iremonger----------- 31d0dff9baSBernard Iremonger 32d0dff9baSBernard IremongerThe following sections provide some explanation of the code. 33d0dff9baSBernard Iremonger 34d0dff9baSBernard IremongerInitialization and Main Loop 35d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36d0dff9baSBernard Iremonger 37d0dff9baSBernard IremongerIn addition to EAL initialization, the timer subsystem must be initialized, by calling the rte_timer_subsystem_init() function. 38d0dff9baSBernard Iremonger 39d0dff9baSBernard Iremonger.. code-block:: c 40d0dff9baSBernard Iremonger 41d0dff9baSBernard Iremonger /* init EAL */ 42d0dff9baSBernard Iremonger 43d0dff9baSBernard Iremonger ret = rte_eal_init(argc, argv); 44d0dff9baSBernard Iremonger if (ret < 0) 45d0dff9baSBernard Iremonger rte_panic("Cannot init EAL\n"); 46d0dff9baSBernard Iremonger 47d0dff9baSBernard Iremonger /* init RTE timer library */ 48d0dff9baSBernard Iremonger 49d0dff9baSBernard Iremonger rte_timer_subsystem_init(); 50d0dff9baSBernard Iremonger 51*cb056611SStephen HemmingerAfter timer creation (see the next paragraph), the main loop is 52*cb056611SStephen Hemmingerexecuted on each worker lcore using the well-known 53*cb056611SStephen Hemmingerrte_eal_remote_launch() and also on the main. 54d0dff9baSBernard Iremonger 55d0dff9baSBernard Iremonger.. code-block:: c 56d0dff9baSBernard Iremonger 57*cb056611SStephen Hemminger /* call lcore_mainloop() on every worker lcore */ 58*cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(lcore_id) { 59d0dff9baSBernard Iremonger rte_eal_remote_launch(lcore_mainloop, NULL, lcore_id); 60d0dff9baSBernard Iremonger } 61d0dff9baSBernard Iremonger 62*cb056611SStephen Hemminger /* call it on main lcore too */ 63d0dff9baSBernard Iremonger 64d0dff9baSBernard Iremonger (void) lcore_mainloop(NULL); 65d0dff9baSBernard Iremonger 66d0dff9baSBernard IremongerThe main loop is very simple in this example: 67d0dff9baSBernard Iremonger 68d0dff9baSBernard Iremonger.. code-block:: c 69d0dff9baSBernard Iremonger 70d0dff9baSBernard Iremonger while (1) { 71d0dff9baSBernard Iremonger /* 72d0dff9baSBernard Iremonger * Call the timer handler on each core: as we don't 73d0dff9baSBernard Iremonger * need a very precise timer, so only call 74fea1d908SJohn McNamara * rte_timer_manage() every ~10ms (at 2 GHz). In a real 75d0dff9baSBernard Iremonger * application, this will enhance performances as 76d0dff9baSBernard Iremonger * reading the HPET timer is not efficient. 77d0dff9baSBernard Iremonger */ 78d0dff9baSBernard Iremonger 79d0dff9baSBernard Iremonger cur_tsc = rte_rdtsc(); 80d0dff9baSBernard Iremonger 81d0dff9baSBernard Iremonger diff_tsc = cur_tsc - prev_tsc; 82d0dff9baSBernard Iremonger 83d0dff9baSBernard Iremonger if (diff_tsc > TIMER_RESOLUTION_CYCLES) { 84d0dff9baSBernard Iremonger rte_timer_manage(); 85d0dff9baSBernard Iremonger prev_tsc = cur_tsc; 86d0dff9baSBernard Iremonger } 87d0dff9baSBernard Iremonger } 88d0dff9baSBernard Iremonger 89d0dff9baSBernard IremongerAs explained in the comment, it is better to use the TSC register (as it is a per-lcore register) to check if the 90d0dff9baSBernard Iremongerrte_timer_manage() function must be called or not. 91d0dff9baSBernard IremongerIn this example, the resolution of the timer is 10 milliseconds. 92d0dff9baSBernard Iremonger 93d0dff9baSBernard IremongerManaging Timers 94d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~ 95d0dff9baSBernard Iremonger 96d0dff9baSBernard IremongerIn the main() function, the two timers are initialized. 97d0dff9baSBernard IremongerThis call to rte_timer_init() is necessary before doing any other operation on the timer structure. 98d0dff9baSBernard Iremonger 99d0dff9baSBernard Iremonger.. code-block:: c 100d0dff9baSBernard Iremonger 101d0dff9baSBernard Iremonger /* init timer structures */ 102d0dff9baSBernard Iremonger 103d0dff9baSBernard Iremonger rte_timer_init(&timer0); 104d0dff9baSBernard Iremonger rte_timer_init(&timer1); 105d0dff9baSBernard Iremonger 106d0dff9baSBernard IremongerThen, the two timers are configured: 107d0dff9baSBernard Iremonger 108*cb056611SStephen Hemminger* The first timer (timer0) is loaded on the main lcore and expires every second. 109d0dff9baSBernard Iremonger Since the PERIODICAL flag is provided, the timer is reloaded automatically by the timer subsystem. 110d0dff9baSBernard Iremonger The callback function is timer0_cb(). 111d0dff9baSBernard Iremonger 112d0dff9baSBernard Iremonger* The second timer (timer1) is loaded on the next available lcore every 333 ms. 113d0dff9baSBernard Iremonger The SINGLE flag means that the timer expires only once and must be reloaded manually if required. 114d0dff9baSBernard Iremonger The callback function is timer1_cb(). 115d0dff9baSBernard Iremonger 116d0dff9baSBernard Iremonger.. code-block:: c 117d0dff9baSBernard Iremonger 118*cb056611SStephen Hemminger /* load timer0, every second, on main lcore, reloaded automatically */ 119d0dff9baSBernard Iremonger 120d0dff9baSBernard Iremonger hz = rte_get_hpet_hz(); 121d0dff9baSBernard Iremonger 122d0dff9baSBernard Iremonger lcore_id = rte_lcore_id(); 123d0dff9baSBernard Iremonger 124d0dff9baSBernard Iremonger rte_timer_reset(&timer0, hz, PERIODICAL, lcore_id, timer0_cb, NULL); 125d0dff9baSBernard Iremonger 126d0dff9baSBernard Iremonger /* load timer1, every second/3, on next lcore, reloaded manually */ 127d0dff9baSBernard Iremonger 128d0dff9baSBernard Iremonger lcore_id = rte_get_next_lcore(lcore_id, 0, 1); 129d0dff9baSBernard Iremonger 130d0dff9baSBernard Iremonger rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL); 131d0dff9baSBernard Iremonger 132d0dff9baSBernard IremongerThe callback for the first timer (timer0) only displays a message until a global counter reaches 20 (after 20 seconds). 133d0dff9baSBernard IremongerIn this case, the timer is stopped using the rte_timer_stop() function. 134d0dff9baSBernard Iremonger 135d0dff9baSBernard Iremonger.. code-block:: c 136d0dff9baSBernard Iremonger 137d0dff9baSBernard Iremonger /* timer0 callback */ 138d0dff9baSBernard Iremonger 139d0dff9baSBernard Iremonger static void 140f2fc83b4SThomas Monjalon timer0_cb(__rte_unused struct rte_timer *tim, __rte_unused void *arg) 141d0dff9baSBernard Iremonger { 142d0dff9baSBernard Iremonger static unsigned counter = 0; 143d0dff9baSBernard Iremonger 144d0dff9baSBernard Iremonger unsigned lcore_id = rte_lcore_id(); 145d0dff9baSBernard Iremonger 146d0dff9baSBernard Iremonger printf("%s() on lcore %u\n", FUNCTION , lcore_id); 147d0dff9baSBernard Iremonger 148d0dff9baSBernard Iremonger /* this timer is automatically reloaded until we decide to stop it, when counter reaches 20. */ 149d0dff9baSBernard Iremonger 150d0dff9baSBernard Iremonger if ((counter ++) == 20) 151d0dff9baSBernard Iremonger rte_timer_stop(tim); 152d0dff9baSBernard Iremonger } 153d0dff9baSBernard Iremonger 154d0dff9baSBernard IremongerThe callback for the second timer (timer1) displays a message and reloads the timer on the next lcore, using the 155d0dff9baSBernard Iremongerrte_timer_reset() function: 156d0dff9baSBernard Iremonger 157d0dff9baSBernard Iremonger.. code-block:: c 158d0dff9baSBernard Iremonger 159d0dff9baSBernard Iremonger /* timer1 callback */ 160d0dff9baSBernard Iremonger 161d0dff9baSBernard Iremonger static void 162f2fc83b4SThomas Monjalon timer1_cb(__rte_unused struct rte_timer *tim, __rte_unused void *arg) 163d0dff9baSBernard Iremonger { 164d0dff9baSBernard Iremonger unsigned lcore_id = rte_lcore_id(); 165d0dff9baSBernard Iremonger uint64_t hz; 166d0dff9baSBernard Iremonger 167d0dff9baSBernard Iremonger printf("%s() on lcore %u\\n", FUNCTION , lcore_id); 168d0dff9baSBernard Iremonger 169d0dff9baSBernard Iremonger /* reload it on another lcore */ 170d0dff9baSBernard Iremonger 171d0dff9baSBernard Iremonger hz = rte_get_hpet_hz(); 172d0dff9baSBernard Iremonger 173d0dff9baSBernard Iremonger lcore_id = rte_get_next_lcore(lcore_id, 0, 1); 174d0dff9baSBernard Iremonger 175d0dff9baSBernard Iremonger rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL); 176d0dff9baSBernard Iremonger } 177