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