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