1d0dff9baSBernard Iremonger.. BSD LICENSE 2d0dff9baSBernard Iremonger Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 3d0dff9baSBernard Iremonger All rights reserved. 4d0dff9baSBernard Iremonger 5d0dff9baSBernard Iremonger Redistribution and use in source and binary forms, with or without 6d0dff9baSBernard Iremonger modification, are permitted provided that the following conditions 7d0dff9baSBernard Iremonger are met: 8d0dff9baSBernard Iremonger 9d0dff9baSBernard Iremonger * Redistributions of source code must retain the above copyright 10d0dff9baSBernard Iremonger notice, this list of conditions and the following disclaimer. 11d0dff9baSBernard Iremonger * Redistributions in binary form must reproduce the above copyright 12d0dff9baSBernard Iremonger notice, this list of conditions and the following disclaimer in 13d0dff9baSBernard Iremonger the documentation and/or other materials provided with the 14d0dff9baSBernard Iremonger distribution. 15d0dff9baSBernard Iremonger * Neither the name of Intel Corporation nor the names of its 16d0dff9baSBernard Iremonger contributors may be used to endorse or promote products derived 17d0dff9baSBernard Iremonger from this software without specific prior written permission. 18d0dff9baSBernard Iremonger 19d0dff9baSBernard Iremonger THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20d0dff9baSBernard Iremonger "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21d0dff9baSBernard Iremonger LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22d0dff9baSBernard Iremonger A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23d0dff9baSBernard Iremonger OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24d0dff9baSBernard Iremonger SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25d0dff9baSBernard Iremonger LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26d0dff9baSBernard Iremonger DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27d0dff9baSBernard Iremonger THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28d0dff9baSBernard Iremonger (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29d0dff9baSBernard Iremonger OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30d0dff9baSBernard Iremonger 31d0dff9baSBernard IremongerTimer Sample Application 32d0dff9baSBernard Iremonger======================== 33d0dff9baSBernard Iremonger 34e0c7c473SSiobhan ButlerThe Timer sample application is a simple application that demonstrates the use of a timer in a DPDK application. 35d0dff9baSBernard IremongerThis application prints some messages from different lcores regularly, demonstrating the use of timers. 36d0dff9baSBernard Iremonger 37d0dff9baSBernard IremongerCompiling the Application 38d0dff9baSBernard Iremonger------------------------- 39d0dff9baSBernard Iremonger 40d0dff9baSBernard Iremonger#. Go to the example directory: 41d0dff9baSBernard Iremonger 42d0dff9baSBernard Iremonger .. code-block:: console 43d0dff9baSBernard Iremonger 44d0dff9baSBernard Iremonger export RTE_SDK=/path/to/rte_sdk cd ${RTE_SDK}/examples/timer 45d0dff9baSBernard Iremonger 46d0dff9baSBernard Iremonger#. Set the target (a default target is used if not specified). For example: 47d0dff9baSBernard Iremonger 48d0dff9baSBernard Iremonger .. code-block:: console 49d0dff9baSBernard Iremonger 50d0dff9baSBernard Iremonger export RTE_TARGET=x86_64-native-linuxapp-gcc 51d0dff9baSBernard Iremonger 52e0c7c473SSiobhan Butler See the *DPDK Getting Started Guide* for possible *RTE_TARGET* values. 53d0dff9baSBernard Iremonger 54d0dff9baSBernard Iremonger#. Build the application: 55d0dff9baSBernard Iremonger 56d0dff9baSBernard Iremonger .. code-block:: console 57d0dff9baSBernard Iremonger 58d0dff9baSBernard Iremonger make 59d0dff9baSBernard Iremonger 60d0dff9baSBernard IremongerRunning the Application 61d0dff9baSBernard Iremonger----------------------- 62d0dff9baSBernard Iremonger 63d0dff9baSBernard IremongerTo run the example in linuxapp environment: 64d0dff9baSBernard Iremonger 65d0dff9baSBernard Iremonger.. code-block:: console 66d0dff9baSBernard Iremonger 67d0dff9baSBernard Iremonger $ ./build/timer -c f -n 4 68d0dff9baSBernard Iremonger 69e0c7c473SSiobhan ButlerRefer to the *DPDK Getting Started Guide* for general information on running applications and 70d0dff9baSBernard Iremongerthe Environment Abstraction Layer (EAL) options. 71d0dff9baSBernard Iremonger 72d0dff9baSBernard IremongerExplanation 73d0dff9baSBernard Iremonger----------- 74d0dff9baSBernard Iremonger 75d0dff9baSBernard IremongerThe following sections provide some explanation of the code. 76d0dff9baSBernard Iremonger 77d0dff9baSBernard IremongerInitialization and Main Loop 78d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 79d0dff9baSBernard Iremonger 80d0dff9baSBernard IremongerIn addition to EAL initialization, the timer subsystem must be initialized, by calling the rte_timer_subsystem_init() function. 81d0dff9baSBernard Iremonger 82d0dff9baSBernard Iremonger.. code-block:: c 83d0dff9baSBernard Iremonger 84d0dff9baSBernard Iremonger /* init EAL */ 85d0dff9baSBernard Iremonger 86d0dff9baSBernard Iremonger ret = rte_eal_init(argc, argv); 87d0dff9baSBernard Iremonger if (ret < 0) 88d0dff9baSBernard Iremonger rte_panic("Cannot init EAL\n"); 89d0dff9baSBernard Iremonger 90d0dff9baSBernard Iremonger /* init RTE timer library */ 91d0dff9baSBernard Iremonger 92d0dff9baSBernard Iremonger rte_timer_subsystem_init(); 93d0dff9baSBernard Iremonger 94d0dff9baSBernard IremongerAfter timer creation (see the next paragraph), 95d0dff9baSBernard Iremongerthe main loop is executed on each slave lcore using the well-known rte_eal_remote_launch() and also on the master. 96d0dff9baSBernard Iremonger 97d0dff9baSBernard Iremonger.. code-block:: c 98d0dff9baSBernard Iremonger 99d0dff9baSBernard Iremonger /* call lcore_mainloop() on every slave lcore */ 100d0dff9baSBernard Iremonger 101d0dff9baSBernard Iremonger RTE_LCORE_FOREACH_SLAVE(lcore_id) { 102d0dff9baSBernard Iremonger rte_eal_remote_launch(lcore_mainloop, NULL, lcore_id); 103d0dff9baSBernard Iremonger } 104d0dff9baSBernard Iremonger 105d0dff9baSBernard Iremonger /* call it on master lcore too */ 106d0dff9baSBernard Iremonger 107d0dff9baSBernard Iremonger (void) lcore_mainloop(NULL); 108d0dff9baSBernard Iremonger 109d0dff9baSBernard IremongerThe main loop is very simple in this example: 110d0dff9baSBernard Iremonger 111d0dff9baSBernard Iremonger.. code-block:: c 112d0dff9baSBernard Iremonger 113d0dff9baSBernard Iremonger while (1) { 114d0dff9baSBernard Iremonger /* 115d0dff9baSBernard Iremonger * Call the timer handler on each core: as we don't 116d0dff9baSBernard Iremonger * need a very precise timer, so only call 117*fea1d908SJohn McNamara * rte_timer_manage() every ~10ms (at 2 GHz). In a real 118d0dff9baSBernard Iremonger * application, this will enhance performances as 119d0dff9baSBernard Iremonger * reading the HPET timer is not efficient. 120d0dff9baSBernard Iremonger */ 121d0dff9baSBernard Iremonger 122d0dff9baSBernard Iremonger cur_tsc = rte_rdtsc(); 123d0dff9baSBernard Iremonger 124d0dff9baSBernard Iremonger diff_tsc = cur_tsc - prev_tsc; 125d0dff9baSBernard Iremonger 126d0dff9baSBernard Iremonger if (diff_tsc > TIMER_RESOLUTION_CYCLES) { 127d0dff9baSBernard Iremonger rte_timer_manage(); 128d0dff9baSBernard Iremonger prev_tsc = cur_tsc; 129d0dff9baSBernard Iremonger } 130d0dff9baSBernard Iremonger } 131d0dff9baSBernard Iremonger 132d0dff9baSBernard IremongerAs explained in the comment, it is better to use the TSC register (as it is a per-lcore register) to check if the 133d0dff9baSBernard Iremongerrte_timer_manage() function must be called or not. 134d0dff9baSBernard IremongerIn this example, the resolution of the timer is 10 milliseconds. 135d0dff9baSBernard Iremonger 136d0dff9baSBernard IremongerManaging Timers 137d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~ 138d0dff9baSBernard Iremonger 139d0dff9baSBernard IremongerIn the main() function, the two timers are initialized. 140d0dff9baSBernard IremongerThis call to rte_timer_init() is necessary before doing any other operation on the timer structure. 141d0dff9baSBernard Iremonger 142d0dff9baSBernard Iremonger.. code-block:: c 143d0dff9baSBernard Iremonger 144d0dff9baSBernard Iremonger /* init timer structures */ 145d0dff9baSBernard Iremonger 146d0dff9baSBernard Iremonger rte_timer_init(&timer0); 147d0dff9baSBernard Iremonger rte_timer_init(&timer1); 148d0dff9baSBernard Iremonger 149d0dff9baSBernard IremongerThen, the two timers are configured: 150d0dff9baSBernard Iremonger 151d0dff9baSBernard Iremonger* The first timer (timer0) is loaded on the master lcore and expires every second. 152d0dff9baSBernard Iremonger Since the PERIODICAL flag is provided, the timer is reloaded automatically by the timer subsystem. 153d0dff9baSBernard Iremonger The callback function is timer0_cb(). 154d0dff9baSBernard Iremonger 155d0dff9baSBernard Iremonger* The second timer (timer1) is loaded on the next available lcore every 333 ms. 156d0dff9baSBernard Iremonger The SINGLE flag means that the timer expires only once and must be reloaded manually if required. 157d0dff9baSBernard Iremonger The callback function is timer1_cb(). 158d0dff9baSBernard Iremonger 159d0dff9baSBernard Iremonger.. code-block:: c 160d0dff9baSBernard Iremonger 161d0dff9baSBernard Iremonger /* load timer0, every second, on master lcore, reloaded automatically */ 162d0dff9baSBernard Iremonger 163d0dff9baSBernard Iremonger hz = rte_get_hpet_hz(); 164d0dff9baSBernard Iremonger 165d0dff9baSBernard Iremonger lcore_id = rte_lcore_id(); 166d0dff9baSBernard Iremonger 167d0dff9baSBernard Iremonger rte_timer_reset(&timer0, hz, PERIODICAL, lcore_id, timer0_cb, NULL); 168d0dff9baSBernard Iremonger 169d0dff9baSBernard Iremonger /* load timer1, every second/3, on next lcore, reloaded manually */ 170d0dff9baSBernard Iremonger 171d0dff9baSBernard Iremonger lcore_id = rte_get_next_lcore(lcore_id, 0, 1); 172d0dff9baSBernard Iremonger 173d0dff9baSBernard Iremonger rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL); 174d0dff9baSBernard Iremonger 175d0dff9baSBernard IremongerThe callback for the first timer (timer0) only displays a message until a global counter reaches 20 (after 20 seconds). 176d0dff9baSBernard IremongerIn this case, the timer is stopped using the rte_timer_stop() function. 177d0dff9baSBernard Iremonger 178d0dff9baSBernard Iremonger.. code-block:: c 179d0dff9baSBernard Iremonger 180d0dff9baSBernard Iremonger /* timer0 callback */ 181d0dff9baSBernard Iremonger 182d0dff9baSBernard Iremonger static void 183d0dff9baSBernard Iremonger timer0_cb( attribute ((unused)) struct rte_timer *tim, __attribute ((unused)) void *arg) 184d0dff9baSBernard Iremonger { 185d0dff9baSBernard Iremonger static unsigned counter = 0; 186d0dff9baSBernard Iremonger 187d0dff9baSBernard Iremonger unsigned lcore_id = rte_lcore_id(); 188d0dff9baSBernard Iremonger 189d0dff9baSBernard Iremonger printf("%s() on lcore %u\n", FUNCTION , lcore_id); 190d0dff9baSBernard Iremonger 191d0dff9baSBernard Iremonger /* this timer is automatically reloaded until we decide to stop it, when counter reaches 20. */ 192d0dff9baSBernard Iremonger 193d0dff9baSBernard Iremonger if ((counter ++) == 20) 194d0dff9baSBernard Iremonger rte_timer_stop(tim); 195d0dff9baSBernard Iremonger } 196d0dff9baSBernard Iremonger 197d0dff9baSBernard IremongerThe callback for the second timer (timer1) displays a message and reloads the timer on the next lcore, using the 198d0dff9baSBernard Iremongerrte_timer_reset() function: 199d0dff9baSBernard Iremonger 200d0dff9baSBernard Iremonger.. code-block:: c 201d0dff9baSBernard Iremonger 202d0dff9baSBernard Iremonger /* timer1 callback */ 203d0dff9baSBernard Iremonger 204d0dff9baSBernard Iremonger static void 205d0dff9baSBernard Iremonger timer1_cb( attribute ((unused)) struct rte_timer *tim, _attribute ((unused)) void *arg) 206d0dff9baSBernard Iremonger { 207d0dff9baSBernard Iremonger unsigned lcore_id = rte_lcore_id(); 208d0dff9baSBernard Iremonger uint64_t hz; 209d0dff9baSBernard Iremonger 210d0dff9baSBernard Iremonger printf("%s() on lcore %u\\n", FUNCTION , lcore_id); 211d0dff9baSBernard Iremonger 212d0dff9baSBernard Iremonger /* reload it on another lcore */ 213d0dff9baSBernard Iremonger 214d0dff9baSBernard Iremonger hz = rte_get_hpet_hz(); 215d0dff9baSBernard Iremonger 216d0dff9baSBernard Iremonger lcore_id = rte_get_next_lcore(lcore_id, 0, 1); 217d0dff9baSBernard Iremonger 218d0dff9baSBernard Iremonger rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL); 219d0dff9baSBernard Iremonger } 220