LCOV - code coverage report
Current view: top level - app/test - test_pflock.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 54 55 98.2 %
Date: 2025-03-01 20:23:48 Functions: 5 5 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 20 22 90.9 %

           Branch data     Line data    Source code
       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                 :            : 
      32                 :            : static rte_pflock_t sl;
      33                 :            : static rte_pflock_t sl_tab[RTE_MAX_LCORE];
      34                 :            : static RTE_ATOMIC(uint32_t) synchro;
      35                 :            : 
      36                 :            : static int
      37                 :          1 : test_pflock_per_core(__rte_unused void *arg)
      38                 :            : {
      39                 :          1 :         rte_pflock_write_lock(&sl);
      40                 :            :         printf("Global write lock taken on core %u\n", rte_lcore_id());
      41                 :          1 :         rte_pflock_write_unlock(&sl);
      42                 :            : 
      43                 :          1 :         rte_pflock_write_lock(&sl_tab[rte_lcore_id()]);
      44                 :            :         printf("Hello from core %u !\n", rte_lcore_id());
      45                 :          1 :         rte_pflock_write_unlock(&sl_tab[rte_lcore_id()]);
      46                 :            : 
      47                 :          1 :         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                 :          1 :         return 0;
      54                 :            : }
      55                 :            : 
      56                 :            : static rte_pflock_t lk = RTE_PFLOCK_INITIALIZER;
      57                 :            : static uint64_t time_count[RTE_MAX_LCORE] = {0};
      58                 :            : 
      59                 :            : #define MAX_LOOP 10000
      60                 :            : 
      61                 :            : static int
      62                 :          4 : load_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                 :          4 :         const int use_lock = *(int *)arg;
      68                 :            :         const unsigned int lcore = rte_lcore_id();
      69                 :            : 
      70                 :            :         /* wait synchro for workers */
      71         [ +  + ]:          4 :         if (lcore != rte_get_main_lcore())
      72                 :            :                 rte_wait_until_equal_32((uint32_t *)(uintptr_t)&synchro, 1,
      73                 :            :                                 rte_memory_order_relaxed);
      74                 :            : 
      75                 :            :         begin = rte_rdtsc_precise();
      76         [ +  + ]:      39699 :         while (lcount < MAX_LOOP) {
      77         [ +  + ]:      39695 :                 if (use_lock)
      78                 :      29696 :                         rte_pflock_write_lock(&lk);
      79                 :      39999 :                 lcount++;
      80         [ +  + ]:      39999 :                 if (use_lock)
      81                 :      30000 :                         rte_pflock_write_unlock(&lk);
      82                 :            : 
      83         [ +  + ]:      40043 :                 if (use_lock) {
      84                 :      30000 :                         rte_pflock_read_lock(&lk);
      85                 :            :                         rte_pflock_read_unlock(&lk);
      86                 :            :                 }
      87                 :            :         }
      88                 :            : 
      89                 :          4 :         time_diff = rte_rdtsc_precise() - begin;
      90                 :          4 :         time_count[lcore] = time_diff * 1000000 / hz;
      91                 :          4 :         return 0;
      92                 :            : }
      93                 :            : 
      94                 :            : static int
      95                 :          1 : test_pflock_perf(void)
      96                 :            : {
      97                 :            :         unsigned int i;
      98                 :          1 :         int lock = 0;
      99                 :            :         uint64_t total = 0;
     100                 :            :         const unsigned int lcore = rte_lcore_id();
     101                 :            : 
     102                 :            :         printf("\nTest with no lock on single core...\n");
     103                 :          1 :         rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
     104                 :          1 :         load_loop_fn(&lock);
     105                 :          1 :         printf("Core [%u] Cost Time = %"PRIu64" us\n",
     106                 :            :                         lcore, time_count[lcore]);
     107                 :            :         memset(time_count, 0, sizeof(time_count));
     108                 :            : 
     109                 :            :         printf("\nTest with phase-fair lock on single core...\n");
     110                 :          1 :         lock = 1;
     111                 :          1 :         rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
     112                 :          1 :         load_loop_fn(&lock);
     113                 :          1 :         printf("Core [%u] Cost Time = %"PRIu64" us\n",
     114                 :            :                         lcore, time_count[lcore]);
     115                 :            :         memset(time_count, 0, sizeof(time_count));
     116                 :            : 
     117                 :          1 :         printf("\nPhase-fair test on %u cores...\n", rte_lcore_count());
     118                 :            : 
     119                 :            :         /* clear synchro and start workers */
     120                 :          1 :         rte_atomic_store_explicit(&synchro, 0, rte_memory_order_relaxed);
     121         [ +  - ]:          1 :         if (rte_eal_mp_remote_launch(load_loop_fn, &lock, SKIP_MAIN) < 0)
     122                 :            :                 return -1;
     123                 :            : 
     124                 :            :         /* start synchro and launch test on main */
     125                 :          1 :         rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
     126                 :          1 :         load_loop_fn(&lock);
     127                 :            : 
     128                 :          1 :         rte_eal_mp_wait_lcore();
     129                 :            : 
     130         [ +  + ]:          3 :         RTE_LCORE_FOREACH(i) {
     131                 :          2 :                 printf("Core [%u] cost time = %"PRIu64" us\n",
     132                 :            :                         i, time_count[i]);
     133                 :          2 :                 total += time_count[i];
     134                 :            :         }
     135                 :            : 
     136                 :            :         printf("Total cost time = %"PRIu64" us\n", total);
     137                 :            :         memset(time_count, 0, sizeof(time_count));
     138                 :            : 
     139                 :          1 :         return 0;
     140                 :            : }
     141                 :            : 
     142                 :            : /*
     143                 :            :  * - There is a global pflock and a table of pflocks (one per lcore).
     144                 :            :  *
     145                 :            :  * - The test function takes all of these locks and launches the
     146                 :            :  *   ``test_pflock_per_core()`` function on each core (except the main).
     147                 :            :  *
     148                 :            :  *   - The function takes the global write lock, display something,
     149                 :            :  *     then releases the global lock.
     150                 :            :  *   - Then, it takes the per-lcore write lock, display something, and
     151                 :            :  *     releases the per-core lock.
     152                 :            :  *   - Finally, a read lock is taken during 100 ms, then released.
     153                 :            :  *
     154                 :            :  * - The main function unlocks the per-lcore locks sequentially and
     155                 :            :  *   waits between each lock. This triggers the display of a message
     156                 :            :  *   for each core, in the correct order.
     157                 :            :  *
     158                 :            :  *   Then, it tries to take the global write lock and display the last
     159                 :            :  *   message. The autotest script checks that the message order is correct.
     160                 :            :  */
     161                 :            : static int
     162                 :          1 : test_pflock(void)
     163                 :            : {
     164                 :            :         int i;
     165                 :            : 
     166                 :            :         rte_pflock_init(&sl);
     167         [ +  + ]:        129 :         for (i = 0; i < RTE_MAX_LCORE; i++)
     168                 :            :                 rte_pflock_init(&sl_tab[i]);
     169                 :            : 
     170                 :          1 :         rte_pflock_write_lock(&sl);
     171                 :            : 
     172         [ +  + ]:          2 :         RTE_LCORE_FOREACH_WORKER(i) {
     173                 :          1 :                 rte_pflock_write_lock(&sl_tab[i]);
     174                 :          1 :                 rte_eal_remote_launch(test_pflock_per_core, NULL, i);
     175                 :            :         }
     176                 :            : 
     177                 :          1 :         rte_pflock_write_unlock(&sl);
     178                 :            : 
     179         [ +  + ]:          2 :         RTE_LCORE_FOREACH_WORKER(i) {
     180                 :          1 :                 rte_pflock_write_unlock(&sl_tab[i]);
     181                 :            :                 rte_delay_ms(100);
     182                 :            :         }
     183                 :            : 
     184                 :          1 :         rte_pflock_write_lock(&sl);
     185                 :            :         /* this message should be the last message of test */
     186                 :            :         printf("Global write lock taken on main core %u\n", rte_lcore_id());
     187                 :          1 :         rte_pflock_write_unlock(&sl);
     188                 :            : 
     189                 :          1 :         rte_eal_mp_wait_lcore();
     190                 :            : 
     191         [ -  + ]:          1 :         if (test_pflock_perf() < 0)
     192                 :          0 :                 return -1;
     193                 :            : 
     194                 :            :         return 0;
     195                 :            : }
     196                 :            : 
     197                 :        252 : REGISTER_FAST_TEST(pflock_autotest, true, true, test_pflock);

Generated by: LCOV version 1.14