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