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