xref: /f-stack/dpdk/app/test/test_rwlock.c (revision 2d9fd380)
14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang  * Copyright(c) 2010-2014 Intel Corporation
34418919fSjohnjiang  */
44418919fSjohnjiang 
54418919fSjohnjiang #include <stdio.h>
64418919fSjohnjiang #include <stdint.h>
74418919fSjohnjiang #include <inttypes.h>
84418919fSjohnjiang #include <unistd.h>
94418919fSjohnjiang #include <sys/queue.h>
104418919fSjohnjiang #include <string.h>
114418919fSjohnjiang 
124418919fSjohnjiang #include <rte_common.h>
134418919fSjohnjiang #include <rte_memory.h>
144418919fSjohnjiang #include <rte_per_lcore.h>
154418919fSjohnjiang #include <rte_launch.h>
164418919fSjohnjiang #include <rte_atomic.h>
174418919fSjohnjiang #include <rte_rwlock.h>
184418919fSjohnjiang #include <rte_eal.h>
194418919fSjohnjiang #include <rte_lcore.h>
204418919fSjohnjiang #include <rte_cycles.h>
214418919fSjohnjiang 
224418919fSjohnjiang #include "test.h"
234418919fSjohnjiang 
244418919fSjohnjiang /*
254418919fSjohnjiang  * rwlock test
264418919fSjohnjiang  * ===========
274418919fSjohnjiang  * Provides UT for rte_rwlock API.
284418919fSjohnjiang  * Main concern is on functional testing, but also provides some
294418919fSjohnjiang  * performance measurements.
304418919fSjohnjiang  * Obviously for proper testing need to be executed with more than one lcore.
314418919fSjohnjiang  */
324418919fSjohnjiang 
334418919fSjohnjiang #define ITER_NUM	0x80
344418919fSjohnjiang 
354418919fSjohnjiang #define TEST_SEC	5
364418919fSjohnjiang 
374418919fSjohnjiang static rte_rwlock_t sl;
384418919fSjohnjiang static rte_rwlock_t sl_tab[RTE_MAX_LCORE];
394418919fSjohnjiang static rte_atomic32_t synchro;
404418919fSjohnjiang 
414418919fSjohnjiang enum {
424418919fSjohnjiang 	LC_TYPE_RDLOCK,
434418919fSjohnjiang 	LC_TYPE_WRLOCK,
444418919fSjohnjiang };
454418919fSjohnjiang 
464418919fSjohnjiang static struct {
474418919fSjohnjiang 	rte_rwlock_t lock;
484418919fSjohnjiang 	uint64_t tick;
494418919fSjohnjiang 	volatile union {
504418919fSjohnjiang 		uint8_t u8[RTE_CACHE_LINE_SIZE];
514418919fSjohnjiang 		uint64_t u64[RTE_CACHE_LINE_SIZE / sizeof(uint64_t)];
524418919fSjohnjiang 	} data;
534418919fSjohnjiang } __rte_cache_aligned try_rwlock_data;
544418919fSjohnjiang 
554418919fSjohnjiang struct try_rwlock_lcore {
564418919fSjohnjiang 	int32_t rc;
574418919fSjohnjiang 	int32_t type;
584418919fSjohnjiang 	struct {
594418919fSjohnjiang 		uint64_t tick;
604418919fSjohnjiang 		uint64_t fail;
614418919fSjohnjiang 		uint64_t success;
624418919fSjohnjiang 	} stat;
634418919fSjohnjiang } __rte_cache_aligned;
644418919fSjohnjiang 
654418919fSjohnjiang static struct try_rwlock_lcore try_lcore_data[RTE_MAX_LCORE];
664418919fSjohnjiang 
674418919fSjohnjiang static int
test_rwlock_per_core(__rte_unused void * arg)68*2d9fd380Sjfb8856606 test_rwlock_per_core(__rte_unused void *arg)
694418919fSjohnjiang {
704418919fSjohnjiang 	rte_rwlock_write_lock(&sl);
714418919fSjohnjiang 	printf("Global write lock taken on core %u\n", rte_lcore_id());
724418919fSjohnjiang 	rte_rwlock_write_unlock(&sl);
734418919fSjohnjiang 
744418919fSjohnjiang 	rte_rwlock_write_lock(&sl_tab[rte_lcore_id()]);
754418919fSjohnjiang 	printf("Hello from core %u !\n", rte_lcore_id());
764418919fSjohnjiang 	rte_rwlock_write_unlock(&sl_tab[rte_lcore_id()]);
774418919fSjohnjiang 
784418919fSjohnjiang 	rte_rwlock_read_lock(&sl);
794418919fSjohnjiang 	printf("Global read lock taken on core %u\n", rte_lcore_id());
804418919fSjohnjiang 	rte_delay_ms(100);
814418919fSjohnjiang 	printf("Release global read lock on core %u\n", rte_lcore_id());
824418919fSjohnjiang 	rte_rwlock_read_unlock(&sl);
834418919fSjohnjiang 
844418919fSjohnjiang 	return 0;
854418919fSjohnjiang }
864418919fSjohnjiang 
874418919fSjohnjiang static rte_rwlock_t lk = RTE_RWLOCK_INITIALIZER;
884418919fSjohnjiang static volatile uint64_t rwlock_data;
894418919fSjohnjiang static uint64_t time_count[RTE_MAX_LCORE] = {0};
904418919fSjohnjiang 
914418919fSjohnjiang #define MAX_LOOP 10000
924418919fSjohnjiang #define TEST_RWLOCK_DEBUG 0
934418919fSjohnjiang 
944418919fSjohnjiang static int
load_loop_fn(__rte_unused void * arg)95*2d9fd380Sjfb8856606 load_loop_fn(__rte_unused void *arg)
964418919fSjohnjiang {
974418919fSjohnjiang 	uint64_t time_diff = 0, begin;
984418919fSjohnjiang 	uint64_t hz = rte_get_timer_hz();
994418919fSjohnjiang 	uint64_t lcount = 0;
1004418919fSjohnjiang 	const unsigned int lcore = rte_lcore_id();
1014418919fSjohnjiang 
102*2d9fd380Sjfb8856606 	/* wait synchro for workers */
103*2d9fd380Sjfb8856606 	if (lcore != rte_get_main_lcore())
1044418919fSjohnjiang 		while (rte_atomic32_read(&synchro) == 0)
1054418919fSjohnjiang 			;
1064418919fSjohnjiang 
1074418919fSjohnjiang 	begin = rte_rdtsc_precise();
1084418919fSjohnjiang 	while (lcount < MAX_LOOP) {
1094418919fSjohnjiang 		rte_rwlock_write_lock(&lk);
1104418919fSjohnjiang 		++rwlock_data;
1114418919fSjohnjiang 		rte_rwlock_write_unlock(&lk);
1124418919fSjohnjiang 
1134418919fSjohnjiang 		rte_rwlock_read_lock(&lk);
1144418919fSjohnjiang 		if (TEST_RWLOCK_DEBUG && !(lcount % 100))
1154418919fSjohnjiang 			printf("Core [%u] rwlock_data = %"PRIu64"\n",
1164418919fSjohnjiang 				lcore, rwlock_data);
1174418919fSjohnjiang 		rte_rwlock_read_unlock(&lk);
1184418919fSjohnjiang 
1194418919fSjohnjiang 		lcount++;
1204418919fSjohnjiang 		/* delay to make lock duty cycle slightly realistic */
1214418919fSjohnjiang 		rte_pause();
1224418919fSjohnjiang 	}
1234418919fSjohnjiang 
1244418919fSjohnjiang 	time_diff = rte_rdtsc_precise() - begin;
1254418919fSjohnjiang 	time_count[lcore] = time_diff * 1000000 / hz;
1264418919fSjohnjiang 	return 0;
1274418919fSjohnjiang }
1284418919fSjohnjiang 
1294418919fSjohnjiang static int
test_rwlock_perf(void)1304418919fSjohnjiang test_rwlock_perf(void)
1314418919fSjohnjiang {
1324418919fSjohnjiang 	unsigned int i;
1334418919fSjohnjiang 	uint64_t total = 0;
1344418919fSjohnjiang 
1354418919fSjohnjiang 	printf("\nRwlock Perf Test on %u cores...\n", rte_lcore_count());
1364418919fSjohnjiang 
137*2d9fd380Sjfb8856606 	/* clear synchro and start workers */
1384418919fSjohnjiang 	rte_atomic32_set(&synchro, 0);
139*2d9fd380Sjfb8856606 	if (rte_eal_mp_remote_launch(load_loop_fn, NULL, SKIP_MAIN) < 0)
1404418919fSjohnjiang 		return -1;
1414418919fSjohnjiang 
142*2d9fd380Sjfb8856606 	/* start synchro and launch test on main */
1434418919fSjohnjiang 	rte_atomic32_set(&synchro, 1);
1444418919fSjohnjiang 	load_loop_fn(NULL);
1454418919fSjohnjiang 
1464418919fSjohnjiang 	rte_eal_mp_wait_lcore();
1474418919fSjohnjiang 
1484418919fSjohnjiang 	RTE_LCORE_FOREACH(i) {
1494418919fSjohnjiang 		printf("Core [%u] cost time = %"PRIu64" us\n",
1504418919fSjohnjiang 			i, time_count[i]);
1514418919fSjohnjiang 		total += time_count[i];
1524418919fSjohnjiang 	}
1534418919fSjohnjiang 
1544418919fSjohnjiang 	printf("Total cost time = %"PRIu64" us\n", total);
1554418919fSjohnjiang 	memset(time_count, 0, sizeof(time_count));
1564418919fSjohnjiang 
1574418919fSjohnjiang 	return 0;
1584418919fSjohnjiang }
1594418919fSjohnjiang 
1604418919fSjohnjiang /*
1614418919fSjohnjiang  * - There is a global rwlock and a table of rwlocks (one per lcore).
1624418919fSjohnjiang  *
1634418919fSjohnjiang  * - The test function takes all of these locks and launches the
164*2d9fd380Sjfb8856606  *   ``test_rwlock_per_core()`` function on each core (except the main).
1654418919fSjohnjiang  *
1664418919fSjohnjiang  *   - The function takes the global write lock, display something,
1674418919fSjohnjiang  *     then releases the global lock.
1684418919fSjohnjiang  *   - Then, it takes the per-lcore write lock, display something, and
1694418919fSjohnjiang  *     releases the per-core lock.
1704418919fSjohnjiang  *   - Finally, a read lock is taken during 100 ms, then released.
1714418919fSjohnjiang  *
1724418919fSjohnjiang  * - The main function unlocks the per-lcore locks sequentially and
1734418919fSjohnjiang  *   waits between each lock. This triggers the display of a message
1744418919fSjohnjiang  *   for each core, in the correct order.
1754418919fSjohnjiang  *
1764418919fSjohnjiang  *   Then, it tries to take the global write lock and display the last
1774418919fSjohnjiang  *   message. The autotest script checks that the message order is correct.
1784418919fSjohnjiang  */
1794418919fSjohnjiang static int
rwlock_test1(void)1804418919fSjohnjiang rwlock_test1(void)
1814418919fSjohnjiang {
1824418919fSjohnjiang 	int i;
1834418919fSjohnjiang 
1844418919fSjohnjiang 	rte_rwlock_init(&sl);
1854418919fSjohnjiang 	for (i=0; i<RTE_MAX_LCORE; i++)
1864418919fSjohnjiang 		rte_rwlock_init(&sl_tab[i]);
1874418919fSjohnjiang 
1884418919fSjohnjiang 	rte_rwlock_write_lock(&sl);
1894418919fSjohnjiang 
190*2d9fd380Sjfb8856606 	RTE_LCORE_FOREACH_WORKER(i) {
1914418919fSjohnjiang 		rte_rwlock_write_lock(&sl_tab[i]);
1924418919fSjohnjiang 		rte_eal_remote_launch(test_rwlock_per_core, NULL, i);
1934418919fSjohnjiang 	}
1944418919fSjohnjiang 
1954418919fSjohnjiang 	rte_rwlock_write_unlock(&sl);
1964418919fSjohnjiang 
197*2d9fd380Sjfb8856606 	RTE_LCORE_FOREACH_WORKER(i) {
1984418919fSjohnjiang 		rte_rwlock_write_unlock(&sl_tab[i]);
1994418919fSjohnjiang 		rte_delay_ms(100);
2004418919fSjohnjiang 	}
2014418919fSjohnjiang 
2024418919fSjohnjiang 	rte_rwlock_write_lock(&sl);
2034418919fSjohnjiang 	/* this message should be the last message of test */
204*2d9fd380Sjfb8856606 	printf("Global write lock taken on main core %u\n", rte_lcore_id());
2054418919fSjohnjiang 	rte_rwlock_write_unlock(&sl);
2064418919fSjohnjiang 
2074418919fSjohnjiang 	rte_eal_mp_wait_lcore();
2084418919fSjohnjiang 
2094418919fSjohnjiang 	if (test_rwlock_perf() < 0)
2104418919fSjohnjiang 		return -1;
2114418919fSjohnjiang 
2124418919fSjohnjiang 	return 0;
2134418919fSjohnjiang }
2144418919fSjohnjiang 
2154418919fSjohnjiang static int
try_read(uint32_t lc)2164418919fSjohnjiang try_read(uint32_t lc)
2174418919fSjohnjiang {
2184418919fSjohnjiang 	int32_t rc;
2194418919fSjohnjiang 	uint32_t i;
2204418919fSjohnjiang 
2214418919fSjohnjiang 	rc = rte_rwlock_read_trylock(&try_rwlock_data.lock);
2224418919fSjohnjiang 	if (rc != 0)
2234418919fSjohnjiang 		return rc;
2244418919fSjohnjiang 
2254418919fSjohnjiang 	for (i = 0; i != RTE_DIM(try_rwlock_data.data.u64); i++) {
2264418919fSjohnjiang 
2274418919fSjohnjiang 		/* race condition occurred, lock doesn't work properly */
2284418919fSjohnjiang 		if (try_rwlock_data.data.u64[i] != 0) {
2294418919fSjohnjiang 			printf("%s(%u) error: unexpected data pattern\n",
2304418919fSjohnjiang 				__func__, lc);
2314418919fSjohnjiang 			rte_memdump(stdout, NULL,
2324418919fSjohnjiang 				(void *)(uintptr_t)&try_rwlock_data.data,
2334418919fSjohnjiang 				sizeof(try_rwlock_data.data));
2344418919fSjohnjiang 			rc = -EFAULT;
2354418919fSjohnjiang 			break;
2364418919fSjohnjiang 		}
2374418919fSjohnjiang 	}
2384418919fSjohnjiang 
2394418919fSjohnjiang 	rte_rwlock_read_unlock(&try_rwlock_data.lock);
2404418919fSjohnjiang 	return rc;
2414418919fSjohnjiang }
2424418919fSjohnjiang 
2434418919fSjohnjiang static int
try_write(uint32_t lc)2444418919fSjohnjiang try_write(uint32_t lc)
2454418919fSjohnjiang {
2464418919fSjohnjiang 	int32_t rc;
2474418919fSjohnjiang 	uint32_t i, v;
2484418919fSjohnjiang 
2494418919fSjohnjiang 	v = RTE_MAX(lc % UINT8_MAX, 1U);
2504418919fSjohnjiang 
2514418919fSjohnjiang 	rc = rte_rwlock_write_trylock(&try_rwlock_data.lock);
2524418919fSjohnjiang 	if (rc != 0)
2534418919fSjohnjiang 		return rc;
2544418919fSjohnjiang 
2554418919fSjohnjiang 	/* update by bytes in reverese order */
2564418919fSjohnjiang 	for (i = RTE_DIM(try_rwlock_data.data.u8); i-- != 0; ) {
2574418919fSjohnjiang 
2584418919fSjohnjiang 		/* race condition occurred, lock doesn't work properly */
2594418919fSjohnjiang 		if (try_rwlock_data.data.u8[i] != 0) {
2604418919fSjohnjiang 			printf("%s:%d(%u) error: unexpected data pattern\n",
2614418919fSjohnjiang 				__func__, __LINE__, lc);
2624418919fSjohnjiang 			rte_memdump(stdout, NULL,
2634418919fSjohnjiang 				(void *)(uintptr_t)&try_rwlock_data.data,
2644418919fSjohnjiang 				sizeof(try_rwlock_data.data));
2654418919fSjohnjiang 			rc = -EFAULT;
2664418919fSjohnjiang 			break;
2674418919fSjohnjiang 		}
2684418919fSjohnjiang 
2694418919fSjohnjiang 		try_rwlock_data.data.u8[i] = v;
2704418919fSjohnjiang 	}
2714418919fSjohnjiang 
2724418919fSjohnjiang 	/* restore by bytes in reverese order */
2734418919fSjohnjiang 	for (i = RTE_DIM(try_rwlock_data.data.u8); i-- != 0; ) {
2744418919fSjohnjiang 
2754418919fSjohnjiang 		/* race condition occurred, lock doesn't work properly */
2764418919fSjohnjiang 		if (try_rwlock_data.data.u8[i] != v) {
2774418919fSjohnjiang 			printf("%s:%d(%u) error: unexpected data pattern\n",
2784418919fSjohnjiang 				__func__, __LINE__, lc);
2794418919fSjohnjiang 			rte_memdump(stdout, NULL,
2804418919fSjohnjiang 				(void *)(uintptr_t)&try_rwlock_data.data,
2814418919fSjohnjiang 				sizeof(try_rwlock_data.data));
2824418919fSjohnjiang 			rc = -EFAULT;
2834418919fSjohnjiang 			break;
2844418919fSjohnjiang 		}
2854418919fSjohnjiang 
2864418919fSjohnjiang 		try_rwlock_data.data.u8[i] = 0;
2874418919fSjohnjiang 	}
2884418919fSjohnjiang 
2894418919fSjohnjiang 	rte_rwlock_write_unlock(&try_rwlock_data.lock);
2904418919fSjohnjiang 	return rc;
2914418919fSjohnjiang }
2924418919fSjohnjiang 
2934418919fSjohnjiang static int
try_read_lcore(__rte_unused void * data)2944418919fSjohnjiang try_read_lcore(__rte_unused void *data)
2954418919fSjohnjiang {
2964418919fSjohnjiang 	int32_t rc;
2974418919fSjohnjiang 	uint32_t i, lc;
2984418919fSjohnjiang 	uint64_t ftm, stm, tm;
2994418919fSjohnjiang 	struct try_rwlock_lcore *lcd;
3004418919fSjohnjiang 
3014418919fSjohnjiang 	lc = rte_lcore_id();
3024418919fSjohnjiang 	lcd = try_lcore_data + lc;
3034418919fSjohnjiang 	lcd->type = LC_TYPE_RDLOCK;
3044418919fSjohnjiang 
3054418919fSjohnjiang 	ftm = try_rwlock_data.tick;
3064418919fSjohnjiang 	stm = rte_get_timer_cycles();
3074418919fSjohnjiang 
3084418919fSjohnjiang 	do {
3094418919fSjohnjiang 		for (i = 0; i != ITER_NUM; i++) {
3104418919fSjohnjiang 			rc = try_read(lc);
3114418919fSjohnjiang 			if (rc == 0)
3124418919fSjohnjiang 				lcd->stat.success++;
3134418919fSjohnjiang 			else if (rc == -EBUSY)
3144418919fSjohnjiang 				lcd->stat.fail++;
3154418919fSjohnjiang 			else
3164418919fSjohnjiang 				break;
3174418919fSjohnjiang 			rc = 0;
3184418919fSjohnjiang 		}
3194418919fSjohnjiang 		tm = rte_get_timer_cycles() - stm;
3204418919fSjohnjiang 	} while (tm < ftm && rc == 0);
3214418919fSjohnjiang 
3224418919fSjohnjiang 	lcd->rc = rc;
3234418919fSjohnjiang 	lcd->stat.tick = tm;
3244418919fSjohnjiang 	return rc;
3254418919fSjohnjiang }
3264418919fSjohnjiang 
3274418919fSjohnjiang static int
try_write_lcore(__rte_unused void * data)3284418919fSjohnjiang try_write_lcore(__rte_unused void *data)
3294418919fSjohnjiang {
3304418919fSjohnjiang 	int32_t rc;
3314418919fSjohnjiang 	uint32_t i, lc;
3324418919fSjohnjiang 	uint64_t ftm, stm, tm;
3334418919fSjohnjiang 	struct try_rwlock_lcore *lcd;
3344418919fSjohnjiang 
3354418919fSjohnjiang 	lc = rte_lcore_id();
3364418919fSjohnjiang 	lcd = try_lcore_data + lc;
3374418919fSjohnjiang 	lcd->type = LC_TYPE_WRLOCK;
3384418919fSjohnjiang 
3394418919fSjohnjiang 	ftm = try_rwlock_data.tick;
3404418919fSjohnjiang 	stm = rte_get_timer_cycles();
3414418919fSjohnjiang 
3424418919fSjohnjiang 	do {
3434418919fSjohnjiang 		for (i = 0; i != ITER_NUM; i++) {
3444418919fSjohnjiang 			rc = try_write(lc);
3454418919fSjohnjiang 			if (rc == 0)
3464418919fSjohnjiang 				lcd->stat.success++;
3474418919fSjohnjiang 			else if (rc == -EBUSY)
3484418919fSjohnjiang 				lcd->stat.fail++;
3494418919fSjohnjiang 			else
3504418919fSjohnjiang 				break;
3514418919fSjohnjiang 			rc = 0;
3524418919fSjohnjiang 		}
3534418919fSjohnjiang 		tm = rte_get_timer_cycles() - stm;
3544418919fSjohnjiang 	} while (tm < ftm && rc == 0);
3554418919fSjohnjiang 
3564418919fSjohnjiang 	lcd->rc = rc;
3574418919fSjohnjiang 	lcd->stat.tick = tm;
3584418919fSjohnjiang 	return rc;
3594418919fSjohnjiang }
3604418919fSjohnjiang 
3614418919fSjohnjiang static void
print_try_lcore_stats(const struct try_rwlock_lcore * tlc,uint32_t lc)3624418919fSjohnjiang print_try_lcore_stats(const struct try_rwlock_lcore *tlc, uint32_t lc)
3634418919fSjohnjiang {
3644418919fSjohnjiang 	uint64_t f, s;
3654418919fSjohnjiang 
3664418919fSjohnjiang 	f = RTE_MAX(tlc->stat.fail, 1ULL);
3674418919fSjohnjiang 	s = RTE_MAX(tlc->stat.success, 1ULL);
3684418919fSjohnjiang 
3694418919fSjohnjiang 	printf("try_lcore_data[%u]={\n"
3704418919fSjohnjiang 		"\trc=%d,\n"
3714418919fSjohnjiang 		"\ttype=%s,\n"
3724418919fSjohnjiang 		"\tfail=%" PRIu64 ",\n"
3734418919fSjohnjiang 		"\tsuccess=%" PRIu64 ",\n"
3744418919fSjohnjiang 		"\tcycles=%" PRIu64 ",\n"
3754418919fSjohnjiang 		"\tcycles/op=%#Lf,\n"
3764418919fSjohnjiang 		"\tcycles/success=%#Lf,\n"
3774418919fSjohnjiang 		"\tsuccess/fail=%#Lf,\n"
3784418919fSjohnjiang 		"};\n",
3794418919fSjohnjiang 		lc,
3804418919fSjohnjiang 		tlc->rc,
3814418919fSjohnjiang 		tlc->type == LC_TYPE_RDLOCK ? "RDLOCK" : "WRLOCK",
3824418919fSjohnjiang 		tlc->stat.fail,
3834418919fSjohnjiang 		tlc->stat.success,
3844418919fSjohnjiang 		tlc->stat.tick,
3854418919fSjohnjiang 		(long double)tlc->stat.tick /
3864418919fSjohnjiang 		(tlc->stat.fail + tlc->stat.success),
3874418919fSjohnjiang 		(long double)tlc->stat.tick / s,
3884418919fSjohnjiang 		(long double)tlc->stat.success / f);
3894418919fSjohnjiang }
3904418919fSjohnjiang 
3914418919fSjohnjiang static void
collect_try_lcore_stats(struct try_rwlock_lcore * tlc,const struct try_rwlock_lcore * lc)3924418919fSjohnjiang collect_try_lcore_stats(struct try_rwlock_lcore *tlc,
3934418919fSjohnjiang 	const struct try_rwlock_lcore *lc)
3944418919fSjohnjiang {
3954418919fSjohnjiang 	tlc->stat.tick += lc->stat.tick;
3964418919fSjohnjiang 	tlc->stat.fail += lc->stat.fail;
3974418919fSjohnjiang 	tlc->stat.success += lc->stat.success;
3984418919fSjohnjiang }
3994418919fSjohnjiang 
4004418919fSjohnjiang /*
4014418919fSjohnjiang  * Process collected results:
4024418919fSjohnjiang  *  - check status
4034418919fSjohnjiang  *  - collect and print statistics
4044418919fSjohnjiang  */
4054418919fSjohnjiang static int
process_try_lcore_stats(void)4064418919fSjohnjiang process_try_lcore_stats(void)
4074418919fSjohnjiang {
4084418919fSjohnjiang 	int32_t rc;
4094418919fSjohnjiang 	uint32_t lc, rd, wr;
4104418919fSjohnjiang 	struct try_rwlock_lcore rlc, wlc;
4114418919fSjohnjiang 
4124418919fSjohnjiang 	memset(&rlc, 0, sizeof(rlc));
4134418919fSjohnjiang 	memset(&wlc, 0, sizeof(wlc));
4144418919fSjohnjiang 
4154418919fSjohnjiang 	rlc.type = LC_TYPE_RDLOCK;
4164418919fSjohnjiang 	wlc.type = LC_TYPE_WRLOCK;
4174418919fSjohnjiang 	rd = 0;
4184418919fSjohnjiang 	wr = 0;
4194418919fSjohnjiang 
4204418919fSjohnjiang 	rc = 0;
4214418919fSjohnjiang 	RTE_LCORE_FOREACH(lc) {
4224418919fSjohnjiang 		rc |= try_lcore_data[lc].rc;
4234418919fSjohnjiang 		if (try_lcore_data[lc].type == LC_TYPE_RDLOCK) {
4244418919fSjohnjiang 			collect_try_lcore_stats(&rlc, try_lcore_data + lc);
4254418919fSjohnjiang 			rd++;
4264418919fSjohnjiang 		} else {
4274418919fSjohnjiang 			collect_try_lcore_stats(&wlc, try_lcore_data + lc);
4284418919fSjohnjiang 			wr++;
4294418919fSjohnjiang 		}
4304418919fSjohnjiang 	}
4314418919fSjohnjiang 
4324418919fSjohnjiang 	if (rc == 0) {
4334418919fSjohnjiang 		RTE_LCORE_FOREACH(lc)
4344418919fSjohnjiang 			print_try_lcore_stats(try_lcore_data + lc, lc);
4354418919fSjohnjiang 
4364418919fSjohnjiang 		if (rd != 0) {
4374418919fSjohnjiang 			printf("aggregated stats for %u RDLOCK cores:\n", rd);
4384418919fSjohnjiang 			print_try_lcore_stats(&rlc, rd);
4394418919fSjohnjiang 		}
4404418919fSjohnjiang 
4414418919fSjohnjiang 		if (wr != 0) {
4424418919fSjohnjiang 			printf("aggregated stats for %u WRLOCK cores:\n", wr);
4434418919fSjohnjiang 			print_try_lcore_stats(&wlc, wr);
4444418919fSjohnjiang 		}
4454418919fSjohnjiang 	}
4464418919fSjohnjiang 
4474418919fSjohnjiang 	return rc;
4484418919fSjohnjiang }
4494418919fSjohnjiang 
4504418919fSjohnjiang static void
try_test_reset(void)4514418919fSjohnjiang try_test_reset(void)
4524418919fSjohnjiang {
4534418919fSjohnjiang 	memset(&try_lcore_data, 0, sizeof(try_lcore_data));
4544418919fSjohnjiang 	memset(&try_rwlock_data, 0, sizeof(try_rwlock_data));
4554418919fSjohnjiang 	try_rwlock_data.tick = TEST_SEC * rte_get_tsc_hz();
4564418919fSjohnjiang }
4574418919fSjohnjiang 
4584418919fSjohnjiang /* all lcores grab RDLOCK */
4594418919fSjohnjiang static int
try_rwlock_test_rda(void)4604418919fSjohnjiang try_rwlock_test_rda(void)
4614418919fSjohnjiang {
4624418919fSjohnjiang 	try_test_reset();
4634418919fSjohnjiang 
4644418919fSjohnjiang 	/* start read test on all avaialble lcores */
465*2d9fd380Sjfb8856606 	rte_eal_mp_remote_launch(try_read_lcore, NULL, CALL_MAIN);
4664418919fSjohnjiang 	rte_eal_mp_wait_lcore();
4674418919fSjohnjiang 
4684418919fSjohnjiang 	return process_try_lcore_stats();
4694418919fSjohnjiang }
4704418919fSjohnjiang 
471*2d9fd380Sjfb8856606 /* all worker lcores grab RDLOCK, main one grabs WRLOCK */
4724418919fSjohnjiang static int
try_rwlock_test_rds_wrm(void)4734418919fSjohnjiang try_rwlock_test_rds_wrm(void)
4744418919fSjohnjiang {
4754418919fSjohnjiang 	try_test_reset();
4764418919fSjohnjiang 
477*2d9fd380Sjfb8856606 	rte_eal_mp_remote_launch(try_read_lcore, NULL, SKIP_MAIN);
4784418919fSjohnjiang 	try_write_lcore(NULL);
4794418919fSjohnjiang 	rte_eal_mp_wait_lcore();
4804418919fSjohnjiang 
4814418919fSjohnjiang 	return process_try_lcore_stats();
4824418919fSjohnjiang }
4834418919fSjohnjiang 
484*2d9fd380Sjfb8856606 /* main and even worker lcores grab RDLOCK, odd lcores grab WRLOCK */
4854418919fSjohnjiang static int
try_rwlock_test_rde_wro(void)4864418919fSjohnjiang try_rwlock_test_rde_wro(void)
4874418919fSjohnjiang {
4884418919fSjohnjiang 	uint32_t lc, mlc;
4894418919fSjohnjiang 
4904418919fSjohnjiang 	try_test_reset();
4914418919fSjohnjiang 
492*2d9fd380Sjfb8856606 	mlc = rte_get_main_lcore();
4934418919fSjohnjiang 
4944418919fSjohnjiang 	RTE_LCORE_FOREACH(lc) {
4954418919fSjohnjiang 		if (lc != mlc) {
4964418919fSjohnjiang 			if ((lc & 1) == 0)
4974418919fSjohnjiang 				rte_eal_remote_launch(try_read_lcore,
4984418919fSjohnjiang 						NULL, lc);
4994418919fSjohnjiang 			else
5004418919fSjohnjiang 				rte_eal_remote_launch(try_write_lcore,
5014418919fSjohnjiang 						NULL, lc);
5024418919fSjohnjiang 		}
5034418919fSjohnjiang 	}
5044418919fSjohnjiang 	try_read_lcore(NULL);
5054418919fSjohnjiang 	rte_eal_mp_wait_lcore();
5064418919fSjohnjiang 
5074418919fSjohnjiang 	return process_try_lcore_stats();
5084418919fSjohnjiang }
5094418919fSjohnjiang 
5104418919fSjohnjiang static int
test_rwlock(void)5114418919fSjohnjiang test_rwlock(void)
5124418919fSjohnjiang {
5134418919fSjohnjiang 	uint32_t i;
5144418919fSjohnjiang 	int32_t rc, ret;
5154418919fSjohnjiang 
5164418919fSjohnjiang 	static const struct {
5174418919fSjohnjiang 		const char *name;
5184418919fSjohnjiang 		int (*ftst)(void);
5194418919fSjohnjiang 	} test[] = {
5204418919fSjohnjiang 		{
5214418919fSjohnjiang 			.name = "rwlock_test1",
5224418919fSjohnjiang 			.ftst = rwlock_test1,
5234418919fSjohnjiang 		},
5244418919fSjohnjiang 		{
5254418919fSjohnjiang 			.name = "try_rwlock_test_rda",
5264418919fSjohnjiang 			.ftst = try_rwlock_test_rda,
5274418919fSjohnjiang 		},
5284418919fSjohnjiang 		{
5294418919fSjohnjiang 			.name = "try_rwlock_test_rds_wrm",
5304418919fSjohnjiang 			.ftst = try_rwlock_test_rds_wrm,
5314418919fSjohnjiang 		},
5324418919fSjohnjiang 		{
5334418919fSjohnjiang 			.name = "try_rwlock_test_rde_wro",
5344418919fSjohnjiang 			.ftst = try_rwlock_test_rde_wro,
5354418919fSjohnjiang 		},
5364418919fSjohnjiang 	};
5374418919fSjohnjiang 
5384418919fSjohnjiang 	ret = 0;
5394418919fSjohnjiang 	for (i = 0; i != RTE_DIM(test); i++) {
5404418919fSjohnjiang 		printf("starting test %s;\n", test[i].name);
5414418919fSjohnjiang 		rc = test[i].ftst();
5424418919fSjohnjiang 		printf("test %s completed with status %d\n", test[i].name, rc);
5434418919fSjohnjiang 		ret |= rc;
5444418919fSjohnjiang 	}
5454418919fSjohnjiang 
5464418919fSjohnjiang 	return ret;
5474418919fSjohnjiang }
5484418919fSjohnjiang 
5494418919fSjohnjiang REGISTER_TEST_COMMAND(rwlock_autotest, test_rwlock);
5504418919fSjohnjiang 
5514418919fSjohnjiang /* subtests used in meson for CI */
5524418919fSjohnjiang REGISTER_TEST_COMMAND(rwlock_test1_autotest, rwlock_test1);
5534418919fSjohnjiang REGISTER_TEST_COMMAND(rwlock_rda_autotest, try_rwlock_test_rda);
5544418919fSjohnjiang REGISTER_TEST_COMMAND(rwlock_rds_wrm_autotest, try_rwlock_test_rds_wrm);
5554418919fSjohnjiang REGISTER_TEST_COMMAND(rwlock_rde_wro_autotest, try_rwlock_test_rde_wro);
556