dpdk/app/test/test_pflock.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2021 Microsoft Corporation
   3 */
   4
   5#include <stdio.h>
   6#include <stdint.h>
   7#include <inttypes.h>
   8#include <unistd.h>
   9#include <sys/queue.h>
  10#include <string.h>
  11
  12#include <rte_common.h>
  13#include <rte_memory.h>
  14#include <rte_per_lcore.h>
  15#include <rte_launch.h>
  16#include <rte_pflock.h>
  17#include <rte_eal.h>
  18#include <rte_lcore.h>
  19#include <rte_cycles.h>
  20
  21#include "test.h"
  22
  23/*
  24 * phase-fair lock test
  25 * ====================
  26 * Provides UT for phase-fair lock API.
  27 * Main concern is on functional testing, but also provides some
  28 * performance measurements.
  29 * Obviously for proper testing need to be executed with more than one lcore.
  30 */
  31
  32static rte_pflock_t sl;
  33static rte_pflock_t sl_tab[RTE_MAX_LCORE];
  34static uint32_t synchro;
  35
  36static int
  37test_pflock_per_core(__rte_unused void *arg)
  38{
  39        rte_pflock_write_lock(&sl);
  40        printf("Global write lock taken on core %u\n", rte_lcore_id());
  41        rte_pflock_write_unlock(&sl);
  42
  43        rte_pflock_write_lock(&sl_tab[rte_lcore_id()]);
  44        printf("Hello from core %u !\n", rte_lcore_id());
  45        rte_pflock_write_unlock(&sl_tab[rte_lcore_id()]);
  46
  47        rte_pflock_read_lock(&sl);
  48        printf("Global read lock taken on core %u\n", rte_lcore_id());
  49        rte_delay_ms(100);
  50        printf("Release global read lock on core %u\n", rte_lcore_id());
  51        rte_pflock_read_unlock(&sl);
  52
  53        return 0;
  54}
  55
  56static rte_pflock_t lk = RTE_PFLOCK_INITIALIZER;
  57static uint64_t time_count[RTE_MAX_LCORE] = {0};
  58
  59#define MAX_LOOP 10000
  60
  61static int
  62load_loop_fn(void *arg)
  63{
  64        uint64_t time_diff = 0, begin;
  65        uint64_t hz = rte_get_timer_hz();
  66        uint64_t lcount = 0;
  67        const int use_lock = *(int *)arg;
  68        const unsigned int lcore = rte_lcore_id();
  69
  70        /* wait synchro for workers */
  71        if (lcore != rte_get_main_lcore())
  72                rte_wait_until_equal_32(&synchro, 1, __ATOMIC_RELAXED);
  73
  74        begin = rte_rdtsc_precise();
  75        while (lcount < MAX_LOOP) {
  76                if (use_lock)
  77                        rte_pflock_write_lock(&lk);
  78                lcount++;
  79                if (use_lock)
  80                        rte_pflock_write_unlock(&lk);
  81
  82                if (use_lock) {
  83                        rte_pflock_read_lock(&lk);
  84                        rte_pflock_read_unlock(&lk);
  85                }
  86        }
  87
  88        time_diff = rte_rdtsc_precise() - begin;
  89        time_count[lcore] = time_diff * 1000000 / hz;
  90        return 0;
  91}
  92
  93static int
  94test_pflock_perf(void)
  95{
  96        unsigned int i;
  97        int lock = 0;
  98        uint64_t total = 0;
  99        const unsigned int lcore = rte_lcore_id();
 100
 101        printf("\nTest with no lock on single core...\n");
 102        __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
 103        load_loop_fn(&lock);
 104        printf("Core [%u] Cost Time = %"PRIu64" us\n",
 105                        lcore, time_count[lcore]);
 106        memset(time_count, 0, sizeof(time_count));
 107
 108        printf("\nTest with phase-fair lock on single core...\n");
 109        lock = 1;
 110        __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
 111        load_loop_fn(&lock);
 112        printf("Core [%u] Cost Time = %"PRIu64" us\n",
 113                        lcore, time_count[lcore]);
 114        memset(time_count, 0, sizeof(time_count));
 115
 116        printf("\nPhase-fair test on %u cores...\n", rte_lcore_count());
 117
 118        /* clear synchro and start workers */
 119        __atomic_store_n(&synchro, 0, __ATOMIC_RELAXED);
 120        if (rte_eal_mp_remote_launch(load_loop_fn, &lock, SKIP_MAIN) < 0)
 121                return -1;
 122
 123        /* start synchro and launch test on main */
 124        __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
 125        load_loop_fn(&lock);
 126
 127        rte_eal_mp_wait_lcore();
 128
 129        RTE_LCORE_FOREACH(i) {
 130                printf("Core [%u] cost time = %"PRIu64" us\n",
 131                        i, time_count[i]);
 132                total += time_count[i];
 133        }
 134
 135        printf("Total cost time = %"PRIu64" us\n", total);
 136        memset(time_count, 0, sizeof(time_count));
 137
 138        return 0;
 139}
 140
 141/*
 142 * - There is a global pflock and a table of pflocks (one per lcore).
 143 *
 144 * - The test function takes all of these locks and launches the
 145 *   ``test_pflock_per_core()`` function on each core (except the main).
 146 *
 147 *   - The function takes the global write lock, display something,
 148 *     then releases the global lock.
 149 *   - Then, it takes the per-lcore write lock, display something, and
 150 *     releases the per-core lock.
 151 *   - Finally, a read lock is taken during 100 ms, then released.
 152 *
 153 * - The main function unlocks the per-lcore locks sequentially and
 154 *   waits between each lock. This triggers the display of a message
 155 *   for each core, in the correct order.
 156 *
 157 *   Then, it tries to take the global write lock and display the last
 158 *   message. The autotest script checks that the message order is correct.
 159 */
 160static int
 161test_pflock(void)
 162{
 163        int i;
 164
 165        rte_pflock_init(&sl);
 166        for (i = 0; i < RTE_MAX_LCORE; i++)
 167                rte_pflock_init(&sl_tab[i]);
 168
 169        rte_pflock_write_lock(&sl);
 170
 171        RTE_LCORE_FOREACH_WORKER(i) {
 172                rte_pflock_write_lock(&sl_tab[i]);
 173                rte_eal_remote_launch(test_pflock_per_core, NULL, i);
 174        }
 175
 176        rte_pflock_write_unlock(&sl);
 177
 178        RTE_LCORE_FOREACH_WORKER(i) {
 179                rte_pflock_write_unlock(&sl_tab[i]);
 180                rte_delay_ms(100);
 181        }
 182
 183        rte_pflock_write_lock(&sl);
 184        /* this message should be the last message of test */
 185        printf("Global write lock taken on main core %u\n", rte_lcore_id());
 186        rte_pflock_write_unlock(&sl);
 187
 188        rte_eal_mp_wait_lcore();
 189
 190        if (test_pflock_perf() < 0)
 191                return -1;
 192
 193        return 0;
 194}
 195
 196REGISTER_TEST_COMMAND(pflock_autotest, test_pflock);
 197