344e391a0b0510f7a6cb52065a6b4b23446fc9bc
[dpdk.git] / app / test / test_timer.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2013 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  */
34
35 /*
36  * Timer
37  * =====
38  *
39  * #. Stress tests.
40  *
41  *    The objective of the timer stress tests is to check that there are no
42  *    race conditions in list and status management. This test launches,
43  *    resets and stops the timer very often on many cores at the same
44  *    time.
45  *
46  *    - Only one timer is used for this test.
47  *    - On each core, the rte_timer_manage() function is called from the main
48  *      loop every 3 microseconds.
49  *    - In the main loop, the timer may be reset (randomly, with a
50  *      probability of 0.5 %) 100 microseconds later on a random core, or
51  *      stopped (with a probability of 0.5 % also).
52  *    - In callback, the timer is can be reset (randomly, with a
53  *      probability of 0.5 %) 100 microseconds later on the same core or
54  *      on another core (same probability), or stopped (same
55  *      probability).
56  *
57  *
58  * #. Basic test.
59  *
60  *    This test performs basic functional checks of the timers. The test
61  *    uses four different timers that are loaded and stopped under
62  *    specific conditions in specific contexts.
63  *
64  *    - Four timers are used for this test.
65  *    - On each core, the rte_timer_manage() function is called from main loop
66  *      every 3 microseconds.
67  *
68  *    The autotest python script checks that the behavior is correct:
69  *
70  *    - timer0
71  *
72  *      - At initialization, timer0 is loaded by the master core, on master core
73  *        in "single" mode (time = 1 second).
74  *      - In the first 19 callbacks, timer0 is reloaded on the same core,
75  *        then, it is explicitly stopped at the 20th call.
76  *      - At t=25s, timer0 is reloaded once by timer2.
77  *
78  *    - timer1
79  *
80  *      - At initialization, timer1 is loaded by the master core, on the
81  *        master core in "single" mode (time = 2 seconds).
82  *      - In the first 9 callbacks, timer1 is reloaded on another
83  *        core. After the 10th callback, timer1 is not reloaded anymore.
84  *
85  *    - timer2
86  *
87  *      - At initialization, timer2 is loaded by the master core, on the
88  *        master core in "periodical" mode (time = 1 second).
89  *      - In the callback, when t=25s, it stops timer3 and reloads timer0
90  *        on the current core.
91  *
92  *    - timer3
93  *
94  *      - At initialization, timer3 is loaded by the master core, on
95  *        another core in "periodical" mode (time = 1 second).
96  *      - It is stopped at t=25s by timer2.
97  */
98
99 #include <stdio.h>
100 #include <stdarg.h>
101 #include <string.h>
102 #include <stdlib.h>
103 #include <stdint.h>
104 #include <inttypes.h>
105 #include <sys/queue.h>
106 #include <math.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 20 /* 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, uint64_t 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_timer_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_timer_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_timer_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_timer_hz();
224         unsigned lcore_id = rte_lcore_id();
225         uint64_t cur_time = rte_get_timer_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_timer_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_timer_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 static int
314 timer_sanity_check(void)
315 {
316 #ifdef RTE_LIBEAL_USE_HPET
317         if (eal_timer_source != EAL_TIMER_HPET) {
318                 printf("Not using HPET, can't sanity check timer sources\n");
319                 return 0;
320         }
321
322         const uint64_t t_hz = rte_get_tsc_hz();
323         const uint64_t h_hz = rte_get_hpet_hz();
324         printf("Hertz values: TSC = %"PRIu64", HPET = %"PRIu64"\n", t_hz, h_hz);
325
326         const uint64_t tsc_start = rte_get_tsc_cycles();
327         const uint64_t hpet_start = rte_get_hpet_cycles();
328         rte_delay_ms(100); /* delay 1/10 second */
329         const uint64_t tsc_end = rte_get_tsc_cycles();
330         const uint64_t hpet_end = rte_get_hpet_cycles();
331         printf("Measured cycles: TSC = %"PRIu64", HPET = %"PRIu64"\n",
332                         tsc_end-tsc_start, hpet_end-hpet_start);
333
334         const double tsc_time = (double)(tsc_end - tsc_start)/t_hz;
335         const double hpet_time = (double)(hpet_end - hpet_start)/h_hz;
336         /* get the percentage that the times differ by */
337         const double time_diff = fabs(tsc_time - hpet_time)*100/tsc_time;
338         printf("Measured time: TSC = %.4f, HPET = %.4f\n", tsc_time, hpet_time);
339
340         printf("Elapsed time measured by TSC and HPET differ by %f%%\n",
341                         time_diff);
342         if (time_diff > 0.1) {
343                 printf("Error times differ by >0.1%%");
344                 return -1;
345         }
346 #endif
347         return 0;
348 }
349
350 int
351 test_timer(void)
352 {
353         unsigned i;
354         uint64_t cur_time;
355         uint64_t hz;
356
357         /* sanity check our timer sources and timer config values */
358         if (timer_sanity_check() < 0) {
359                 printf("Timer sanity checks failed\n");
360                 return -1;
361         }
362
363         if (rte_lcore_count() < 2) {
364                 printf("not enough lcores for this test\n");
365                 return -1;
366         }
367
368         /* init timer */
369         for (i=0; i<NB_TIMER; i++) {
370                 memset(&mytiminfo[i], 0, sizeof(struct mytimerinfo));
371                 mytiminfo[i].id = i;
372                 rte_timer_init(&mytiminfo[i].tim);
373         }
374
375         /* calculate the "end of test" time */
376         cur_time = rte_get_timer_cycles();
377         hz = rte_get_timer_hz();
378         end_time = cur_time + (hz * TEST_DURATION_S);
379
380         /* start other cores */
381         printf("Start timer stress tests (%d seconds)\n", TEST_DURATION_S);
382         rte_eal_mp_remote_launch(timer_stress_main_loop, NULL, CALL_MASTER);
383         rte_eal_mp_wait_lcore();
384
385         /* stop timer 0 used for stress test */
386         rte_timer_stop_sync(&mytiminfo[0].tim);
387
388         /* calculate the "end of test" time */
389         cur_time = rte_get_timer_cycles();
390         hz = rte_get_timer_hz();
391         end_time = cur_time + (hz * TEST_DURATION_S);
392
393         /* start other cores */
394         printf("Start timer basic tests (%d seconds)\n", TEST_DURATION_S);
395         rte_eal_mp_remote_launch(timer_basic_main_loop, NULL, CALL_MASTER);
396         rte_eal_mp_wait_lcore();
397
398         /* stop all timers */
399         for (i=0; i<NB_TIMER; i++) {
400                 rte_timer_stop_sync(&mytiminfo[i].tim);
401         }
402
403         rte_timer_dump_stats();
404
405         return 0;
406 }