1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
3a9de470cSBruce Richardson */
4a9de470cSBruce Richardson
5a9de470cSBruce Richardson #include "test.h"
6a9de470cSBruce Richardson
7a9de470cSBruce Richardson /*
8a9de470cSBruce Richardson * Timer
9a9de470cSBruce Richardson * =====
10a9de470cSBruce Richardson *
11a9de470cSBruce Richardson * #. Stress test 1.
12a9de470cSBruce Richardson *
13a9de470cSBruce Richardson * The objective of the timer stress tests is to check that there are no
14a9de470cSBruce Richardson * race conditions in list and status management. This test launches,
15a9de470cSBruce Richardson * resets and stops the timer very often on many cores at the same
16a9de470cSBruce Richardson * time.
17a9de470cSBruce Richardson *
18a9de470cSBruce Richardson * - Only one timer is used for this test.
19a9de470cSBruce Richardson * - On each core, the rte_timer_manage() function is called from the main
20a9de470cSBruce Richardson * loop every 3 microseconds.
21a9de470cSBruce Richardson * - In the main loop, the timer may be reset (randomly, with a
22a9de470cSBruce Richardson * probability of 0.5 %) 100 microseconds later on a random core, or
23a9de470cSBruce Richardson * stopped (with a probability of 0.5 % also).
24a9de470cSBruce Richardson * - In callback, the timer is can be reset (randomly, with a
25a9de470cSBruce Richardson * probability of 0.5 %) 100 microseconds later on the same core or
26a9de470cSBruce Richardson * on another core (same probability), or stopped (same
27a9de470cSBruce Richardson * probability).
28a9de470cSBruce Richardson *
29a9de470cSBruce Richardson * # Stress test 2.
30a9de470cSBruce Richardson *
31a9de470cSBruce Richardson * The objective of this test is similar to the first in that it attempts
32a9de470cSBruce Richardson * to find if there are any race conditions in the timer library. However,
33a9de470cSBruce Richardson * it is less complex in terms of operations performed and duration, as it
34a9de470cSBruce Richardson * is designed to have a predictable outcome that can be tested.
35a9de470cSBruce Richardson *
36a9de470cSBruce Richardson * - A set of timers is initialized for use by the test
37a9de470cSBruce Richardson * - All cores then simultaneously are set to schedule all the timers at
38a9de470cSBruce Richardson * the same time, so conflicts should occur.
39a9de470cSBruce Richardson * - Then there is a delay while we wait for the timers to expire
40cb056611SStephen Hemminger * - Then the main lcore calls timer_manage() and we check that all
41a9de470cSBruce Richardson * timers have had their callbacks called exactly once - no more no less.
42a9de470cSBruce Richardson * - Then we repeat the process, except after setting up the timers, we have
43a9de470cSBruce Richardson * all cores randomly reschedule them.
44a9de470cSBruce Richardson * - Again we check that the expected number of callbacks has occurred when
45a9de470cSBruce Richardson * we call timer-manage.
46a9de470cSBruce Richardson *
47a9de470cSBruce Richardson * #. Basic test.
48a9de470cSBruce Richardson *
49a9de470cSBruce Richardson * This test performs basic functional checks of the timers. The test
50a9de470cSBruce Richardson * uses four different timers that are loaded and stopped under
51a9de470cSBruce Richardson * specific conditions in specific contexts.
52a9de470cSBruce Richardson *
53a9de470cSBruce Richardson * - Four timers are used for this test.
54a9de470cSBruce Richardson * - On each core, the rte_timer_manage() function is called from main loop
55a9de470cSBruce Richardson * every 3 microseconds.
56a9de470cSBruce Richardson *
57a9de470cSBruce Richardson * The autotest python script checks that the behavior is correct:
58a9de470cSBruce Richardson *
59a9de470cSBruce Richardson * - timer0
60a9de470cSBruce Richardson *
61cb056611SStephen Hemminger * - At initialization, timer0 is loaded by the main core, on main core
62a9de470cSBruce Richardson * in "single" mode (time = 1 second).
63a9de470cSBruce Richardson * - In the first 19 callbacks, timer0 is reloaded on the same core,
64a9de470cSBruce Richardson * then, it is explicitly stopped at the 20th call.
65a9de470cSBruce Richardson * - At t=25s, timer0 is reloaded once by timer2.
66a9de470cSBruce Richardson *
67a9de470cSBruce Richardson * - timer1
68a9de470cSBruce Richardson *
69cb056611SStephen Hemminger * - At initialization, timer1 is loaded by the main core, on the
70cb056611SStephen Hemminger * main core in "single" mode (time = 2 seconds).
71a9de470cSBruce Richardson * - In the first 9 callbacks, timer1 is reloaded on another
72a9de470cSBruce Richardson * core. After the 10th callback, timer1 is not reloaded anymore.
73a9de470cSBruce Richardson *
74a9de470cSBruce Richardson * - timer2
75a9de470cSBruce Richardson *
76cb056611SStephen Hemminger * - At initialization, timer2 is loaded by the main core, on the
77cb056611SStephen Hemminger * main core in "periodical" mode (time = 1 second).
78a9de470cSBruce Richardson * - In the callback, when t=25s, it stops timer3 and reloads timer0
79a9de470cSBruce Richardson * on the current core.
80a9de470cSBruce Richardson *
81a9de470cSBruce Richardson * - timer3
82a9de470cSBruce Richardson *
83cb056611SStephen Hemminger * - At initialization, timer3 is loaded by the main core, on
84a9de470cSBruce Richardson * another core in "periodical" mode (time = 1 second).
85a9de470cSBruce Richardson * - It is stopped at t=25s by timer2.
86a9de470cSBruce Richardson */
87a9de470cSBruce Richardson
88a9de470cSBruce Richardson #include <stdio.h>
89a9de470cSBruce Richardson #include <stdarg.h>
90a9de470cSBruce Richardson #include <string.h>
91a9de470cSBruce Richardson #include <stdlib.h>
92a9de470cSBruce Richardson #include <stdint.h>
93a9de470cSBruce Richardson #include <inttypes.h>
94a9de470cSBruce Richardson #include <sys/queue.h>
95a9de470cSBruce Richardson #include <math.h>
96a9de470cSBruce Richardson
97a9de470cSBruce Richardson #include <rte_common.h>
98a9de470cSBruce Richardson #include <rte_log.h>
99a9de470cSBruce Richardson #include <rte_memory.h>
100a9de470cSBruce Richardson #include <rte_launch.h>
101a9de470cSBruce Richardson #include <rte_cycles.h>
102a9de470cSBruce Richardson #include <rte_eal.h>
103a9de470cSBruce Richardson #include <rte_per_lcore.h>
104a9de470cSBruce Richardson #include <rte_lcore.h>
105a9de470cSBruce Richardson #include <rte_timer.h>
106a9de470cSBruce Richardson #include <rte_random.h>
107a9de470cSBruce Richardson #include <rte_malloc.h>
108a9de470cSBruce Richardson #include <rte_pause.h>
109a9de470cSBruce Richardson
110a9de470cSBruce Richardson #define TEST_DURATION_S 1 /* in seconds */
111a9de470cSBruce Richardson #define NB_TIMER 4
112a9de470cSBruce Richardson
113a9de470cSBruce Richardson #define RTE_LOGTYPE_TESTTIMER RTE_LOGTYPE_USER3
114a9de470cSBruce Richardson
115a9de470cSBruce Richardson static volatile uint64_t end_time;
116a9de470cSBruce Richardson static volatile int test_failed;
117a9de470cSBruce Richardson
118a9de470cSBruce Richardson struct mytimerinfo {
119a9de470cSBruce Richardson struct rte_timer tim;
120a9de470cSBruce Richardson unsigned id;
121a9de470cSBruce Richardson unsigned count;
122a9de470cSBruce Richardson };
123a9de470cSBruce Richardson
124a9de470cSBruce Richardson static struct mytimerinfo mytiminfo[NB_TIMER];
125a9de470cSBruce Richardson
126a9de470cSBruce Richardson static void timer_basic_cb(struct rte_timer *tim, void *arg);
127a9de470cSBruce Richardson
128a9de470cSBruce Richardson static void
mytimer_reset(struct mytimerinfo * timinfo,uint64_t ticks,enum rte_timer_type type,unsigned tim_lcore,rte_timer_cb_t fct)129a9de470cSBruce Richardson mytimer_reset(struct mytimerinfo *timinfo, uint64_t ticks,
130a9de470cSBruce Richardson enum rte_timer_type type, unsigned tim_lcore,
131a9de470cSBruce Richardson rte_timer_cb_t fct)
132a9de470cSBruce Richardson {
133a9de470cSBruce Richardson rte_timer_reset_sync(&timinfo->tim, ticks, type, tim_lcore,
134a9de470cSBruce Richardson fct, timinfo);
135a9de470cSBruce Richardson }
136a9de470cSBruce Richardson
137a9de470cSBruce Richardson /* timer callback for stress tests */
138a9de470cSBruce Richardson static void
timer_stress_cb(__rte_unused struct rte_timer * tim,__rte_unused void * arg)139f2fc83b4SThomas Monjalon timer_stress_cb(__rte_unused struct rte_timer *tim,
140f2fc83b4SThomas Monjalon __rte_unused void *arg)
141a9de470cSBruce Richardson {
142a9de470cSBruce Richardson long r;
143a9de470cSBruce Richardson unsigned lcore_id = rte_lcore_id();
144a9de470cSBruce Richardson uint64_t hz = rte_get_timer_hz();
145a9de470cSBruce Richardson
146a9de470cSBruce Richardson if (rte_timer_pending(tim))
147a9de470cSBruce Richardson return;
148a9de470cSBruce Richardson
149a9de470cSBruce Richardson r = rte_rand();
150a9de470cSBruce Richardson if ((r & 0xff) == 0) {
151a9de470cSBruce Richardson mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
152a9de470cSBruce Richardson timer_stress_cb);
153a9de470cSBruce Richardson }
154a9de470cSBruce Richardson else if ((r & 0xff) == 1) {
155a9de470cSBruce Richardson mytimer_reset(&mytiminfo[0], hz, SINGLE,
156a9de470cSBruce Richardson rte_get_next_lcore(lcore_id, 0, 1),
157a9de470cSBruce Richardson timer_stress_cb);
158a9de470cSBruce Richardson }
159a9de470cSBruce Richardson else if ((r & 0xff) == 2) {
160a9de470cSBruce Richardson rte_timer_stop(&mytiminfo[0].tim);
161a9de470cSBruce Richardson }
162a9de470cSBruce Richardson }
163a9de470cSBruce Richardson
164a9de470cSBruce Richardson static int
timer_stress_main_loop(__rte_unused void * arg)165f2fc83b4SThomas Monjalon timer_stress_main_loop(__rte_unused void *arg)
166a9de470cSBruce Richardson {
167a9de470cSBruce Richardson uint64_t hz = rte_get_timer_hz();
168a9de470cSBruce Richardson unsigned lcore_id = rte_lcore_id();
169a9de470cSBruce Richardson uint64_t cur_time;
170a9de470cSBruce Richardson int64_t diff = 0;
171a9de470cSBruce Richardson long r;
172a9de470cSBruce Richardson
173a9de470cSBruce Richardson while (diff >= 0) {
174a9de470cSBruce Richardson
175a9de470cSBruce Richardson /* call the timer handler on each core */
176a9de470cSBruce Richardson rte_timer_manage();
177a9de470cSBruce Richardson
178a9de470cSBruce Richardson /* simulate the processing of a packet
179a9de470cSBruce Richardson * (1 us = 2000 cycles at 2 Ghz) */
180a9de470cSBruce Richardson rte_delay_us(1);
181a9de470cSBruce Richardson
182a9de470cSBruce Richardson /* randomly stop or reset timer */
183a9de470cSBruce Richardson r = rte_rand();
184a9de470cSBruce Richardson lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
185a9de470cSBruce Richardson if ((r & 0xff) == 0) {
186a9de470cSBruce Richardson /* 100 us */
187a9de470cSBruce Richardson mytimer_reset(&mytiminfo[0], hz/10000, SINGLE, lcore_id,
188a9de470cSBruce Richardson timer_stress_cb);
189a9de470cSBruce Richardson }
190a9de470cSBruce Richardson else if ((r & 0xff) == 1) {
191a9de470cSBruce Richardson rte_timer_stop_sync(&mytiminfo[0].tim);
192a9de470cSBruce Richardson }
193a9de470cSBruce Richardson cur_time = rte_get_timer_cycles();
194a9de470cSBruce Richardson diff = end_time - cur_time;
195a9de470cSBruce Richardson }
196a9de470cSBruce Richardson
197a9de470cSBruce Richardson lcore_id = rte_lcore_id();
198a9de470cSBruce Richardson RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
199a9de470cSBruce Richardson
200a9de470cSBruce Richardson return 0;
201a9de470cSBruce Richardson }
202a9de470cSBruce Richardson
203cb056611SStephen Hemminger /* Need to synchronize worker lcores through multiple steps. */
204cb056611SStephen Hemminger enum { WORKER_WAITING = 1, WORKER_RUN_SIGNAL, WORKER_RUNNING, WORKER_FINISHED };
205*827aa9c6SJoyce Kong static uint16_t lcore_state[RTE_MAX_LCORE];
206a9de470cSBruce Richardson
207a9de470cSBruce Richardson static void
main_init_workers(void)208cb056611SStephen Hemminger main_init_workers(void)
209a9de470cSBruce Richardson {
210a9de470cSBruce Richardson unsigned i;
211a9de470cSBruce Richardson
212cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(i) {
213*827aa9c6SJoyce Kong __atomic_store_n(&lcore_state[i], WORKER_WAITING, __ATOMIC_RELAXED);
214a9de470cSBruce Richardson }
215a9de470cSBruce Richardson }
216a9de470cSBruce Richardson
217a9de470cSBruce Richardson static void
main_start_workers(void)218cb056611SStephen Hemminger main_start_workers(void)
219a9de470cSBruce Richardson {
220a9de470cSBruce Richardson unsigned i;
221a9de470cSBruce Richardson
222cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(i) {
223*827aa9c6SJoyce Kong __atomic_store_n(&lcore_state[i], WORKER_RUN_SIGNAL, __ATOMIC_RELEASE);
224a9de470cSBruce Richardson }
225cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(i) {
226*827aa9c6SJoyce Kong rte_wait_until_equal_16(&lcore_state[i], WORKER_RUNNING, __ATOMIC_ACQUIRE);
227a9de470cSBruce Richardson }
228a9de470cSBruce Richardson }
229a9de470cSBruce Richardson
230a9de470cSBruce Richardson static void
main_wait_for_workers(void)231cb056611SStephen Hemminger main_wait_for_workers(void)
232a9de470cSBruce Richardson {
233a9de470cSBruce Richardson unsigned i;
234a9de470cSBruce Richardson
235cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(i) {
236*827aa9c6SJoyce Kong rte_wait_until_equal_16(&lcore_state[i], WORKER_FINISHED, __ATOMIC_ACQUIRE);
237a9de470cSBruce Richardson }
238a9de470cSBruce Richardson }
239a9de470cSBruce Richardson
240a9de470cSBruce Richardson static void
worker_wait_to_start(void)241cb056611SStephen Hemminger worker_wait_to_start(void)
242a9de470cSBruce Richardson {
243a9de470cSBruce Richardson unsigned lcore_id = rte_lcore_id();
244a9de470cSBruce Richardson
245*827aa9c6SJoyce Kong rte_wait_until_equal_16(&lcore_state[lcore_id], WORKER_RUN_SIGNAL, __ATOMIC_ACQUIRE);
246*827aa9c6SJoyce Kong __atomic_store_n(&lcore_state[lcore_id], WORKER_RUNNING, __ATOMIC_RELEASE);
247a9de470cSBruce Richardson }
248a9de470cSBruce Richardson
249a9de470cSBruce Richardson static void
worker_finish(void)250cb056611SStephen Hemminger worker_finish(void)
251a9de470cSBruce Richardson {
252a9de470cSBruce Richardson unsigned lcore_id = rte_lcore_id();
253a9de470cSBruce Richardson
254*827aa9c6SJoyce Kong __atomic_store_n(&lcore_state[lcore_id], WORKER_FINISHED, __ATOMIC_RELEASE);
255a9de470cSBruce Richardson }
256a9de470cSBruce Richardson
257a9de470cSBruce Richardson
258a9de470cSBruce Richardson static volatile int cb_count = 0;
259a9de470cSBruce Richardson
260a9de470cSBruce Richardson /* callback for second stress test. will only be called
261cb056611SStephen Hemminger * on main lcore
262cb056611SStephen Hemminger */
263a9de470cSBruce Richardson static void
timer_stress2_cb(struct rte_timer * tim __rte_unused,void * arg __rte_unused)264a9de470cSBruce Richardson timer_stress2_cb(struct rte_timer *tim __rte_unused, void *arg __rte_unused)
265a9de470cSBruce Richardson {
266a9de470cSBruce Richardson cb_count++;
267a9de470cSBruce Richardson }
268a9de470cSBruce Richardson
269a9de470cSBruce Richardson #define NB_STRESS2_TIMERS 8192
270a9de470cSBruce Richardson
271a9de470cSBruce Richardson static int
timer_stress2_main_loop(__rte_unused void * arg)272f2fc83b4SThomas Monjalon timer_stress2_main_loop(__rte_unused void *arg)
273a9de470cSBruce Richardson {
274a9de470cSBruce Richardson static struct rte_timer *timers;
275a9de470cSBruce Richardson int i, ret;
276a9de470cSBruce Richardson uint64_t delay = rte_get_timer_hz() / 20;
277cb056611SStephen Hemminger unsigned int lcore_id = rte_lcore_id();
278cb056611SStephen Hemminger unsigned int main_lcore = rte_get_main_lcore();
279a9de470cSBruce Richardson int32_t my_collisions = 0;
280*827aa9c6SJoyce Kong static uint32_t collisions;
281a9de470cSBruce Richardson
282cb056611SStephen Hemminger if (lcore_id == main_lcore) {
283a9de470cSBruce Richardson cb_count = 0;
284a9de470cSBruce Richardson test_failed = 0;
285*827aa9c6SJoyce Kong __atomic_store_n(&collisions, 0, __ATOMIC_RELAXED);
286a9de470cSBruce Richardson timers = rte_malloc(NULL, sizeof(*timers) * NB_STRESS2_TIMERS, 0);
287a9de470cSBruce Richardson if (timers == NULL) {
288a9de470cSBruce Richardson printf("Test Failed\n");
289a9de470cSBruce Richardson printf("- Cannot allocate memory for timers\n" );
290a9de470cSBruce Richardson test_failed = 1;
291cb056611SStephen Hemminger main_start_workers();
292a9de470cSBruce Richardson goto cleanup;
293a9de470cSBruce Richardson }
294a9de470cSBruce Richardson for (i = 0; i < NB_STRESS2_TIMERS; i++)
295a9de470cSBruce Richardson rte_timer_init(&timers[i]);
296cb056611SStephen Hemminger main_start_workers();
297a9de470cSBruce Richardson } else {
298cb056611SStephen Hemminger worker_wait_to_start();
299a9de470cSBruce Richardson if (test_failed)
300a9de470cSBruce Richardson goto cleanup;
301a9de470cSBruce Richardson }
302a9de470cSBruce Richardson
303cb056611SStephen Hemminger /* have all cores schedule all timers on main lcore */
304a9de470cSBruce Richardson for (i = 0; i < NB_STRESS2_TIMERS; i++) {
305cb056611SStephen Hemminger ret = rte_timer_reset(&timers[i], delay, SINGLE, main_lcore,
306a9de470cSBruce Richardson timer_stress2_cb, NULL);
307a9de470cSBruce Richardson /* there will be collisions when multiple cores simultaneously
308a9de470cSBruce Richardson * configure the same timers */
309a9de470cSBruce Richardson if (ret != 0)
310a9de470cSBruce Richardson my_collisions++;
311a9de470cSBruce Richardson }
312a9de470cSBruce Richardson if (my_collisions != 0)
313*827aa9c6SJoyce Kong __atomic_fetch_add(&collisions, my_collisions, __ATOMIC_RELAXED);
314a9de470cSBruce Richardson
315a9de470cSBruce Richardson /* wait long enough for timers to expire */
316a9de470cSBruce Richardson rte_delay_ms(100);
317a9de470cSBruce Richardson
318a9de470cSBruce Richardson /* all cores rendezvous */
319cb056611SStephen Hemminger if (lcore_id == main_lcore) {
320cb056611SStephen Hemminger main_wait_for_workers();
321a9de470cSBruce Richardson } else {
322cb056611SStephen Hemminger worker_finish();
323a9de470cSBruce Richardson }
324a9de470cSBruce Richardson
325a9de470cSBruce Richardson /* now check that we get the right number of callbacks */
326cb056611SStephen Hemminger if (lcore_id == main_lcore) {
327*827aa9c6SJoyce Kong my_collisions = __atomic_load_n(&collisions, __ATOMIC_RELAXED);
328a9de470cSBruce Richardson if (my_collisions != 0)
329a9de470cSBruce Richardson printf("- %d timer reset collisions (OK)\n", my_collisions);
330a9de470cSBruce Richardson rte_timer_manage();
331a9de470cSBruce Richardson if (cb_count != NB_STRESS2_TIMERS) {
332a9de470cSBruce Richardson printf("Test Failed\n");
333a9de470cSBruce Richardson printf("- Stress test 2, part 1 failed\n");
334a9de470cSBruce Richardson printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS,
335a9de470cSBruce Richardson cb_count);
336a9de470cSBruce Richardson test_failed = 1;
337cb056611SStephen Hemminger main_start_workers();
338a9de470cSBruce Richardson goto cleanup;
339a9de470cSBruce Richardson }
340a9de470cSBruce Richardson cb_count = 0;
341a9de470cSBruce Richardson
342a9de470cSBruce Richardson /* proceed */
343cb056611SStephen Hemminger main_start_workers();
344a9de470cSBruce Richardson } else {
345a9de470cSBruce Richardson /* proceed */
346cb056611SStephen Hemminger worker_wait_to_start();
347a9de470cSBruce Richardson if (test_failed)
348a9de470cSBruce Richardson goto cleanup;
349a9de470cSBruce Richardson }
350a9de470cSBruce Richardson
351a9de470cSBruce Richardson /* now test again, just stop and restart timers at random after init*/
352a9de470cSBruce Richardson for (i = 0; i < NB_STRESS2_TIMERS; i++)
353cb056611SStephen Hemminger rte_timer_reset(&timers[i], delay, SINGLE, main_lcore,
354a9de470cSBruce Richardson timer_stress2_cb, NULL);
355a9de470cSBruce Richardson
356a9de470cSBruce Richardson /* pick random timer to reset, stopping them first half the time */
357a9de470cSBruce Richardson for (i = 0; i < 100000; i++) {
358a9de470cSBruce Richardson int r = rand() % NB_STRESS2_TIMERS;
359a9de470cSBruce Richardson if (i % 2)
360a9de470cSBruce Richardson rte_timer_stop(&timers[r]);
361cb056611SStephen Hemminger rte_timer_reset(&timers[r], delay, SINGLE, main_lcore,
362a9de470cSBruce Richardson timer_stress2_cb, NULL);
363a9de470cSBruce Richardson }
364a9de470cSBruce Richardson
365a9de470cSBruce Richardson /* wait long enough for timers to expire */
366a9de470cSBruce Richardson rte_delay_ms(100);
367a9de470cSBruce Richardson
368a9de470cSBruce Richardson /* now check that we get the right number of callbacks */
369cb056611SStephen Hemminger if (lcore_id == main_lcore) {
370cb056611SStephen Hemminger main_wait_for_workers();
371a9de470cSBruce Richardson
372a9de470cSBruce Richardson rte_timer_manage();
373a9de470cSBruce Richardson if (cb_count != NB_STRESS2_TIMERS) {
374a9de470cSBruce Richardson printf("Test Failed\n");
375a9de470cSBruce Richardson printf("- Stress test 2, part 2 failed\n");
376a9de470cSBruce Richardson printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS,
377a9de470cSBruce Richardson cb_count);
378a9de470cSBruce Richardson test_failed = 1;
379a9de470cSBruce Richardson } else {
380a9de470cSBruce Richardson printf("Test OK\n");
381a9de470cSBruce Richardson }
382a9de470cSBruce Richardson }
383a9de470cSBruce Richardson
384a9de470cSBruce Richardson cleanup:
385cb056611SStephen Hemminger if (lcore_id == main_lcore) {
386cb056611SStephen Hemminger main_wait_for_workers();
387a9de470cSBruce Richardson if (timers != NULL) {
388a9de470cSBruce Richardson rte_free(timers);
389a9de470cSBruce Richardson timers = NULL;
390a9de470cSBruce Richardson }
391a9de470cSBruce Richardson } else {
392cb056611SStephen Hemminger worker_finish();
393a9de470cSBruce Richardson }
394a9de470cSBruce Richardson
395a9de470cSBruce Richardson return 0;
396a9de470cSBruce Richardson }
397a9de470cSBruce Richardson
398a9de470cSBruce Richardson /* timer callback for basic tests */
399a9de470cSBruce Richardson static void
timer_basic_cb(struct rte_timer * tim,void * arg)400a9de470cSBruce Richardson timer_basic_cb(struct rte_timer *tim, void *arg)
401a9de470cSBruce Richardson {
402a9de470cSBruce Richardson struct mytimerinfo *timinfo = arg;
403a9de470cSBruce Richardson uint64_t hz = rte_get_timer_hz();
404a9de470cSBruce Richardson unsigned lcore_id = rte_lcore_id();
405a9de470cSBruce Richardson uint64_t cur_time = rte_get_timer_cycles();
406a9de470cSBruce Richardson
407a9de470cSBruce Richardson if (rte_timer_pending(tim))
408a9de470cSBruce Richardson return;
409a9de470cSBruce Richardson
410a9de470cSBruce Richardson timinfo->count ++;
411a9de470cSBruce Richardson
412a9de470cSBruce Richardson RTE_LOG(INFO, TESTTIMER,
413a9de470cSBruce Richardson "%"PRIu64": callback id=%u count=%u on core %u\n",
414a9de470cSBruce Richardson cur_time, timinfo->id, timinfo->count, lcore_id);
415a9de470cSBruce Richardson
416a9de470cSBruce Richardson /* reload timer 0 on same core */
417a9de470cSBruce Richardson if (timinfo->id == 0 && timinfo->count < 20) {
418a9de470cSBruce Richardson mytimer_reset(timinfo, hz, SINGLE, lcore_id, timer_basic_cb);
419a9de470cSBruce Richardson return;
420a9de470cSBruce Richardson }
421a9de470cSBruce Richardson
422a9de470cSBruce Richardson /* reload timer 1 on next core */
423a9de470cSBruce Richardson if (timinfo->id == 1 && timinfo->count < 10) {
424a9de470cSBruce Richardson mytimer_reset(timinfo, hz*2, SINGLE,
425a9de470cSBruce Richardson rte_get_next_lcore(lcore_id, 0, 1),
426a9de470cSBruce Richardson timer_basic_cb);
427a9de470cSBruce Richardson return;
428a9de470cSBruce Richardson }
429a9de470cSBruce Richardson
4304a6672c2SStephen Hemminger /* Explicitly stop timer 0. Once stop() called, we can even
431a9de470cSBruce Richardson * erase the content of the structure: it is not referenced
432a9de470cSBruce Richardson * anymore by any code (in case of dynamic structure, it can
433a9de470cSBruce Richardson * be freed) */
434a9de470cSBruce Richardson if (timinfo->id == 0 && timinfo->count == 20) {
435a9de470cSBruce Richardson
436a9de470cSBruce Richardson /* stop_sync() is not needed, because we know that the
437a9de470cSBruce Richardson * status of timer is only modified by this core */
438a9de470cSBruce Richardson rte_timer_stop(tim);
439a9de470cSBruce Richardson memset(tim, 0xAA, sizeof(struct rte_timer));
440a9de470cSBruce Richardson return;
441a9de470cSBruce Richardson }
442a9de470cSBruce Richardson
443a9de470cSBruce Richardson /* stop timer3, and restart a new timer0 (it was removed 5
444a9de470cSBruce Richardson * seconds ago) for a single shot */
445a9de470cSBruce Richardson if (timinfo->id == 2 && timinfo->count == 25) {
446a9de470cSBruce Richardson rte_timer_stop_sync(&mytiminfo[3].tim);
447a9de470cSBruce Richardson
448a9de470cSBruce Richardson /* need to reinit because structure was erased with 0xAA */
449a9de470cSBruce Richardson rte_timer_init(&mytiminfo[0].tim);
450a9de470cSBruce Richardson mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id,
451a9de470cSBruce Richardson timer_basic_cb);
452a9de470cSBruce Richardson }
453a9de470cSBruce Richardson }
454a9de470cSBruce Richardson
455a9de470cSBruce Richardson static int
timer_basic_main_loop(__rte_unused void * arg)456f2fc83b4SThomas Monjalon timer_basic_main_loop(__rte_unused void *arg)
457a9de470cSBruce Richardson {
458a9de470cSBruce Richardson uint64_t hz = rte_get_timer_hz();
459a9de470cSBruce Richardson unsigned lcore_id = rte_lcore_id();
460a9de470cSBruce Richardson uint64_t cur_time;
461a9de470cSBruce Richardson int64_t diff = 0;
462a9de470cSBruce Richardson
463a9de470cSBruce Richardson /* launch all timers on core 0 */
464cb056611SStephen Hemminger if (lcore_id == rte_get_main_lcore()) {
465a9de470cSBruce Richardson mytimer_reset(&mytiminfo[0], hz/4, SINGLE, lcore_id,
466a9de470cSBruce Richardson timer_basic_cb);
467a9de470cSBruce Richardson mytimer_reset(&mytiminfo[1], hz/2, SINGLE, lcore_id,
468a9de470cSBruce Richardson timer_basic_cb);
469a9de470cSBruce Richardson mytimer_reset(&mytiminfo[2], hz/4, PERIODICAL, lcore_id,
470a9de470cSBruce Richardson timer_basic_cb);
471a9de470cSBruce Richardson mytimer_reset(&mytiminfo[3], hz/4, PERIODICAL,
472a9de470cSBruce Richardson rte_get_next_lcore(lcore_id, 0, 1),
473a9de470cSBruce Richardson timer_basic_cb);
474a9de470cSBruce Richardson }
475a9de470cSBruce Richardson
476a9de470cSBruce Richardson while (diff >= 0) {
477a9de470cSBruce Richardson
478a9de470cSBruce Richardson /* call the timer handler on each core */
479a9de470cSBruce Richardson rte_timer_manage();
480a9de470cSBruce Richardson
481a9de470cSBruce Richardson /* simulate the processing of a packet
482a9de470cSBruce Richardson * (3 us = 6000 cycles at 2 Ghz) */
483a9de470cSBruce Richardson rte_delay_us(3);
484a9de470cSBruce Richardson
485a9de470cSBruce Richardson cur_time = rte_get_timer_cycles();
486a9de470cSBruce Richardson diff = end_time - cur_time;
487a9de470cSBruce Richardson }
488a9de470cSBruce Richardson RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
489a9de470cSBruce Richardson
490a9de470cSBruce Richardson return 0;
491a9de470cSBruce Richardson }
492a9de470cSBruce Richardson
493a9de470cSBruce Richardson static int
timer_sanity_check(void)494a9de470cSBruce Richardson timer_sanity_check(void)
495a9de470cSBruce Richardson {
496a9de470cSBruce Richardson #ifdef RTE_LIBEAL_USE_HPET
497a9de470cSBruce Richardson if (eal_timer_source != EAL_TIMER_HPET) {
498a9de470cSBruce Richardson printf("Not using HPET, can't sanity check timer sources\n");
499a9de470cSBruce Richardson return 0;
500a9de470cSBruce Richardson }
501a9de470cSBruce Richardson
502a9de470cSBruce Richardson const uint64_t t_hz = rte_get_tsc_hz();
503a9de470cSBruce Richardson const uint64_t h_hz = rte_get_hpet_hz();
504a9de470cSBruce Richardson printf("Hertz values: TSC = %"PRIu64", HPET = %"PRIu64"\n", t_hz, h_hz);
505a9de470cSBruce Richardson
506a9de470cSBruce Richardson const uint64_t tsc_start = rte_get_tsc_cycles();
507a9de470cSBruce Richardson const uint64_t hpet_start = rte_get_hpet_cycles();
508a9de470cSBruce Richardson rte_delay_ms(100); /* delay 1/10 second */
509a9de470cSBruce Richardson const uint64_t tsc_end = rte_get_tsc_cycles();
510a9de470cSBruce Richardson const uint64_t hpet_end = rte_get_hpet_cycles();
511a9de470cSBruce Richardson printf("Measured cycles: TSC = %"PRIu64", HPET = %"PRIu64"\n",
512a9de470cSBruce Richardson tsc_end-tsc_start, hpet_end-hpet_start);
513a9de470cSBruce Richardson
514a9de470cSBruce Richardson const double tsc_time = (double)(tsc_end - tsc_start)/t_hz;
515a9de470cSBruce Richardson const double hpet_time = (double)(hpet_end - hpet_start)/h_hz;
516a9de470cSBruce Richardson /* get the percentage that the times differ by */
517a9de470cSBruce Richardson const double time_diff = fabs(tsc_time - hpet_time)*100/tsc_time;
518a9de470cSBruce Richardson printf("Measured time: TSC = %.4f, HPET = %.4f\n", tsc_time, hpet_time);
519a9de470cSBruce Richardson
520a9de470cSBruce Richardson printf("Elapsed time measured by TSC and HPET differ by %f%%\n",
521a9de470cSBruce Richardson time_diff);
522a9de470cSBruce Richardson if (time_diff > 0.1) {
523a9de470cSBruce Richardson printf("Error times differ by >0.1%%");
524a9de470cSBruce Richardson return -1;
525a9de470cSBruce Richardson }
526a9de470cSBruce Richardson #endif
527a9de470cSBruce Richardson return 0;
528a9de470cSBruce Richardson }
529a9de470cSBruce Richardson
530a9de470cSBruce Richardson static int
test_timer(void)531a9de470cSBruce Richardson test_timer(void)
532a9de470cSBruce Richardson {
533a9de470cSBruce Richardson unsigned i;
534a9de470cSBruce Richardson uint64_t cur_time;
535a9de470cSBruce Richardson uint64_t hz;
536a9de470cSBruce Richardson
537e0f4a0edSDavid Marchand if (rte_lcore_count() < 2) {
538e0f4a0edSDavid Marchand printf("Not enough cores for timer_autotest, expecting at least 2\n");
539e0f4a0edSDavid Marchand return TEST_SKIPPED;
540e0f4a0edSDavid Marchand }
541e0f4a0edSDavid Marchand
542a9de470cSBruce Richardson /* sanity check our timer sources and timer config values */
543a9de470cSBruce Richardson if (timer_sanity_check() < 0) {
544a9de470cSBruce Richardson printf("Timer sanity checks failed\n");
545a9de470cSBruce Richardson return TEST_FAILED;
546a9de470cSBruce Richardson }
547a9de470cSBruce Richardson
548a9de470cSBruce Richardson /* init timer */
549a9de470cSBruce Richardson for (i=0; i<NB_TIMER; i++) {
550a9de470cSBruce Richardson memset(&mytiminfo[i], 0, sizeof(struct mytimerinfo));
551a9de470cSBruce Richardson mytiminfo[i].id = i;
552a9de470cSBruce Richardson rte_timer_init(&mytiminfo[i].tim);
553a9de470cSBruce Richardson }
554a9de470cSBruce Richardson
555a9de470cSBruce Richardson /* calculate the "end of test" time */
556a9de470cSBruce Richardson cur_time = rte_get_timer_cycles();
557a9de470cSBruce Richardson hz = rte_get_timer_hz();
558a9de470cSBruce Richardson end_time = cur_time + (hz * TEST_DURATION_S);
559a9de470cSBruce Richardson
560a9de470cSBruce Richardson /* start other cores */
561a9de470cSBruce Richardson printf("Start timer stress tests\n");
562cb056611SStephen Hemminger rte_eal_mp_remote_launch(timer_stress_main_loop, NULL, CALL_MAIN);
563a9de470cSBruce Richardson rte_eal_mp_wait_lcore();
564a9de470cSBruce Richardson
565a9de470cSBruce Richardson /* stop timer 0 used for stress test */
566a9de470cSBruce Richardson rte_timer_stop_sync(&mytiminfo[0].tim);
567a9de470cSBruce Richardson
568a9de470cSBruce Richardson /* run a second, slightly different set of stress tests */
569a9de470cSBruce Richardson printf("\nStart timer stress tests 2\n");
570a9de470cSBruce Richardson test_failed = 0;
571*827aa9c6SJoyce Kong main_init_workers();
572cb056611SStephen Hemminger rte_eal_mp_remote_launch(timer_stress2_main_loop, NULL, CALL_MAIN);
573a9de470cSBruce Richardson rte_eal_mp_wait_lcore();
574a9de470cSBruce Richardson if (test_failed)
575a9de470cSBruce Richardson return TEST_FAILED;
576a9de470cSBruce Richardson
577a9de470cSBruce Richardson /* calculate the "end of test" time */
578a9de470cSBruce Richardson cur_time = rte_get_timer_cycles();
579a9de470cSBruce Richardson hz = rte_get_timer_hz();
580a9de470cSBruce Richardson end_time = cur_time + (hz * TEST_DURATION_S);
581a9de470cSBruce Richardson
582a9de470cSBruce Richardson /* start other cores */
583a9de470cSBruce Richardson printf("\nStart timer basic tests\n");
584cb056611SStephen Hemminger rte_eal_mp_remote_launch(timer_basic_main_loop, NULL, CALL_MAIN);
585a9de470cSBruce Richardson rte_eal_mp_wait_lcore();
586a9de470cSBruce Richardson
587a9de470cSBruce Richardson /* stop all timers */
588a9de470cSBruce Richardson for (i=0; i<NB_TIMER; i++) {
589a9de470cSBruce Richardson rte_timer_stop_sync(&mytiminfo[i].tim);
590a9de470cSBruce Richardson }
591a9de470cSBruce Richardson
592a9de470cSBruce Richardson rte_timer_dump_stats(stdout);
593a9de470cSBruce Richardson
594a9de470cSBruce Richardson return TEST_SUCCESS;
595a9de470cSBruce Richardson }
596a9de470cSBruce Richardson
597a9de470cSBruce Richardson REGISTER_TEST_COMMAND(timer_autotest, test_timer);
598