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 [ + + ]: 40002 : while (lcount < MAX_LOOP) {
77 [ + + ]: 39998 : if (use_lock)
78 : 29998 : rte_pflock_write_lock(&lk);
79 : 40000 : lcount++;
80 [ + + ]: 40000 : if (use_lock)
81 : 30000 : rte_pflock_write_unlock(&lk);
82 : :
83 [ + + ]: 39998 : 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);
|