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 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(&synchro, 1, __ATOMIC_RELAXED);
73 : :
74 : : begin = rte_rdtsc_precise();
75 [ + + ]: 39564 : while (lcount < MAX_LOOP) {
76 [ + + ]: 39560 : if (use_lock)
77 : 29561 : rte_pflock_write_lock(&lk);
78 : 39999 : lcount++;
79 [ + + ]: 39999 : if (use_lock)
80 : 30000 : rte_pflock_write_unlock(&lk);
81 : :
82 [ + + ]: 40290 : if (use_lock) {
83 : 30000 : rte_pflock_read_lock(&lk);
84 : : rte_pflock_read_unlock(&lk);
85 : : }
86 : : }
87 : :
88 : 4 : time_diff = rte_rdtsc_precise() - begin;
89 : 4 : time_count[lcore] = time_diff * 1000000 / hz;
90 : 4 : return 0;
91 : : }
92 : :
93 : : static int
94 : 1 : test_pflock_perf(void)
95 : : {
96 : : unsigned int i;
97 : 1 : 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 : 1 : __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
103 : 1 : load_loop_fn(&lock);
104 : 1 : 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 : 1 : lock = 1;
110 : 1 : __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
111 : 1 : load_loop_fn(&lock);
112 : 2 : printf("Core [%u] Cost Time = %"PRIu64" us\n",
113 : : lcore, time_count[lcore]);
114 : : memset(time_count, 0, sizeof(time_count));
115 : :
116 : 1 : printf("\nPhase-fair test on %u cores...\n", rte_lcore_count());
117 : :
118 : : /* clear synchro and start workers */
119 : 1 : __atomic_store_n(&synchro, 0, __ATOMIC_RELAXED);
120 [ + - ]: 1 : 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 : 1 : __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
125 : 1 : load_loop_fn(&lock);
126 : :
127 : 1 : rte_eal_mp_wait_lcore();
128 : :
129 [ + + ]: 3 : RTE_LCORE_FOREACH(i) {
130 : 2 : printf("Core [%u] cost time = %"PRIu64" us\n",
131 : : i, time_count[i]);
132 : 2 : 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 : 1 : 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 : : */
160 : : static int
161 : 1 : test_pflock(void)
162 : : {
163 : : int i;
164 : :
165 : : rte_pflock_init(&sl);
166 [ + + ]: 129 : for (i = 0; i < RTE_MAX_LCORE; i++)
167 : : rte_pflock_init(&sl_tab[i]);
168 : :
169 : 1 : rte_pflock_write_lock(&sl);
170 : :
171 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(i) {
172 : 1 : rte_pflock_write_lock(&sl_tab[i]);
173 : 1 : rte_eal_remote_launch(test_pflock_per_core, NULL, i);
174 : : }
175 : :
176 : 1 : rte_pflock_write_unlock(&sl);
177 : :
178 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(i) {
179 : 1 : rte_pflock_write_unlock(&sl_tab[i]);
180 : : rte_delay_ms(100);
181 : : }
182 : :
183 : 1 : 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 : 1 : rte_pflock_write_unlock(&sl);
187 : :
188 : 1 : rte_eal_mp_wait_lcore();
189 : :
190 [ - + ]: 1 : if (test_pflock_perf() < 0)
191 : 0 : return -1;
192 : :
193 : : return 0;
194 : : }
195 : :
196 : 235 : REGISTER_FAST_TEST(pflock_autotest, true, true, test_pflock);
|