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