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