xref: /dpdk/doc/guides/sample_app_ug/timer.rst (revision fea1d908d39989a27890b29b5c0ec94c85c8257b)
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