xref: /dpdk/app/test/test_timer_racecond.c (revision e0a8442ccd15bafbb7eb150c35331c8e3b828c53)
108ab4769SHemant Agrawal /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson  * Copyright(c) 2015 Akamai Technologies.
3a9de470cSBruce Richardson  * All rights reserved.
4a9de470cSBruce Richardson  */
5a9de470cSBruce Richardson 
6a9de470cSBruce Richardson #include "test.h"
7a9de470cSBruce Richardson 
8a9de470cSBruce Richardson #include <stdio.h>
9a9de470cSBruce Richardson #include <unistd.h>
10a9de470cSBruce Richardson #include <inttypes.h>
11a9de470cSBruce Richardson #include <rte_cycles.h>
12a9de470cSBruce Richardson #include <rte_timer.h>
13a9de470cSBruce Richardson #include <rte_common.h>
14a9de470cSBruce Richardson #include <rte_lcore.h>
15a9de470cSBruce Richardson #include <rte_random.h>
16a9de470cSBruce Richardson #include <rte_malloc.h>
17a9de470cSBruce Richardson #include <rte_pause.h>
18a9de470cSBruce Richardson 
19742bde12SBruce Richardson #ifdef RTE_EXEC_ENV_LINUX
20a9de470cSBruce Richardson #define usec_delay(us) usleep(us)
21a9de470cSBruce Richardson #else
22a9de470cSBruce Richardson #define usec_delay(us) rte_delay_us(us)
23a9de470cSBruce Richardson #endif
24a9de470cSBruce Richardson 
25a9de470cSBruce Richardson #define BILLION (1UL << 30)
26a9de470cSBruce Richardson 
27a9de470cSBruce Richardson #define TEST_DURATION_S 4 /* in seconds */
28a9de470cSBruce Richardson #define N_TIMERS    50
29a9de470cSBruce Richardson 
30a9de470cSBruce Richardson static struct rte_timer timer[N_TIMERS];
31cb056611SStephen Hemminger static unsigned int timer_lcore_id[N_TIMERS];
32a9de470cSBruce Richardson 
33cb056611SStephen Hemminger static unsigned int main_lcore;
34cb056611SStephen Hemminger static volatile unsigned int stop_workers;
35a9de470cSBruce Richardson 
36a9de470cSBruce Richardson static int reload_timer(struct rte_timer *tim);
37a9de470cSBruce Richardson 
389c99878aSJerin Jacob RTE_LOG_REGISTER(timer_logtype_test, test.timer, INFO);
391ae40fdbSDharmik Thakkar 
40a9de470cSBruce Richardson static void
timer_cb(struct rte_timer * tim,void * arg __rte_unused)41a9de470cSBruce Richardson timer_cb(struct rte_timer *tim, void *arg __rte_unused)
42a9de470cSBruce Richardson {
43a9de470cSBruce Richardson 	/* Simulate slow callback function, 100 us. */
44a9de470cSBruce Richardson 	rte_delay_us(100);
45a9de470cSBruce Richardson 	if (tim == &timer[0])
461ae40fdbSDharmik Thakkar 		rte_log(RTE_LOG_DEBUG, timer_logtype_test,
471ae40fdbSDharmik Thakkar 			"------------------------------------------------\n");
481ae40fdbSDharmik Thakkar 	rte_log(RTE_LOG_DEBUG, timer_logtype_test, "%s: core %u timer %"
491ae40fdbSDharmik Thakkar 		PRIuPTR "\n", __func__, rte_lcore_id(), tim - timer);
50a9de470cSBruce Richardson 	(void)reload_timer(tim);
51a9de470cSBruce Richardson }
52a9de470cSBruce Richardson 
53a9de470cSBruce Richardson RTE_DEFINE_PER_LCORE(unsigned, n_reset_collisions);
54a9de470cSBruce Richardson 
55a9de470cSBruce Richardson static int
reload_timer(struct rte_timer * tim)56a9de470cSBruce Richardson reload_timer(struct rte_timer *tim)
57a9de470cSBruce Richardson {
58a9de470cSBruce Richardson 	/* Make timer expire roughly when the TSC hits the next BILLION
59a9de470cSBruce Richardson 	 * multiple. Add in timer's index to make them expire in nearly
60a9de470cSBruce Richardson 	 * sorted order. This makes all timers somewhat synchronized,
61a9de470cSBruce Richardson 	 * firing ~2-3 times per second, assuming 2-3 GHz TSCs.
62a9de470cSBruce Richardson 	 */
63a9de470cSBruce Richardson 	uint64_t ticks = BILLION - (rte_get_timer_cycles() % BILLION) +
64a9de470cSBruce Richardson 	    (tim - timer);
65a9de470cSBruce Richardson 	int ret;
66a9de470cSBruce Richardson 
67cb056611SStephen Hemminger 	ret = rte_timer_reset(tim, ticks, PERIODICAL, main_lcore, timer_cb, NULL);
68a9de470cSBruce Richardson 	if (ret != 0) {
691ae40fdbSDharmik Thakkar 		rte_log(RTE_LOG_DEBUG, timer_logtype_test,
701ae40fdbSDharmik Thakkar 			"- core %u failed to reset timer %" PRIuPTR " (OK)\n",
71a9de470cSBruce Richardson 			rte_lcore_id(), tim - timer);
72a9de470cSBruce Richardson 		RTE_PER_LCORE(n_reset_collisions) += 1;
73a9de470cSBruce Richardson 	}
74a9de470cSBruce Richardson 	return ret;
75a9de470cSBruce Richardson }
76a9de470cSBruce Richardson 
77a9de470cSBruce Richardson static int
worker_main_loop(__rte_unused void * arg)78cb056611SStephen Hemminger worker_main_loop(__rte_unused void *arg)
79a9de470cSBruce Richardson {
80a9de470cSBruce Richardson 	unsigned lcore_id = rte_lcore_id();
81a9de470cSBruce Richardson 	unsigned i;
82a9de470cSBruce Richardson 
83a9de470cSBruce Richardson 	RTE_PER_LCORE(n_reset_collisions) = 0;
84a9de470cSBruce Richardson 
85a9de470cSBruce Richardson 	printf("Starting main loop on core %u\n", lcore_id);
86a9de470cSBruce Richardson 
87cb056611SStephen Hemminger 	while (!stop_workers) {
88a9de470cSBruce Richardson 		/* Wait until the timer manager is running.
89a9de470cSBruce Richardson 		 * We know it's running when we see timer[0] NOT pending.
90a9de470cSBruce Richardson 		 */
91a9de470cSBruce Richardson 		if (rte_timer_pending(&timer[0])) {
92a9de470cSBruce Richardson 			rte_pause();
93a9de470cSBruce Richardson 			continue;
94a9de470cSBruce Richardson 		}
95a9de470cSBruce Richardson 
96a9de470cSBruce Richardson 		/* Now, go cause some havoc!
97a9de470cSBruce Richardson 		 * Reload our timers.
98a9de470cSBruce Richardson 		 */
99a9de470cSBruce Richardson 		for (i = 0; i < N_TIMERS; i++) {
100a9de470cSBruce Richardson 			if (timer_lcore_id[i] == lcore_id)
101a9de470cSBruce Richardson 				(void)reload_timer(&timer[i]);
102a9de470cSBruce Richardson 		}
103a9de470cSBruce Richardson 		usec_delay(100*1000); /* sleep 100 ms */
104a9de470cSBruce Richardson 	}
105a9de470cSBruce Richardson 
106a9de470cSBruce Richardson 	if (RTE_PER_LCORE(n_reset_collisions) != 0) {
107a9de470cSBruce Richardson 		printf("- core %u, %u reset collisions (OK)\n",
108a9de470cSBruce Richardson 			lcore_id, RTE_PER_LCORE(n_reset_collisions));
109a9de470cSBruce Richardson 	}
110a9de470cSBruce Richardson 	return 0;
111a9de470cSBruce Richardson }
112a9de470cSBruce Richardson 
113a9de470cSBruce Richardson static int
test_timer_racecond(void)114a9de470cSBruce Richardson test_timer_racecond(void)
115a9de470cSBruce Richardson {
116a9de470cSBruce Richardson 	int ret;
117a9de470cSBruce Richardson 	uint64_t hz;
118a9de470cSBruce Richardson 	uint64_t cur_time;
119a9de470cSBruce Richardson 	uint64_t end_time;
120a9de470cSBruce Richardson 	int64_t diff = 0;
121a9de470cSBruce Richardson 	unsigned lcore_id;
122a9de470cSBruce Richardson 	unsigned i;
123a9de470cSBruce Richardson 
124cb056611SStephen Hemminger 	main_lcore = lcore_id = rte_lcore_id();
125a9de470cSBruce Richardson 	hz = rte_get_timer_hz();
126a9de470cSBruce Richardson 
127a9de470cSBruce Richardson 	/* init and start timers */
128a9de470cSBruce Richardson 	for (i = 0; i < N_TIMERS; i++) {
129a9de470cSBruce Richardson 		rte_timer_init(&timer[i]);
130a9de470cSBruce Richardson 		ret = reload_timer(&timer[i]);
131a9de470cSBruce Richardson 		TEST_ASSERT(ret == 0, "reload_timer failed");
132a9de470cSBruce Richardson 
133cb056611SStephen Hemminger 		/* Distribute timers to workers.
134cb056611SStephen Hemminger 		 * Note that we assign timer[0] to the main.
135a9de470cSBruce Richardson 		 */
136a9de470cSBruce Richardson 		timer_lcore_id[i] = lcore_id;
137a9de470cSBruce Richardson 		lcore_id = rte_get_next_lcore(lcore_id, 1, 1);
138a9de470cSBruce Richardson 	}
139a9de470cSBruce Richardson 
140a9de470cSBruce Richardson 	/* calculate the "end of test" time */
141a9de470cSBruce Richardson 	cur_time = rte_get_timer_cycles();
142a9de470cSBruce Richardson 	end_time = cur_time + (hz * TEST_DURATION_S);
143a9de470cSBruce Richardson 
144cb056611SStephen Hemminger 	/* start worker cores */
145cb056611SStephen Hemminger 	stop_workers = 0;
146a9de470cSBruce Richardson 	printf("Start timer manage race condition test (%u seconds)\n",
147a9de470cSBruce Richardson 			TEST_DURATION_S);
148cb056611SStephen Hemminger 	rte_eal_mp_remote_launch(worker_main_loop, NULL, SKIP_MAIN);
149a9de470cSBruce Richardson 
150a9de470cSBruce Richardson 	while (diff >= 0) {
151a9de470cSBruce Richardson 		/* run the timers */
152a9de470cSBruce Richardson 		rte_timer_manage();
153a9de470cSBruce Richardson 
154a9de470cSBruce Richardson 		/* wait 100 ms */
155a9de470cSBruce Richardson 		usec_delay(100*1000);
156a9de470cSBruce Richardson 
157a9de470cSBruce Richardson 		cur_time = rte_get_timer_cycles();
158a9de470cSBruce Richardson 		diff = end_time - cur_time;
159a9de470cSBruce Richardson 	}
160a9de470cSBruce Richardson 
161cb056611SStephen Hemminger 	/* stop worker cores */
162a9de470cSBruce Richardson 	printf("Stopping timer manage race condition test\n");
163cb056611SStephen Hemminger 	stop_workers = 1;
164a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
165a9de470cSBruce Richardson 
166a9de470cSBruce Richardson 	/* stop timers */
167a9de470cSBruce Richardson 	for (i = 0; i < N_TIMERS; i++) {
168a9de470cSBruce Richardson 		ret = rte_timer_stop(&timer[i]);
169a9de470cSBruce Richardson 		TEST_ASSERT(ret == 0, "rte_timer_stop failed");
170a9de470cSBruce Richardson 	}
171a9de470cSBruce Richardson 
172a9de470cSBruce Richardson 	return TEST_SUCCESS;
173a9de470cSBruce Richardson }
174a9de470cSBruce Richardson 
175*e0a8442cSBruce Richardson REGISTER_PERF_TEST(timer_racecond_autotest, test_timer_racecond);
176