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