xref: /dpdk/app/test/test_rwlock.c (revision b6a7e6852e9ab82ae0e05e2d2a0b83abca17de3b)
1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
3a9de470cSBruce Richardson  */
4a9de470cSBruce Richardson 
5a9de470cSBruce Richardson #include <stdio.h>
6a9de470cSBruce Richardson #include <stdint.h>
7a9de470cSBruce Richardson #include <inttypes.h>
8a9de470cSBruce Richardson #include <unistd.h>
9a9de470cSBruce Richardson #include <sys/queue.h>
10a9de470cSBruce Richardson #include <string.h>
11a9de470cSBruce Richardson 
12a9de470cSBruce Richardson #include <rte_common.h>
13a9de470cSBruce Richardson #include <rte_memory.h>
14a9de470cSBruce Richardson #include <rte_per_lcore.h>
15a9de470cSBruce Richardson #include <rte_launch.h>
16a9de470cSBruce Richardson #include <rte_rwlock.h>
17a9de470cSBruce Richardson #include <rte_eal.h>
18a9de470cSBruce Richardson #include <rte_lcore.h>
19a9de470cSBruce Richardson #include <rte_cycles.h>
20a9de470cSBruce Richardson 
21a9de470cSBruce Richardson #include "test.h"
22a9de470cSBruce Richardson 
23a9de470cSBruce Richardson /*
24a9de470cSBruce Richardson  * rwlock test
25a9de470cSBruce Richardson  * ===========
26a9de470cSBruce Richardson  * Provides UT for rte_rwlock API.
27a9de470cSBruce Richardson  * Main concern is on functional testing, but also provides some
28a9de470cSBruce Richardson  * performance measurements.
29a9de470cSBruce Richardson  * Obviously for proper testing need to be executed with more than one lcore.
30a9de470cSBruce Richardson  */
31a9de470cSBruce Richardson 
32a9de470cSBruce Richardson #define ITER_NUM	0x80
33a9de470cSBruce Richardson 
34a9de470cSBruce Richardson #define TEST_SEC	5
35a9de470cSBruce Richardson 
36a9de470cSBruce Richardson static rte_rwlock_t sl;
37a9de470cSBruce Richardson static rte_rwlock_t sl_tab[RTE_MAX_LCORE];
38*b6a7e685STyler Retzlaff static RTE_ATOMIC(uint32_t) synchro;
39a9de470cSBruce Richardson 
40a9de470cSBruce Richardson enum {
41a9de470cSBruce Richardson 	LC_TYPE_RDLOCK,
42a9de470cSBruce Richardson 	LC_TYPE_WRLOCK,
43a9de470cSBruce Richardson };
44a9de470cSBruce Richardson 
450efea35aSTyler Retzlaff static alignas(RTE_CACHE_LINE_SIZE) struct {
46a9de470cSBruce Richardson 	rte_rwlock_t lock;
47a9de470cSBruce Richardson 	uint64_t tick;
4814df4f29SStephen Hemminger 
49a9de470cSBruce Richardson 	volatile union {
50a9de470cSBruce Richardson 		uint8_t u8[RTE_CACHE_LINE_SIZE];
51a9de470cSBruce Richardson 		uint64_t u64[RTE_CACHE_LINE_SIZE / sizeof(uint64_t)];
52a9de470cSBruce Richardson 	} data;
530efea35aSTyler Retzlaff } try_rwlock_data;
54a9de470cSBruce Richardson 
550efea35aSTyler Retzlaff struct __rte_cache_aligned try_rwlock_lcore {
56a9de470cSBruce Richardson 	int32_t rc;
57a9de470cSBruce Richardson 	int32_t type;
58a9de470cSBruce Richardson 	struct {
59a9de470cSBruce Richardson 		uint64_t tick;
60a9de470cSBruce Richardson 		uint64_t fail;
61a9de470cSBruce Richardson 		uint64_t success;
62a9de470cSBruce Richardson 	} stat;
630efea35aSTyler Retzlaff };
64a9de470cSBruce Richardson 
65a9de470cSBruce Richardson static struct try_rwlock_lcore try_lcore_data[RTE_MAX_LCORE];
66a9de470cSBruce Richardson 
67a9de470cSBruce Richardson static int
test_rwlock_per_core(__rte_unused void * arg)68f2fc83b4SThomas Monjalon test_rwlock_per_core(__rte_unused void *arg)
69a9de470cSBruce Richardson {
70a9de470cSBruce Richardson 	rte_rwlock_write_lock(&sl);
71a9de470cSBruce Richardson 	printf("Global write lock taken on core %u\n", rte_lcore_id());
72a9de470cSBruce Richardson 	rte_rwlock_write_unlock(&sl);
73a9de470cSBruce Richardson 
74a9de470cSBruce Richardson 	rte_rwlock_write_lock(&sl_tab[rte_lcore_id()]);
75a9de470cSBruce Richardson 	printf("Hello from core %u !\n", rte_lcore_id());
76a9de470cSBruce Richardson 	rte_rwlock_write_unlock(&sl_tab[rte_lcore_id()]);
77a9de470cSBruce Richardson 
78a9de470cSBruce Richardson 	rte_rwlock_read_lock(&sl);
79a9de470cSBruce Richardson 	printf("Global read lock taken on core %u\n", rte_lcore_id());
80a9de470cSBruce Richardson 	rte_delay_ms(100);
81a9de470cSBruce Richardson 	printf("Release global read lock on core %u\n", rte_lcore_id());
82a9de470cSBruce Richardson 	rte_rwlock_read_unlock(&sl);
83a9de470cSBruce Richardson 
84a9de470cSBruce Richardson 	return 0;
85a9de470cSBruce Richardson }
86a9de470cSBruce Richardson 
87fe252fb6SJoyce Kong static rte_rwlock_t lk = RTE_RWLOCK_INITIALIZER;
88fe252fb6SJoyce Kong static volatile uint64_t rwlock_data;
896fef1ae4SJoyce Kong static uint64_t time_count[RTE_MAX_LCORE] = {0};
90fe252fb6SJoyce Kong 
916fef1ae4SJoyce Kong #define MAX_LOOP 10000
92fe252fb6SJoyce Kong #define TEST_RWLOCK_DEBUG 0
93fe252fb6SJoyce Kong 
94fe252fb6SJoyce Kong static int
load_loop_fn(__rte_unused void * arg)95f2fc83b4SThomas Monjalon load_loop_fn(__rte_unused void *arg)
96fe252fb6SJoyce Kong {
97fe252fb6SJoyce Kong 	uint64_t time_diff = 0, begin;
98fe252fb6SJoyce Kong 	uint64_t hz = rte_get_timer_hz();
99fe252fb6SJoyce Kong 	uint64_t lcount = 0;
100fe252fb6SJoyce Kong 	const unsigned int lcore = rte_lcore_id();
101fe252fb6SJoyce Kong 
102cb056611SStephen Hemminger 	/* wait synchro for workers */
103cb056611SStephen Hemminger 	if (lcore != rte_get_main_lcore())
104*b6a7e685STyler Retzlaff 		rte_wait_until_equal_32((uint32_t *)(uintptr_t)&synchro, 1,
105*b6a7e685STyler Retzlaff 				rte_memory_order_relaxed);
106fe252fb6SJoyce Kong 
107fe252fb6SJoyce Kong 	begin = rte_rdtsc_precise();
1086fef1ae4SJoyce Kong 	while (lcount < MAX_LOOP) {
109fe252fb6SJoyce Kong 		rte_rwlock_write_lock(&lk);
110fe252fb6SJoyce Kong 		++rwlock_data;
111fe252fb6SJoyce Kong 		rte_rwlock_write_unlock(&lk);
112fe252fb6SJoyce Kong 
113fe252fb6SJoyce Kong 		rte_rwlock_read_lock(&lk);
114fe252fb6SJoyce Kong 		if (TEST_RWLOCK_DEBUG && !(lcount % 100))
115fe252fb6SJoyce Kong 			printf("Core [%u] rwlock_data = %"PRIu64"\n",
116fe252fb6SJoyce Kong 				lcore, rwlock_data);
117fe252fb6SJoyce Kong 		rte_rwlock_read_unlock(&lk);
118fe252fb6SJoyce Kong 
119fe252fb6SJoyce Kong 		lcount++;
120fe252fb6SJoyce Kong 		/* delay to make lock duty cycle slightly realistic */
121fe252fb6SJoyce Kong 		rte_pause();
122fe252fb6SJoyce Kong 	}
123fe252fb6SJoyce Kong 
1246fef1ae4SJoyce Kong 	time_diff = rte_rdtsc_precise() - begin;
1256fef1ae4SJoyce Kong 	time_count[lcore] = time_diff * 1000000 / hz;
126fe252fb6SJoyce Kong 	return 0;
127fe252fb6SJoyce Kong }
128fe252fb6SJoyce Kong 
129fe252fb6SJoyce Kong static int
test_rwlock_perf(void)130fe252fb6SJoyce Kong test_rwlock_perf(void)
131fe252fb6SJoyce Kong {
132fe252fb6SJoyce Kong 	unsigned int i;
133fe252fb6SJoyce Kong 	uint64_t total = 0;
134fe252fb6SJoyce Kong 
135fe252fb6SJoyce Kong 	printf("\nRwlock Perf Test on %u cores...\n", rte_lcore_count());
136fe252fb6SJoyce Kong 
137cb056611SStephen Hemminger 	/* clear synchro and start workers */
138*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&synchro, 0, rte_memory_order_relaxed);
139cb056611SStephen Hemminger 	if (rte_eal_mp_remote_launch(load_loop_fn, NULL, SKIP_MAIN) < 0)
140fe252fb6SJoyce Kong 		return -1;
141fe252fb6SJoyce Kong 
142cb056611SStephen Hemminger 	/* start synchro and launch test on main */
143*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
144fe252fb6SJoyce Kong 	load_loop_fn(NULL);
145fe252fb6SJoyce Kong 
146fe252fb6SJoyce Kong 	rte_eal_mp_wait_lcore();
147fe252fb6SJoyce Kong 
148fe252fb6SJoyce Kong 	RTE_LCORE_FOREACH(i) {
1496fef1ae4SJoyce Kong 		printf("Core [%u] cost time = %"PRIu64" us\n",
1506fef1ae4SJoyce Kong 			i, time_count[i]);
1516fef1ae4SJoyce Kong 		total += time_count[i];
152fe252fb6SJoyce Kong 	}
153fe252fb6SJoyce Kong 
1546fef1ae4SJoyce Kong 	printf("Total cost time = %"PRIu64" us\n", total);
1556fef1ae4SJoyce Kong 	memset(time_count, 0, sizeof(time_count));
156fe252fb6SJoyce Kong 
157fe252fb6SJoyce Kong 	return 0;
158fe252fb6SJoyce Kong }
159fe252fb6SJoyce Kong 
160a9de470cSBruce Richardson /*
161a9de470cSBruce Richardson  * - There is a global rwlock and a table of rwlocks (one per lcore).
162a9de470cSBruce Richardson  *
163a9de470cSBruce Richardson  * - The test function takes all of these locks and launches the
164cb056611SStephen Hemminger  *   ``test_rwlock_per_core()`` function on each core (except the main).
165a9de470cSBruce Richardson  *
166a9de470cSBruce Richardson  *   - The function takes the global write lock, display something,
167a9de470cSBruce Richardson  *     then releases the global lock.
168a9de470cSBruce Richardson  *   - Then, it takes the per-lcore write lock, display something, and
169a9de470cSBruce Richardson  *     releases the per-core lock.
170a9de470cSBruce Richardson  *   - Finally, a read lock is taken during 100 ms, then released.
171a9de470cSBruce Richardson  *
172a9de470cSBruce Richardson  * - The main function unlocks the per-lcore locks sequentially and
173a9de470cSBruce Richardson  *   waits between each lock. This triggers the display of a message
174a9de470cSBruce Richardson  *   for each core, in the correct order.
175a9de470cSBruce Richardson  *
176a9de470cSBruce Richardson  *   Then, it tries to take the global write lock and display the last
177a9de470cSBruce Richardson  *   message. The autotest script checks that the message order is correct.
178a9de470cSBruce Richardson  */
179a9de470cSBruce Richardson static int
rwlock_test1(void)180a9de470cSBruce Richardson rwlock_test1(void)
181a9de470cSBruce Richardson {
182a9de470cSBruce Richardson 	int i;
183a9de470cSBruce Richardson 
184a9de470cSBruce Richardson 	rte_rwlock_init(&sl);
185a9de470cSBruce Richardson 	for (i = 0; i < RTE_MAX_LCORE; i++)
186a9de470cSBruce Richardson 		rte_rwlock_init(&sl_tab[i]);
187a9de470cSBruce Richardson 
188a9de470cSBruce Richardson 	rte_rwlock_write_lock(&sl);
189a9de470cSBruce Richardson 
190cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
191a9de470cSBruce Richardson 		rte_rwlock_write_lock(&sl_tab[i]);
192a9de470cSBruce Richardson 		rte_eal_remote_launch(test_rwlock_per_core, NULL, i);
193a9de470cSBruce Richardson 	}
194a9de470cSBruce Richardson 
195a9de470cSBruce Richardson 	rte_rwlock_write_unlock(&sl);
196a9de470cSBruce Richardson 
197cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
198a9de470cSBruce Richardson 		rte_rwlock_write_unlock(&sl_tab[i]);
199a9de470cSBruce Richardson 		rte_delay_ms(100);
200a9de470cSBruce Richardson 	}
201a9de470cSBruce Richardson 
202a9de470cSBruce Richardson 	rte_rwlock_write_lock(&sl);
203a9de470cSBruce Richardson 	/* this message should be the last message of test */
204cb056611SStephen Hemminger 	printf("Global write lock taken on main core %u\n", rte_lcore_id());
205a9de470cSBruce Richardson 	rte_rwlock_write_unlock(&sl);
206a9de470cSBruce Richardson 
207a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
208a9de470cSBruce Richardson 
209fe252fb6SJoyce Kong 	if (test_rwlock_perf() < 0)
210fe252fb6SJoyce Kong 		return -1;
211fe252fb6SJoyce Kong 
212a9de470cSBruce Richardson 	return 0;
213a9de470cSBruce Richardson }
214a9de470cSBruce Richardson 
215a9de470cSBruce Richardson static int
try_read(uint32_t lc)216a9de470cSBruce Richardson try_read(uint32_t lc)
217a9de470cSBruce Richardson {
218a9de470cSBruce Richardson 	int32_t rc;
219a9de470cSBruce Richardson 	uint32_t i;
220a9de470cSBruce Richardson 
221a9de470cSBruce Richardson 	rc = rte_rwlock_read_trylock(&try_rwlock_data.lock);
222a9de470cSBruce Richardson 	if (rc != 0)
223a9de470cSBruce Richardson 		return rc;
224a9de470cSBruce Richardson 
225a9de470cSBruce Richardson 	for (i = 0; i != RTE_DIM(try_rwlock_data.data.u64); i++) {
226a9de470cSBruce Richardson 
227a9de470cSBruce Richardson 		/* race condition occurred, lock doesn't work properly */
228a9de470cSBruce Richardson 		if (try_rwlock_data.data.u64[i] != 0) {
229a9de470cSBruce Richardson 			printf("%s(%u) error: unexpected data pattern\n",
230a9de470cSBruce Richardson 				__func__, lc);
231a9de470cSBruce Richardson 			rte_memdump(stdout, NULL,
232a9de470cSBruce Richardson 				(void *)(uintptr_t)&try_rwlock_data.data,
233a9de470cSBruce Richardson 				sizeof(try_rwlock_data.data));
234a9de470cSBruce Richardson 			rc = -EFAULT;
235a9de470cSBruce Richardson 			break;
236a9de470cSBruce Richardson 		}
237a9de470cSBruce Richardson 	}
238a9de470cSBruce Richardson 
239a9de470cSBruce Richardson 	rte_rwlock_read_unlock(&try_rwlock_data.lock);
240a9de470cSBruce Richardson 	return rc;
241a9de470cSBruce Richardson }
242a9de470cSBruce Richardson 
243a9de470cSBruce Richardson static int
try_write(uint32_t lc)244a9de470cSBruce Richardson try_write(uint32_t lc)
245a9de470cSBruce Richardson {
246a9de470cSBruce Richardson 	int32_t rc;
247a9de470cSBruce Richardson 	uint32_t i, v;
248a9de470cSBruce Richardson 
249a9de470cSBruce Richardson 	v = RTE_MAX(lc % UINT8_MAX, 1U);
250a9de470cSBruce Richardson 
251a9de470cSBruce Richardson 	rc = rte_rwlock_write_trylock(&try_rwlock_data.lock);
252a9de470cSBruce Richardson 	if (rc != 0)
253a9de470cSBruce Richardson 		return rc;
254a9de470cSBruce Richardson 
25514df4f29SStephen Hemminger 	/* update by bytes in reverse order */
256a9de470cSBruce Richardson 	for (i = RTE_DIM(try_rwlock_data.data.u8); i-- != 0; ) {
257a9de470cSBruce Richardson 
258a9de470cSBruce Richardson 		/* race condition occurred, lock doesn't work properly */
259a9de470cSBruce Richardson 		if (try_rwlock_data.data.u8[i] != 0) {
260a9de470cSBruce Richardson 			printf("%s:%d(%u) error: unexpected data pattern\n",
261a9de470cSBruce Richardson 				__func__, __LINE__, lc);
262a9de470cSBruce Richardson 			rte_memdump(stdout, NULL,
263a9de470cSBruce Richardson 				(void *)(uintptr_t)&try_rwlock_data.data,
264a9de470cSBruce Richardson 				sizeof(try_rwlock_data.data));
265a9de470cSBruce Richardson 			rc = -EFAULT;
266a9de470cSBruce Richardson 			break;
267a9de470cSBruce Richardson 		}
268a9de470cSBruce Richardson 
269a9de470cSBruce Richardson 		try_rwlock_data.data.u8[i] = v;
270a9de470cSBruce Richardson 	}
271a9de470cSBruce Richardson 
27214df4f29SStephen Hemminger 	/* restore by bytes in reverse order */
273a9de470cSBruce Richardson 	for (i = RTE_DIM(try_rwlock_data.data.u8); i-- != 0; ) {
274a9de470cSBruce Richardson 
275a9de470cSBruce Richardson 		/* race condition occurred, lock doesn't work properly */
276a9de470cSBruce Richardson 		if (try_rwlock_data.data.u8[i] != v) {
277a9de470cSBruce Richardson 			printf("%s:%d(%u) error: unexpected data pattern\n",
278a9de470cSBruce Richardson 				__func__, __LINE__, lc);
279a9de470cSBruce Richardson 			rte_memdump(stdout, NULL,
280a9de470cSBruce Richardson 				(void *)(uintptr_t)&try_rwlock_data.data,
281a9de470cSBruce Richardson 				sizeof(try_rwlock_data.data));
282a9de470cSBruce Richardson 			rc = -EFAULT;
283a9de470cSBruce Richardson 			break;
284a9de470cSBruce Richardson 		}
285a9de470cSBruce Richardson 
286a9de470cSBruce Richardson 		try_rwlock_data.data.u8[i] = 0;
287a9de470cSBruce Richardson 	}
288a9de470cSBruce Richardson 
289a9de470cSBruce Richardson 	rte_rwlock_write_unlock(&try_rwlock_data.lock);
290a9de470cSBruce Richardson 	return rc;
291a9de470cSBruce Richardson }
292a9de470cSBruce Richardson 
293a9de470cSBruce Richardson static int
try_read_lcore(__rte_unused void * data)294a9de470cSBruce Richardson try_read_lcore(__rte_unused void *data)
295a9de470cSBruce Richardson {
296a9de470cSBruce Richardson 	int32_t rc;
297a9de470cSBruce Richardson 	uint32_t i, lc;
298a9de470cSBruce Richardson 	uint64_t ftm, stm, tm;
299a9de470cSBruce Richardson 	struct try_rwlock_lcore *lcd;
300a9de470cSBruce Richardson 
301a9de470cSBruce Richardson 	lc = rte_lcore_id();
302a9de470cSBruce Richardson 	lcd = try_lcore_data + lc;
303a9de470cSBruce Richardson 	lcd->type = LC_TYPE_RDLOCK;
304a9de470cSBruce Richardson 
305a9de470cSBruce Richardson 	ftm = try_rwlock_data.tick;
306a9de470cSBruce Richardson 	stm = rte_get_timer_cycles();
307a9de470cSBruce Richardson 
308a9de470cSBruce Richardson 	do {
309a9de470cSBruce Richardson 		for (i = 0; i != ITER_NUM; i++) {
310a9de470cSBruce Richardson 			rc = try_read(lc);
311a9de470cSBruce Richardson 			if (rc == 0)
312a9de470cSBruce Richardson 				lcd->stat.success++;
313a9de470cSBruce Richardson 			else if (rc == -EBUSY)
314a9de470cSBruce Richardson 				lcd->stat.fail++;
315a9de470cSBruce Richardson 			else
316a9de470cSBruce Richardson 				break;
317a9de470cSBruce Richardson 			rc = 0;
318a9de470cSBruce Richardson 		}
319a9de470cSBruce Richardson 		tm = rte_get_timer_cycles() - stm;
320a9de470cSBruce Richardson 	} while (tm < ftm && rc == 0);
321a9de470cSBruce Richardson 
322a9de470cSBruce Richardson 	lcd->rc = rc;
323a9de470cSBruce Richardson 	lcd->stat.tick = tm;
324a9de470cSBruce Richardson 	return rc;
325a9de470cSBruce Richardson }
326a9de470cSBruce Richardson 
327a9de470cSBruce Richardson static int
try_write_lcore(__rte_unused void * data)328a9de470cSBruce Richardson try_write_lcore(__rte_unused void *data)
329a9de470cSBruce Richardson {
330a9de470cSBruce Richardson 	int32_t rc;
331a9de470cSBruce Richardson 	uint32_t i, lc;
332a9de470cSBruce Richardson 	uint64_t ftm, stm, tm;
333a9de470cSBruce Richardson 	struct try_rwlock_lcore *lcd;
334a9de470cSBruce Richardson 
335a9de470cSBruce Richardson 	lc = rte_lcore_id();
336a9de470cSBruce Richardson 	lcd = try_lcore_data + lc;
337a9de470cSBruce Richardson 	lcd->type = LC_TYPE_WRLOCK;
338a9de470cSBruce Richardson 
339a9de470cSBruce Richardson 	ftm = try_rwlock_data.tick;
340a9de470cSBruce Richardson 	stm = rte_get_timer_cycles();
341a9de470cSBruce Richardson 
342a9de470cSBruce Richardson 	do {
343a9de470cSBruce Richardson 		for (i = 0; i != ITER_NUM; i++) {
344a9de470cSBruce Richardson 			rc = try_write(lc);
345a9de470cSBruce Richardson 			if (rc == 0)
346a9de470cSBruce Richardson 				lcd->stat.success++;
347a9de470cSBruce Richardson 			else if (rc == -EBUSY)
348a9de470cSBruce Richardson 				lcd->stat.fail++;
349a9de470cSBruce Richardson 			else
350a9de470cSBruce Richardson 				break;
351a9de470cSBruce Richardson 			rc = 0;
352a9de470cSBruce Richardson 		}
353a9de470cSBruce Richardson 		tm = rte_get_timer_cycles() - stm;
354a9de470cSBruce Richardson 	} while (tm < ftm && rc == 0);
355a9de470cSBruce Richardson 
356a9de470cSBruce Richardson 	lcd->rc = rc;
357a9de470cSBruce Richardson 	lcd->stat.tick = tm;
358a9de470cSBruce Richardson 	return rc;
359a9de470cSBruce Richardson }
360a9de470cSBruce Richardson 
361a9de470cSBruce Richardson static void
print_try_lcore_stats(const struct try_rwlock_lcore * tlc,uint32_t lc)362a9de470cSBruce Richardson print_try_lcore_stats(const struct try_rwlock_lcore *tlc, uint32_t lc)
363a9de470cSBruce Richardson {
364a9de470cSBruce Richardson 	uint64_t f, s;
365a9de470cSBruce Richardson 
366a9de470cSBruce Richardson 	f = RTE_MAX(tlc->stat.fail, 1ULL);
367a9de470cSBruce Richardson 	s = RTE_MAX(tlc->stat.success, 1ULL);
368a9de470cSBruce Richardson 
369a9de470cSBruce Richardson 	printf("try_lcore_data[%u]={\n"
370a9de470cSBruce Richardson 		"\trc=%d,\n"
371a9de470cSBruce Richardson 		"\ttype=%s,\n"
372a9de470cSBruce Richardson 		"\tfail=%" PRIu64 ",\n"
373a9de470cSBruce Richardson 		"\tsuccess=%" PRIu64 ",\n"
374a9de470cSBruce Richardson 		"\tcycles=%" PRIu64 ",\n"
375a9de470cSBruce Richardson 		"\tcycles/op=%#Lf,\n"
376a9de470cSBruce Richardson 		"\tcycles/success=%#Lf,\n"
377a9de470cSBruce Richardson 		"\tsuccess/fail=%#Lf,\n"
378a9de470cSBruce Richardson 		"};\n",
379a9de470cSBruce Richardson 		lc,
380a9de470cSBruce Richardson 		tlc->rc,
381a9de470cSBruce Richardson 		tlc->type == LC_TYPE_RDLOCK ? "RDLOCK" : "WRLOCK",
382a9de470cSBruce Richardson 		tlc->stat.fail,
383a9de470cSBruce Richardson 		tlc->stat.success,
384a9de470cSBruce Richardson 		tlc->stat.tick,
385a9de470cSBruce Richardson 		(long double)tlc->stat.tick /
386a9de470cSBruce Richardson 		(tlc->stat.fail + tlc->stat.success),
387a9de470cSBruce Richardson 		(long double)tlc->stat.tick / s,
388a9de470cSBruce Richardson 		(long double)tlc->stat.success / f);
389a9de470cSBruce Richardson }
390a9de470cSBruce Richardson 
391a9de470cSBruce Richardson static void
collect_try_lcore_stats(struct try_rwlock_lcore * tlc,const struct try_rwlock_lcore * lc)392a9de470cSBruce Richardson collect_try_lcore_stats(struct try_rwlock_lcore *tlc,
393a9de470cSBruce Richardson 	const struct try_rwlock_lcore *lc)
394a9de470cSBruce Richardson {
395a9de470cSBruce Richardson 	tlc->stat.tick += lc->stat.tick;
396a9de470cSBruce Richardson 	tlc->stat.fail += lc->stat.fail;
397a9de470cSBruce Richardson 	tlc->stat.success += lc->stat.success;
398a9de470cSBruce Richardson }
399a9de470cSBruce Richardson 
400a9de470cSBruce Richardson /*
401a9de470cSBruce Richardson  * Process collected results:
402a9de470cSBruce Richardson  *  - check status
403a9de470cSBruce Richardson  *  - collect and print statistics
404a9de470cSBruce Richardson  */
405a9de470cSBruce Richardson static int
process_try_lcore_stats(void)406a9de470cSBruce Richardson process_try_lcore_stats(void)
407a9de470cSBruce Richardson {
408a9de470cSBruce Richardson 	int32_t rc;
409a9de470cSBruce Richardson 	uint32_t lc, rd, wr;
410a9de470cSBruce Richardson 	struct try_rwlock_lcore rlc, wlc;
411a9de470cSBruce Richardson 
412a9de470cSBruce Richardson 	memset(&rlc, 0, sizeof(rlc));
413a9de470cSBruce Richardson 	memset(&wlc, 0, sizeof(wlc));
414a9de470cSBruce Richardson 
415a9de470cSBruce Richardson 	rlc.type = LC_TYPE_RDLOCK;
416a9de470cSBruce Richardson 	wlc.type = LC_TYPE_WRLOCK;
417a9de470cSBruce Richardson 	rd = 0;
418a9de470cSBruce Richardson 	wr = 0;
419a9de470cSBruce Richardson 
420a9de470cSBruce Richardson 	rc = 0;
421a9de470cSBruce Richardson 	RTE_LCORE_FOREACH(lc) {
422a9de470cSBruce Richardson 		rc |= try_lcore_data[lc].rc;
423a9de470cSBruce Richardson 		if (try_lcore_data[lc].type == LC_TYPE_RDLOCK) {
424a9de470cSBruce Richardson 			collect_try_lcore_stats(&rlc, try_lcore_data + lc);
425a9de470cSBruce Richardson 			rd++;
426a9de470cSBruce Richardson 		} else {
427a9de470cSBruce Richardson 			collect_try_lcore_stats(&wlc, try_lcore_data + lc);
428a9de470cSBruce Richardson 			wr++;
429a9de470cSBruce Richardson 		}
430a9de470cSBruce Richardson 	}
431a9de470cSBruce Richardson 
432a9de470cSBruce Richardson 	if (rc == 0) {
433a9de470cSBruce Richardson 		RTE_LCORE_FOREACH(lc)
434a9de470cSBruce Richardson 			print_try_lcore_stats(try_lcore_data + lc, lc);
435a9de470cSBruce Richardson 
436a9de470cSBruce Richardson 		if (rd != 0) {
437a9de470cSBruce Richardson 			printf("aggregated stats for %u RDLOCK cores:\n", rd);
438a9de470cSBruce Richardson 			print_try_lcore_stats(&rlc, rd);
439a9de470cSBruce Richardson 		}
440a9de470cSBruce Richardson 
441a9de470cSBruce Richardson 		if (wr != 0) {
442a9de470cSBruce Richardson 			printf("aggregated stats for %u WRLOCK cores:\n", wr);
443a9de470cSBruce Richardson 			print_try_lcore_stats(&wlc, wr);
444a9de470cSBruce Richardson 		}
445a9de470cSBruce Richardson 	}
446a9de470cSBruce Richardson 
447a9de470cSBruce Richardson 	return rc;
448a9de470cSBruce Richardson }
449a9de470cSBruce Richardson 
450a9de470cSBruce Richardson static void
try_test_reset(void)451a9de470cSBruce Richardson try_test_reset(void)
452a9de470cSBruce Richardson {
453a9de470cSBruce Richardson 	memset(&try_lcore_data, 0, sizeof(try_lcore_data));
454a9de470cSBruce Richardson 	memset(&try_rwlock_data, 0, sizeof(try_rwlock_data));
455a9de470cSBruce Richardson 	try_rwlock_data.tick = TEST_SEC * rte_get_tsc_hz();
456a9de470cSBruce Richardson }
457a9de470cSBruce Richardson 
458a9de470cSBruce Richardson /* all lcores grab RDLOCK */
459a9de470cSBruce Richardson static int
try_rwlock_test_rda(void)460a9de470cSBruce Richardson try_rwlock_test_rda(void)
461a9de470cSBruce Richardson {
462a9de470cSBruce Richardson 	try_test_reset();
463a9de470cSBruce Richardson 
46414df4f29SStephen Hemminger 	/* start read test on all available lcores */
465cb056611SStephen Hemminger 	rte_eal_mp_remote_launch(try_read_lcore, NULL, CALL_MAIN);
466a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
467a9de470cSBruce Richardson 
468a9de470cSBruce Richardson 	return process_try_lcore_stats();
469a9de470cSBruce Richardson }
470a9de470cSBruce Richardson 
471cb056611SStephen Hemminger /* all worker lcores grab RDLOCK, main one grabs WRLOCK */
472a9de470cSBruce Richardson static int
try_rwlock_test_rds_wrm(void)473a9de470cSBruce Richardson try_rwlock_test_rds_wrm(void)
474a9de470cSBruce Richardson {
475a9de470cSBruce Richardson 	try_test_reset();
476a9de470cSBruce Richardson 
477cb056611SStephen Hemminger 	rte_eal_mp_remote_launch(try_read_lcore, NULL, SKIP_MAIN);
478a9de470cSBruce Richardson 	try_write_lcore(NULL);
479a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
480a9de470cSBruce Richardson 
481a9de470cSBruce Richardson 	return process_try_lcore_stats();
482a9de470cSBruce Richardson }
483a9de470cSBruce Richardson 
484cb056611SStephen Hemminger /* main and even worker lcores grab RDLOCK, odd lcores grab WRLOCK */
485a9de470cSBruce Richardson static int
try_rwlock_test_rde_wro(void)486a9de470cSBruce Richardson try_rwlock_test_rde_wro(void)
487a9de470cSBruce Richardson {
488a9de470cSBruce Richardson 	uint32_t lc, mlc;
489a9de470cSBruce Richardson 
490a9de470cSBruce Richardson 	try_test_reset();
491a9de470cSBruce Richardson 
492cb056611SStephen Hemminger 	mlc = rte_get_main_lcore();
493a9de470cSBruce Richardson 
494a9de470cSBruce Richardson 	RTE_LCORE_FOREACH(lc) {
495a9de470cSBruce Richardson 		if (lc != mlc) {
496a9de470cSBruce Richardson 			if ((lc & 1) == 0)
497a9de470cSBruce Richardson 				rte_eal_remote_launch(try_read_lcore,
498a9de470cSBruce Richardson 						NULL, lc);
499a9de470cSBruce Richardson 			else
500a9de470cSBruce Richardson 				rte_eal_remote_launch(try_write_lcore,
501a9de470cSBruce Richardson 						NULL, lc);
502a9de470cSBruce Richardson 		}
503a9de470cSBruce Richardson 	}
504a9de470cSBruce Richardson 	try_read_lcore(NULL);
505a9de470cSBruce Richardson 	rte_eal_mp_wait_lcore();
506a9de470cSBruce Richardson 
507a9de470cSBruce Richardson 	return process_try_lcore_stats();
508a9de470cSBruce Richardson }
509a9de470cSBruce Richardson 
510e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_test1_autotest, true, true, rwlock_test1);
511e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_rda_autotest, true, true, try_rwlock_test_rda);
512e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_rds_wrm_autotest, true, true, try_rwlock_test_rds_wrm);
513e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_rde_wro_autotest, true, true, try_rwlock_test_rde_wro);
514