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