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 cd ${RTE_SDK}/examples/timer 45 46#. Set the target (a default target is used if not specified). For example: 47 48 .. code-block:: console 49 50 export RTE_TARGET=x86_64-native-linuxapp-gcc 51 52 See the *DPDK Getting Started Guide* for possible *RTE_TARGET* values. 53 54#. Build the application: 55 56 .. code-block:: console 57 58 make 59 60Running the Application 61----------------------- 62 63To run the example in linuxapp environment: 64 65.. code-block:: console 66 67 $ ./build/timer -c f -n 4 68 69Refer to the *DPDK Getting Started Guide* for general information on running applications and 70the Environment Abstraction Layer (EAL) options. 71 72Explanation 73----------- 74 75The following sections provide some explanation of the code. 76 77Initialization and Main Loop 78~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 79 80In addition to EAL initialization, the timer subsystem must be initialized, by calling the rte_timer_subsystem_init() function. 81 82.. code-block:: c 83 84 /* init EAL */ 85 86 ret = rte_eal_init(argc, argv); 87 if (ret < 0) 88 rte_panic("Cannot init EAL\n"); 89 90 /* init RTE timer library */ 91 92 rte_timer_subsystem_init(); 93 94After timer creation (see the next paragraph), 95the main loop is executed on each slave lcore using the well-known rte_eal_remote_launch() and also on the master. 96 97.. code-block:: c 98 99 /* call lcore_mainloop() on every slave lcore */ 100 101 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 102 rte_eal_remote_launch(lcore_mainloop, NULL, lcore_id); 103 } 104 105 /* call it on master lcore too */ 106 107 (void) lcore_mainloop(NULL); 108 109The main loop is very simple in this example: 110 111.. code-block:: c 112 113 while (1) { 114 /* 115 * Call the timer handler on each core: as we don't 116 * need a very precise timer, so only call 117 * rte_timer_manage() every ~10ms (at 2 GHz). In a real 118 * application, this will enhance performances as 119 * reading the HPET timer is not efficient. 120 */ 121 122 cur_tsc = rte_rdtsc(); 123 124 diff_tsc = cur_tsc - prev_tsc; 125 126 if (diff_tsc > TIMER_RESOLUTION_CYCLES) { 127 rte_timer_manage(); 128 prev_tsc = cur_tsc; 129 } 130 } 131 132As explained in the comment, it is better to use the TSC register (as it is a per-lcore register) to check if the 133rte_timer_manage() function must be called or not. 134In this example, the resolution of the timer is 10 milliseconds. 135 136Managing Timers 137~~~~~~~~~~~~~~~ 138 139In the main() function, the two timers are initialized. 140This call to rte_timer_init() is necessary before doing any other operation on the timer structure. 141 142.. code-block:: c 143 144 /* init timer structures */ 145 146 rte_timer_init(&timer0); 147 rte_timer_init(&timer1); 148 149Then, the two timers are configured: 150 151* The first timer (timer0) is loaded on the master lcore and expires every second. 152 Since the PERIODICAL flag is provided, the timer is reloaded automatically by the timer subsystem. 153 The callback function is timer0_cb(). 154 155* The second timer (timer1) is loaded on the next available lcore every 333 ms. 156 The SINGLE flag means that the timer expires only once and must be reloaded manually if required. 157 The callback function is timer1_cb(). 158 159.. code-block:: c 160 161 /* load timer0, every second, on master lcore, reloaded automatically */ 162 163 hz = rte_get_hpet_hz(); 164 165 lcore_id = rte_lcore_id(); 166 167 rte_timer_reset(&timer0, hz, PERIODICAL, lcore_id, timer0_cb, NULL); 168 169 /* load timer1, every second/3, on next lcore, reloaded manually */ 170 171 lcore_id = rte_get_next_lcore(lcore_id, 0, 1); 172 173 rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL); 174 175The callback for the first timer (timer0) only displays a message until a global counter reaches 20 (after 20 seconds). 176In this case, the timer is stopped using the rte_timer_stop() function. 177 178.. code-block:: c 179 180 /* timer0 callback */ 181 182 static void 183 timer0_cb( attribute ((unused)) struct rte_timer *tim, __attribute ((unused)) void *arg) 184 { 185 static unsigned counter = 0; 186 187 unsigned lcore_id = rte_lcore_id(); 188 189 printf("%s() on lcore %u\n", FUNCTION , lcore_id); 190 191 /* this timer is automatically reloaded until we decide to stop it, when counter reaches 20. */ 192 193 if ((counter ++) == 20) 194 rte_timer_stop(tim); 195 } 196 197The callback for the second timer (timer1) displays a message and reloads the timer on the next lcore, using the 198rte_timer_reset() function: 199 200.. code-block:: c 201 202 /* timer1 callback */ 203 204 static void 205 timer1_cb( attribute ((unused)) struct rte_timer *tim, _attribute ((unused)) void *arg) 206 { 207 unsigned lcore_id = rte_lcore_id(); 208 uint64_t hz; 209 210 printf("%s() on lcore %u\\n", FUNCTION , lcore_id); 211 212 /* reload it on another lcore */ 213 214 hz = rte_get_hpet_hz(); 215 216 lcore_id = rte_get_next_lcore(lcore_id, 0, 1); 217 218 rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL); 219 } 220