first public release
[dpdk.git] / app / test / test_timer.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  *  version: DPDK.L.1.2.3-3
34  */
35
36 /*
37  * Timer
38  * =====
39  *
40  * #. Stress tests.
41  *
42  *    The objective of the timer stress tests is to check that there are no
43  *    race conditions in list and status management. This test launches,
44  *    resets and stops the timer very often on many cores at the same
45  *    time.
46  *
47  *    - Only one timer is used for this test.
48  *    - On each core, the rte_timer_manage() function is called from the main
49  *      loop every 3 microseconds.
50  *    - In the main loop, the timer may be reset (randomly, with a
51  *      probability of 0.5 %) 100 microseconds later on a random core, or
52  *      stopped (with a probability of 0.5 % also).
53  *    - In callback, the timer is can be reset (randomly, with a
54  *      probability of 0.5 %) 100 microseconds later on the same core or
55  *      on another core (same probability), or stopped (same
56  *      probability).
57  *
58  *
59  * #. Basic test.
60  *
61  *    This test performs basic functional checks of the timers. The test
62  *    uses four different timers that are loaded and stopped under
63  *    specific conditions in specific contexts.
64  *
65  *    - Four timers are used for this test.
66  *    - On each core, the rte_timer_manage() function is called from main loop
67  *      every 3 microseconds.
68  *
69  *    The autotest python script checks that the behavior is correct:
70  *
71  *    - timer0
72  *
73  *      - At initialization, timer0 is loaded by the master core, on master core
74  *        in "single" mode (time = 1 second).
75  *      - In the first 19 callbacks, timer0 is reloaded on the same core,
76  *        then, it is explicitly stopped at the 20th call.
77  *      - At t=25s, timer0 is reloaded once by timer2.
78  *
79  *    - timer1
80  *
81  *      - At initialization, timer1 is loaded by the master core, on the
82  *        master core in "single" mode (time = 2 seconds).
83  *      - In the first 9 callbacks, timer1 is reloaded on another
84  *        core. After the 10th callback, timer1 is not reloaded anymore.
85  *
86  *    - timer2
87  *
88  *      - At initialization, timer2 is loaded by the master core, on the
89  *        master core in "periodical" mode (time = 1 second).
90  *      - In the callback, when t=25s, it stops timer3 and reloads timer0
91  *        on the current core.
92  *
93  *    - timer3
94  *
95  *      - At initialization, timer3 is loaded by the master core, on
96  *        another core in "periodical" mode (time = 1 second).
97  *      - It is stopped at t=25s by timer2.
98  */
99
100 #include <stdio.h>
101 #include <stdarg.h>
102 #include <string.h>
103 #include <stdlib.h>
104 #include <stdint.h>
105 #include <inttypes.h>
106 #include <sys/queue.h>
107
108 #include <cmdline_parse.h>
109
110 #include <rte_common.h>
111 #include <rte_log.h>
112 #include <rte_memory.h>
113 #include <rte_memzone.h>
114 #include <rte_launch.h>
115 #include <rte_cycles.h>
116 #include <rte_tailq.h>
117 #include <rte_eal.h>
118 #include <rte_per_lcore.h>
119 #include <rte_lcore.h>
120 #include <rte_atomic.h>
121 #include <rte_timer.h>
122 #include <rte_random.h>
123
124 #include "test.h"
125
126 #define TEST_DURATION_S 30 /* in seconds */
127 #define NB_TIMER 4
128
129 #define RTE_LOGTYPE_TESTTIMER RTE_LOGTYPE_USER3
130
131 static volatile uint64_t end_time;
132
133 struct mytimerinfo {
134         struct rte_timer tim;
135         unsigned id;
136         unsigned count;
137 };
138
139 static struct mytimerinfo mytiminfo[NB_TIMER];
140
141 static void timer_basic_cb(struct rte_timer *tim, void *arg);
142
143 static void
144 mytimer_reset(struct mytimerinfo *timinfo, unsigned ticks,
145               enum rte_timer_type type, unsigned tim_lcore,
146               rte_timer_cb_t fct)
147 {
148         rte_timer_reset_sync(&timinfo->tim, ticks, type, tim_lcore,
149                              fct, timinfo);
150 }
151
152 /* timer callback for stress tests */
153 static void
154 timer_stress_cb(__attribute__((unused)) struct rte_timer *tim,
155                 __attribute__((unused)) void *arg)
156 {
157         long r;
158         unsigned lcore_id = rte_lcore_id();
159         uint64_t hz = rte_get_hpet_hz();
160
161         if (rte_timer_pending(tim))
162                 return;
163
164         r = rte_rand();
165         if ((r & 0xff) == 0) {
166                 mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
167                               timer_stress_cb);
168         }
169         else if ((r & 0xff) == 1) {
170                 mytimer_reset(&mytiminfo[0], hz, SINGLE,
171                               rte_get_next_lcore(lcore_id, 0, 1),
172                               timer_stress_cb);
173         }
174         else if ((r & 0xff) == 2) {
175                 rte_timer_stop(&mytiminfo[0].tim);
176         }
177 }
178
179 static int
180 timer_stress_main_loop(__attribute__((unused)) void *arg)
181 {
182         uint64_t hz = rte_get_hpet_hz();
183         unsigned lcore_id = rte_lcore_id();
184         uint64_t cur_time;
185         int64_t diff = 0;
186         long r;
187
188         while (diff >= 0) {
189
190                 /* call the timer handler on each core */
191                 rte_timer_manage();
192
193                 /* simulate the processing of a packet
194                  * (3 us = 6000 cycles at 2 Ghz) */
195                 rte_delay_us(3);
196
197                 /* randomly stop or reset timer */
198                 r = rte_rand();
199                 lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
200                 if ((r & 0xff) == 0) {
201                         /* 100 us */
202                         mytimer_reset(&mytiminfo[0], hz/10000, SINGLE, lcore_id,
203                                       timer_stress_cb);
204                 }
205                 else if ((r & 0xff) == 1) {
206                         rte_timer_stop_sync(&mytiminfo[0].tim);
207                 }
208                 cur_time = rte_get_hpet_cycles();
209                 diff = end_time - cur_time;
210         }
211
212         lcore_id = rte_lcore_id();
213         RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
214
215         return 0;
216 }
217
218 /* timer callback for basic tests */
219 static void
220 timer_basic_cb(struct rte_timer *tim, void *arg)
221 {
222         struct mytimerinfo *timinfo = arg;
223         uint64_t hz = rte_get_hpet_hz();
224         unsigned lcore_id = rte_lcore_id();
225         uint64_t cur_time = rte_get_hpet_cycles();
226
227         if (rte_timer_pending(tim))
228                 return;
229
230         timinfo->count ++;
231
232         RTE_LOG(INFO, TESTTIMER,
233                 "%"PRIu64": callback id=%u count=%u on core %u\n",
234                 cur_time, timinfo->id, timinfo->count, lcore_id);
235
236         /* reload timer 0 on same core */
237         if (timinfo->id == 0 && timinfo->count < 20) {
238                 mytimer_reset(timinfo, hz, SINGLE, lcore_id, timer_basic_cb);
239                 return;
240         }
241
242         /* reload timer 1 on next core */
243         if (timinfo->id == 1 && timinfo->count < 10) {
244                 mytimer_reset(timinfo, hz*2, SINGLE,
245                               rte_get_next_lcore(lcore_id, 0, 1),
246                               timer_basic_cb);
247                 return;
248         }
249
250         /* Explicitelly stop timer 0. Once stop() called, we can even
251          * erase the content of the structure: it is not referenced
252          * anymore by any code (in case of dynamic structure, it can
253          * be freed) */
254         if (timinfo->id == 0 && timinfo->count == 20) {
255
256                 /* stop_sync() is not needed, because we know that the
257                  * status of timer is only modified by this core */
258                 rte_timer_stop(tim);
259                 memset(tim, 0xAA, sizeof(struct rte_timer));
260                 return;
261         }
262
263         /* stop timer3, and restart a new timer0 (it was removed 5
264          * seconds ago) for a single shot */
265         if (timinfo->id == 2 && timinfo->count == 25) {
266                 rte_timer_stop_sync(&mytiminfo[3].tim);
267
268                 /* need to reinit because structure was erased with 0xAA */
269                 rte_timer_init(&mytiminfo[0].tim);
270                 mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
271                               timer_basic_cb);
272         }
273 }
274
275 static int
276 timer_basic_main_loop(__attribute__((unused)) void *arg)
277 {
278         uint64_t hz = rte_get_hpet_hz();
279         unsigned lcore_id = rte_lcore_id();
280         uint64_t cur_time;
281         int64_t diff = 0;
282
283         /* launch all timers on core 0 */
284         if (lcore_id == rte_get_master_lcore()) {
285                 mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
286                               timer_basic_cb);
287                 mytimer_reset(&mytiminfo[1], hz*2, SINGLE, lcore_id,
288                               timer_basic_cb);
289                 mytimer_reset(&mytiminfo[2], hz, PERIODICAL, lcore_id,
290                               timer_basic_cb);
291                 mytimer_reset(&mytiminfo[3], hz, PERIODICAL,
292                               rte_get_next_lcore(lcore_id, 0, 1),
293                               timer_basic_cb);
294         }
295
296         while (diff >= 0) {
297
298                 /* call the timer handler on each core */
299                 rte_timer_manage();
300
301                 /* simulate the processing of a packet
302                  * (3 us = 6000 cycles at 2 Ghz) */
303                 rte_delay_us(3);
304
305                 cur_time = rte_get_hpet_cycles();
306                 diff = end_time - cur_time;
307         }
308         RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
309
310         return 0;
311 }
312
313 int
314 test_timer(void)
315 {
316         unsigned i;
317         uint64_t cur_time;
318         uint64_t hz;
319
320         if (rte_lcore_count() < 2) {
321                 printf("not enough lcores for this test\n");
322                 return -1;
323         }
324
325         /* init timer */
326         for (i=0; i<NB_TIMER; i++) {
327                 memset(&mytiminfo[i], 0, sizeof(struct mytimerinfo));
328                 mytiminfo[i].id = i;
329                 rte_timer_init(&mytiminfo[i].tim);
330         }
331
332         /* calculate the "end of test" time */
333         cur_time = rte_get_hpet_cycles();
334         hz = rte_get_hpet_hz();
335         end_time = cur_time + (hz * TEST_DURATION_S);
336
337         /* start other cores */
338         printf("Start timer stress tests (%d seconds)\n", TEST_DURATION_S);
339         rte_eal_mp_remote_launch(timer_stress_main_loop, NULL, CALL_MASTER);
340         rte_eal_mp_wait_lcore();
341
342         /* stop timer 0 used for stress test */
343         rte_timer_stop_sync(&mytiminfo[0].tim);
344
345         /* calculate the "end of test" time */
346         cur_time = rte_get_hpet_cycles();
347         hz = rte_get_hpet_hz();
348         end_time = cur_time + (hz * TEST_DURATION_S);
349
350         /* start other cores */
351         printf("Start timer basic tests (%d seconds)\n", TEST_DURATION_S);
352         rte_eal_mp_remote_launch(timer_basic_main_loop, NULL, CALL_MASTER);
353         rte_eal_mp_wait_lcore();
354
355         /* stop all timers */
356         for (i=0; i<NB_TIMER; i++) {
357                 rte_timer_stop_sync(&mytiminfo[i].tim);
358         }
359
360         rte_timer_dump_stats();
361
362         return 0;
363 }