xref: /dpdk/app/test/test_pflock.c (revision b6a7e6852e9ab82ae0e05e2d2a0b83abca17de3b)
19667d97cSStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
29667d97cSStephen Hemminger  * Copyright(c) 2021 Microsoft Corporation
39667d97cSStephen Hemminger  */
49667d97cSStephen Hemminger 
59667d97cSStephen Hemminger #include <stdio.h>
69667d97cSStephen Hemminger #include <stdint.h>
79667d97cSStephen Hemminger #include <inttypes.h>
89667d97cSStephen Hemminger #include <unistd.h>
99667d97cSStephen Hemminger #include <sys/queue.h>
109667d97cSStephen Hemminger #include <string.h>
119667d97cSStephen Hemminger 
129667d97cSStephen Hemminger #include <rte_common.h>
139667d97cSStephen Hemminger #include <rte_memory.h>
149667d97cSStephen Hemminger #include <rte_per_lcore.h>
159667d97cSStephen Hemminger #include <rte_launch.h>
169667d97cSStephen Hemminger #include <rte_pflock.h>
179667d97cSStephen Hemminger #include <rte_eal.h>
189667d97cSStephen Hemminger #include <rte_lcore.h>
199667d97cSStephen Hemminger #include <rte_cycles.h>
209667d97cSStephen Hemminger 
219667d97cSStephen Hemminger #include "test.h"
229667d97cSStephen Hemminger 
239667d97cSStephen Hemminger /*
249667d97cSStephen Hemminger  * phase-fair lock test
259667d97cSStephen Hemminger  * ====================
269667d97cSStephen Hemminger  * Provides UT for phase-fair lock API.
279667d97cSStephen Hemminger  * Main concern is on functional testing, but also provides some
289667d97cSStephen Hemminger  * performance measurements.
299667d97cSStephen Hemminger  * Obviously for proper testing need to be executed with more than one lcore.
309667d97cSStephen Hemminger  */
319667d97cSStephen Hemminger 
329667d97cSStephen Hemminger static rte_pflock_t sl;
339667d97cSStephen Hemminger static rte_pflock_t sl_tab[RTE_MAX_LCORE];
34*b6a7e685STyler Retzlaff static RTE_ATOMIC(uint32_t) synchro;
359667d97cSStephen Hemminger 
369667d97cSStephen Hemminger static int
test_pflock_per_core(__rte_unused void * arg)379667d97cSStephen Hemminger test_pflock_per_core(__rte_unused void *arg)
389667d97cSStephen Hemminger {
399667d97cSStephen Hemminger 	rte_pflock_write_lock(&sl);
409667d97cSStephen Hemminger 	printf("Global write lock taken on core %u\n", rte_lcore_id());
419667d97cSStephen Hemminger 	rte_pflock_write_unlock(&sl);
429667d97cSStephen Hemminger 
439667d97cSStephen Hemminger 	rte_pflock_write_lock(&sl_tab[rte_lcore_id()]);
449667d97cSStephen Hemminger 	printf("Hello from core %u !\n", rte_lcore_id());
459667d97cSStephen Hemminger 	rte_pflock_write_unlock(&sl_tab[rte_lcore_id()]);
469667d97cSStephen Hemminger 
479667d97cSStephen Hemminger 	rte_pflock_read_lock(&sl);
489667d97cSStephen Hemminger 	printf("Global read lock taken on core %u\n", rte_lcore_id());
499667d97cSStephen Hemminger 	rte_delay_ms(100);
509667d97cSStephen Hemminger 	printf("Release global read lock on core %u\n", rte_lcore_id());
519667d97cSStephen Hemminger 	rte_pflock_read_unlock(&sl);
529667d97cSStephen Hemminger 
539667d97cSStephen Hemminger 	return 0;
549667d97cSStephen Hemminger }
559667d97cSStephen Hemminger 
569667d97cSStephen Hemminger static rte_pflock_t lk = RTE_PFLOCK_INITIALIZER;
579667d97cSStephen Hemminger static uint64_t time_count[RTE_MAX_LCORE] = {0};
589667d97cSStephen Hemminger 
599667d97cSStephen Hemminger #define MAX_LOOP 10000
609667d97cSStephen Hemminger 
619667d97cSStephen Hemminger static int
load_loop_fn(void * arg)629667d97cSStephen Hemminger load_loop_fn(void *arg)
639667d97cSStephen Hemminger {
649667d97cSStephen Hemminger 	uint64_t time_diff = 0, begin;
659667d97cSStephen Hemminger 	uint64_t hz = rte_get_timer_hz();
669667d97cSStephen Hemminger 	uint64_t lcount = 0;
679667d97cSStephen Hemminger 	const int use_lock = *(int *)arg;
689667d97cSStephen Hemminger 	const unsigned int lcore = rte_lcore_id();
699667d97cSStephen Hemminger 
709667d97cSStephen Hemminger 	/* wait synchro for workers */
719667d97cSStephen Hemminger 	if (lcore != rte_get_main_lcore())
72*b6a7e685STyler Retzlaff 		rte_wait_until_equal_32((uint32_t *)(uintptr_t)&synchro, 1,
73*b6a7e685STyler Retzlaff 				rte_memory_order_relaxed);
749667d97cSStephen Hemminger 
759667d97cSStephen Hemminger 	begin = rte_rdtsc_precise();
769667d97cSStephen Hemminger 	while (lcount < MAX_LOOP) {
779667d97cSStephen Hemminger 		if (use_lock)
789667d97cSStephen Hemminger 			rte_pflock_write_lock(&lk);
799667d97cSStephen Hemminger 		lcount++;
809667d97cSStephen Hemminger 		if (use_lock)
819667d97cSStephen Hemminger 			rte_pflock_write_unlock(&lk);
829667d97cSStephen Hemminger 
839667d97cSStephen Hemminger 		if (use_lock) {
849667d97cSStephen Hemminger 			rte_pflock_read_lock(&lk);
859667d97cSStephen Hemminger 			rte_pflock_read_unlock(&lk);
869667d97cSStephen Hemminger 		}
879667d97cSStephen Hemminger 	}
889667d97cSStephen Hemminger 
899667d97cSStephen Hemminger 	time_diff = rte_rdtsc_precise() - begin;
909667d97cSStephen Hemminger 	time_count[lcore] = time_diff * 1000000 / hz;
919667d97cSStephen Hemminger 	return 0;
929667d97cSStephen Hemminger }
939667d97cSStephen Hemminger 
949667d97cSStephen Hemminger static int
test_pflock_perf(void)959667d97cSStephen Hemminger test_pflock_perf(void)
969667d97cSStephen Hemminger {
979667d97cSStephen Hemminger 	unsigned int i;
989667d97cSStephen Hemminger 	int lock = 0;
999667d97cSStephen Hemminger 	uint64_t total = 0;
1009667d97cSStephen Hemminger 	const unsigned int lcore = rte_lcore_id();
1019667d97cSStephen Hemminger 
1029667d97cSStephen Hemminger 	printf("\nTest with no lock on single core...\n");
103*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
1049667d97cSStephen Hemminger 	load_loop_fn(&lock);
1059667d97cSStephen Hemminger 	printf("Core [%u] Cost Time = %"PRIu64" us\n",
1069667d97cSStephen Hemminger 			lcore, time_count[lcore]);
1079667d97cSStephen Hemminger 	memset(time_count, 0, sizeof(time_count));
1089667d97cSStephen Hemminger 
1099667d97cSStephen Hemminger 	printf("\nTest with phase-fair lock on single core...\n");
1109667d97cSStephen Hemminger 	lock = 1;
111*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
1129667d97cSStephen Hemminger 	load_loop_fn(&lock);
1139667d97cSStephen Hemminger 	printf("Core [%u] Cost Time = %"PRIu64" us\n",
1149667d97cSStephen Hemminger 			lcore, time_count[lcore]);
1159667d97cSStephen Hemminger 	memset(time_count, 0, sizeof(time_count));
1169667d97cSStephen Hemminger 
1179667d97cSStephen Hemminger 	printf("\nPhase-fair test on %u cores...\n", rte_lcore_count());
1189667d97cSStephen Hemminger 
1199667d97cSStephen Hemminger 	/* clear synchro and start workers */
120*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&synchro, 0, rte_memory_order_relaxed);
1219667d97cSStephen Hemminger 	if (rte_eal_mp_remote_launch(load_loop_fn, &lock, SKIP_MAIN) < 0)
1229667d97cSStephen Hemminger 		return -1;
1239667d97cSStephen Hemminger 
1249667d97cSStephen Hemminger 	/* start synchro and launch test on main */
125*b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
1269667d97cSStephen Hemminger 	load_loop_fn(&lock);
1279667d97cSStephen Hemminger 
1289667d97cSStephen Hemminger 	rte_eal_mp_wait_lcore();
1299667d97cSStephen Hemminger 
1309667d97cSStephen Hemminger 	RTE_LCORE_FOREACH(i) {
1319667d97cSStephen Hemminger 		printf("Core [%u] cost time = %"PRIu64" us\n",
1329667d97cSStephen Hemminger 			i, time_count[i]);
1339667d97cSStephen Hemminger 		total += time_count[i];
1349667d97cSStephen Hemminger 	}
1359667d97cSStephen Hemminger 
1369667d97cSStephen Hemminger 	printf("Total cost time = %"PRIu64" us\n", total);
1379667d97cSStephen Hemminger 	memset(time_count, 0, sizeof(time_count));
1389667d97cSStephen Hemminger 
1399667d97cSStephen Hemminger 	return 0;
1409667d97cSStephen Hemminger }
1419667d97cSStephen Hemminger 
1429667d97cSStephen Hemminger /*
1439667d97cSStephen Hemminger  * - There is a global pflock and a table of pflocks (one per lcore).
1449667d97cSStephen Hemminger  *
1459667d97cSStephen Hemminger  * - The test function takes all of these locks and launches the
1469667d97cSStephen Hemminger  *   ``test_pflock_per_core()`` function on each core (except the main).
1479667d97cSStephen Hemminger  *
1489667d97cSStephen Hemminger  *   - The function takes the global write lock, display something,
1499667d97cSStephen Hemminger  *     then releases the global lock.
1509667d97cSStephen Hemminger  *   - Then, it takes the per-lcore write lock, display something, and
1519667d97cSStephen Hemminger  *     releases the per-core lock.
1529667d97cSStephen Hemminger  *   - Finally, a read lock is taken during 100 ms, then released.
1539667d97cSStephen Hemminger  *
1549667d97cSStephen Hemminger  * - The main function unlocks the per-lcore locks sequentially and
1559667d97cSStephen Hemminger  *   waits between each lock. This triggers the display of a message
1569667d97cSStephen Hemminger  *   for each core, in the correct order.
1579667d97cSStephen Hemminger  *
1589667d97cSStephen Hemminger  *   Then, it tries to take the global write lock and display the last
1599667d97cSStephen Hemminger  *   message. The autotest script checks that the message order is correct.
1609667d97cSStephen Hemminger  */
1619667d97cSStephen Hemminger static int
test_pflock(void)1629667d97cSStephen Hemminger test_pflock(void)
1639667d97cSStephen Hemminger {
1649667d97cSStephen Hemminger 	int i;
1659667d97cSStephen Hemminger 
1669667d97cSStephen Hemminger 	rte_pflock_init(&sl);
1679667d97cSStephen Hemminger 	for (i = 0; i < RTE_MAX_LCORE; i++)
1689667d97cSStephen Hemminger 		rte_pflock_init(&sl_tab[i]);
1699667d97cSStephen Hemminger 
1709667d97cSStephen Hemminger 	rte_pflock_write_lock(&sl);
1719667d97cSStephen Hemminger 
1729667d97cSStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
1739667d97cSStephen Hemminger 		rte_pflock_write_lock(&sl_tab[i]);
1749667d97cSStephen Hemminger 		rte_eal_remote_launch(test_pflock_per_core, NULL, i);
1759667d97cSStephen Hemminger 	}
1769667d97cSStephen Hemminger 
1779667d97cSStephen Hemminger 	rte_pflock_write_unlock(&sl);
1789667d97cSStephen Hemminger 
1799667d97cSStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
1809667d97cSStephen Hemminger 		rte_pflock_write_unlock(&sl_tab[i]);
1819667d97cSStephen Hemminger 		rte_delay_ms(100);
1829667d97cSStephen Hemminger 	}
1839667d97cSStephen Hemminger 
1849667d97cSStephen Hemminger 	rte_pflock_write_lock(&sl);
1859667d97cSStephen Hemminger 	/* this message should be the last message of test */
1869667d97cSStephen Hemminger 	printf("Global write lock taken on main core %u\n", rte_lcore_id());
1879667d97cSStephen Hemminger 	rte_pflock_write_unlock(&sl);
1889667d97cSStephen Hemminger 
1899667d97cSStephen Hemminger 	rte_eal_mp_wait_lcore();
1909667d97cSStephen Hemminger 
1919667d97cSStephen Hemminger 	if (test_pflock_perf() < 0)
1929667d97cSStephen Hemminger 		return -1;
1939667d97cSStephen Hemminger 
1949667d97cSStephen Hemminger 	return 0;
1959667d97cSStephen Hemminger }
1969667d97cSStephen Hemminger 
197e0a8442cSBruce Richardson REGISTER_FAST_TEST(pflock_autotest, true, true, test_pflock);
198