1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
3a9de470cSBruce Richardson */
4a9de470cSBruce Richardson
5a9de470cSBruce Richardson #include <stdio.h>
6a9de470cSBruce Richardson #include <stdint.h>
7a9de470cSBruce Richardson #include <inttypes.h>
8a9de470cSBruce Richardson #include <unistd.h>
9a9de470cSBruce Richardson #include <sys/queue.h>
10a9de470cSBruce Richardson #include <string.h>
11a9de470cSBruce Richardson
12a9de470cSBruce Richardson #include <rte_common.h>
13a9de470cSBruce Richardson #include <rte_memory.h>
14a9de470cSBruce Richardson #include <rte_per_lcore.h>
15a9de470cSBruce Richardson #include <rte_launch.h>
16a9de470cSBruce Richardson #include <rte_rwlock.h>
17a9de470cSBruce Richardson #include <rte_eal.h>
18a9de470cSBruce Richardson #include <rte_lcore.h>
19a9de470cSBruce Richardson #include <rte_cycles.h>
20a9de470cSBruce Richardson
21a9de470cSBruce Richardson #include "test.h"
22a9de470cSBruce Richardson
23a9de470cSBruce Richardson /*
24a9de470cSBruce Richardson * rwlock test
25a9de470cSBruce Richardson * ===========
26a9de470cSBruce Richardson * Provides UT for rte_rwlock API.
27a9de470cSBruce Richardson * Main concern is on functional testing, but also provides some
28a9de470cSBruce Richardson * performance measurements.
29a9de470cSBruce Richardson * Obviously for proper testing need to be executed with more than one lcore.
30a9de470cSBruce Richardson */
31a9de470cSBruce Richardson
32a9de470cSBruce Richardson #define ITER_NUM 0x80
33a9de470cSBruce Richardson
34a9de470cSBruce Richardson #define TEST_SEC 5
35a9de470cSBruce Richardson
36a9de470cSBruce Richardson static rte_rwlock_t sl;
37a9de470cSBruce Richardson static rte_rwlock_t sl_tab[RTE_MAX_LCORE];
38*b6a7e685STyler Retzlaff static RTE_ATOMIC(uint32_t) synchro;
39a9de470cSBruce Richardson
40a9de470cSBruce Richardson enum {
41a9de470cSBruce Richardson LC_TYPE_RDLOCK,
42a9de470cSBruce Richardson LC_TYPE_WRLOCK,
43a9de470cSBruce Richardson };
44a9de470cSBruce Richardson
450efea35aSTyler Retzlaff static alignas(RTE_CACHE_LINE_SIZE) struct {
46a9de470cSBruce Richardson rte_rwlock_t lock;
47a9de470cSBruce Richardson uint64_t tick;
4814df4f29SStephen Hemminger
49a9de470cSBruce Richardson volatile union {
50a9de470cSBruce Richardson uint8_t u8[RTE_CACHE_LINE_SIZE];
51a9de470cSBruce Richardson uint64_t u64[RTE_CACHE_LINE_SIZE / sizeof(uint64_t)];
52a9de470cSBruce Richardson } data;
530efea35aSTyler Retzlaff } try_rwlock_data;
54a9de470cSBruce Richardson
550efea35aSTyler Retzlaff struct __rte_cache_aligned try_rwlock_lcore {
56a9de470cSBruce Richardson int32_t rc;
57a9de470cSBruce Richardson int32_t type;
58a9de470cSBruce Richardson struct {
59a9de470cSBruce Richardson uint64_t tick;
60a9de470cSBruce Richardson uint64_t fail;
61a9de470cSBruce Richardson uint64_t success;
62a9de470cSBruce Richardson } stat;
630efea35aSTyler Retzlaff };
64a9de470cSBruce Richardson
65a9de470cSBruce Richardson static struct try_rwlock_lcore try_lcore_data[RTE_MAX_LCORE];
66a9de470cSBruce Richardson
67a9de470cSBruce Richardson static int
test_rwlock_per_core(__rte_unused void * arg)68f2fc83b4SThomas Monjalon test_rwlock_per_core(__rte_unused void *arg)
69a9de470cSBruce Richardson {
70a9de470cSBruce Richardson rte_rwlock_write_lock(&sl);
71a9de470cSBruce Richardson printf("Global write lock taken on core %u\n", rte_lcore_id());
72a9de470cSBruce Richardson rte_rwlock_write_unlock(&sl);
73a9de470cSBruce Richardson
74a9de470cSBruce Richardson rte_rwlock_write_lock(&sl_tab[rte_lcore_id()]);
75a9de470cSBruce Richardson printf("Hello from core %u !\n", rte_lcore_id());
76a9de470cSBruce Richardson rte_rwlock_write_unlock(&sl_tab[rte_lcore_id()]);
77a9de470cSBruce Richardson
78a9de470cSBruce Richardson rte_rwlock_read_lock(&sl);
79a9de470cSBruce Richardson printf("Global read lock taken on core %u\n", rte_lcore_id());
80a9de470cSBruce Richardson rte_delay_ms(100);
81a9de470cSBruce Richardson printf("Release global read lock on core %u\n", rte_lcore_id());
82a9de470cSBruce Richardson rte_rwlock_read_unlock(&sl);
83a9de470cSBruce Richardson
84a9de470cSBruce Richardson return 0;
85a9de470cSBruce Richardson }
86a9de470cSBruce Richardson
87fe252fb6SJoyce Kong static rte_rwlock_t lk = RTE_RWLOCK_INITIALIZER;
88fe252fb6SJoyce Kong static volatile uint64_t rwlock_data;
896fef1ae4SJoyce Kong static uint64_t time_count[RTE_MAX_LCORE] = {0};
90fe252fb6SJoyce Kong
916fef1ae4SJoyce Kong #define MAX_LOOP 10000
92fe252fb6SJoyce Kong #define TEST_RWLOCK_DEBUG 0
93fe252fb6SJoyce Kong
94fe252fb6SJoyce Kong static int
load_loop_fn(__rte_unused void * arg)95f2fc83b4SThomas Monjalon load_loop_fn(__rte_unused void *arg)
96fe252fb6SJoyce Kong {
97fe252fb6SJoyce Kong uint64_t time_diff = 0, begin;
98fe252fb6SJoyce Kong uint64_t hz = rte_get_timer_hz();
99fe252fb6SJoyce Kong uint64_t lcount = 0;
100fe252fb6SJoyce Kong const unsigned int lcore = rte_lcore_id();
101fe252fb6SJoyce Kong
102cb056611SStephen Hemminger /* wait synchro for workers */
103cb056611SStephen Hemminger if (lcore != rte_get_main_lcore())
104*b6a7e685STyler Retzlaff rte_wait_until_equal_32((uint32_t *)(uintptr_t)&synchro, 1,
105*b6a7e685STyler Retzlaff rte_memory_order_relaxed);
106fe252fb6SJoyce Kong
107fe252fb6SJoyce Kong begin = rte_rdtsc_precise();
1086fef1ae4SJoyce Kong while (lcount < MAX_LOOP) {
109fe252fb6SJoyce Kong rte_rwlock_write_lock(&lk);
110fe252fb6SJoyce Kong ++rwlock_data;
111fe252fb6SJoyce Kong rte_rwlock_write_unlock(&lk);
112fe252fb6SJoyce Kong
113fe252fb6SJoyce Kong rte_rwlock_read_lock(&lk);
114fe252fb6SJoyce Kong if (TEST_RWLOCK_DEBUG && !(lcount % 100))
115fe252fb6SJoyce Kong printf("Core [%u] rwlock_data = %"PRIu64"\n",
116fe252fb6SJoyce Kong lcore, rwlock_data);
117fe252fb6SJoyce Kong rte_rwlock_read_unlock(&lk);
118fe252fb6SJoyce Kong
119fe252fb6SJoyce Kong lcount++;
120fe252fb6SJoyce Kong /* delay to make lock duty cycle slightly realistic */
121fe252fb6SJoyce Kong rte_pause();
122fe252fb6SJoyce Kong }
123fe252fb6SJoyce Kong
1246fef1ae4SJoyce Kong time_diff = rte_rdtsc_precise() - begin;
1256fef1ae4SJoyce Kong time_count[lcore] = time_diff * 1000000 / hz;
126fe252fb6SJoyce Kong return 0;
127fe252fb6SJoyce Kong }
128fe252fb6SJoyce Kong
129fe252fb6SJoyce Kong static int
test_rwlock_perf(void)130fe252fb6SJoyce Kong test_rwlock_perf(void)
131fe252fb6SJoyce Kong {
132fe252fb6SJoyce Kong unsigned int i;
133fe252fb6SJoyce Kong uint64_t total = 0;
134fe252fb6SJoyce Kong
135fe252fb6SJoyce Kong printf("\nRwlock Perf Test on %u cores...\n", rte_lcore_count());
136fe252fb6SJoyce Kong
137cb056611SStephen Hemminger /* clear synchro and start workers */
138*b6a7e685STyler Retzlaff rte_atomic_store_explicit(&synchro, 0, rte_memory_order_relaxed);
139cb056611SStephen Hemminger if (rte_eal_mp_remote_launch(load_loop_fn, NULL, SKIP_MAIN) < 0)
140fe252fb6SJoyce Kong return -1;
141fe252fb6SJoyce Kong
142cb056611SStephen Hemminger /* start synchro and launch test on main */
143*b6a7e685STyler Retzlaff rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
144fe252fb6SJoyce Kong load_loop_fn(NULL);
145fe252fb6SJoyce Kong
146fe252fb6SJoyce Kong rte_eal_mp_wait_lcore();
147fe252fb6SJoyce Kong
148fe252fb6SJoyce Kong RTE_LCORE_FOREACH(i) {
1496fef1ae4SJoyce Kong printf("Core [%u] cost time = %"PRIu64" us\n",
1506fef1ae4SJoyce Kong i, time_count[i]);
1516fef1ae4SJoyce Kong total += time_count[i];
152fe252fb6SJoyce Kong }
153fe252fb6SJoyce Kong
1546fef1ae4SJoyce Kong printf("Total cost time = %"PRIu64" us\n", total);
1556fef1ae4SJoyce Kong memset(time_count, 0, sizeof(time_count));
156fe252fb6SJoyce Kong
157fe252fb6SJoyce Kong return 0;
158fe252fb6SJoyce Kong }
159fe252fb6SJoyce Kong
160a9de470cSBruce Richardson /*
161a9de470cSBruce Richardson * - There is a global rwlock and a table of rwlocks (one per lcore).
162a9de470cSBruce Richardson *
163a9de470cSBruce Richardson * - The test function takes all of these locks and launches the
164cb056611SStephen Hemminger * ``test_rwlock_per_core()`` function on each core (except the main).
165a9de470cSBruce Richardson *
166a9de470cSBruce Richardson * - The function takes the global write lock, display something,
167a9de470cSBruce Richardson * then releases the global lock.
168a9de470cSBruce Richardson * - Then, it takes the per-lcore write lock, display something, and
169a9de470cSBruce Richardson * releases the per-core lock.
170a9de470cSBruce Richardson * - Finally, a read lock is taken during 100 ms, then released.
171a9de470cSBruce Richardson *
172a9de470cSBruce Richardson * - The main function unlocks the per-lcore locks sequentially and
173a9de470cSBruce Richardson * waits between each lock. This triggers the display of a message
174a9de470cSBruce Richardson * for each core, in the correct order.
175a9de470cSBruce Richardson *
176a9de470cSBruce Richardson * Then, it tries to take the global write lock and display the last
177a9de470cSBruce Richardson * message. The autotest script checks that the message order is correct.
178a9de470cSBruce Richardson */
179a9de470cSBruce Richardson static int
rwlock_test1(void)180a9de470cSBruce Richardson rwlock_test1(void)
181a9de470cSBruce Richardson {
182a9de470cSBruce Richardson int i;
183a9de470cSBruce Richardson
184a9de470cSBruce Richardson rte_rwlock_init(&sl);
185a9de470cSBruce Richardson for (i = 0; i < RTE_MAX_LCORE; i++)
186a9de470cSBruce Richardson rte_rwlock_init(&sl_tab[i]);
187a9de470cSBruce Richardson
188a9de470cSBruce Richardson rte_rwlock_write_lock(&sl);
189a9de470cSBruce Richardson
190cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(i) {
191a9de470cSBruce Richardson rte_rwlock_write_lock(&sl_tab[i]);
192a9de470cSBruce Richardson rte_eal_remote_launch(test_rwlock_per_core, NULL, i);
193a9de470cSBruce Richardson }
194a9de470cSBruce Richardson
195a9de470cSBruce Richardson rte_rwlock_write_unlock(&sl);
196a9de470cSBruce Richardson
197cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(i) {
198a9de470cSBruce Richardson rte_rwlock_write_unlock(&sl_tab[i]);
199a9de470cSBruce Richardson rte_delay_ms(100);
200a9de470cSBruce Richardson }
201a9de470cSBruce Richardson
202a9de470cSBruce Richardson rte_rwlock_write_lock(&sl);
203a9de470cSBruce Richardson /* this message should be the last message of test */
204cb056611SStephen Hemminger printf("Global write lock taken on main core %u\n", rte_lcore_id());
205a9de470cSBruce Richardson rte_rwlock_write_unlock(&sl);
206a9de470cSBruce Richardson
207a9de470cSBruce Richardson rte_eal_mp_wait_lcore();
208a9de470cSBruce Richardson
209fe252fb6SJoyce Kong if (test_rwlock_perf() < 0)
210fe252fb6SJoyce Kong return -1;
211fe252fb6SJoyce Kong
212a9de470cSBruce Richardson return 0;
213a9de470cSBruce Richardson }
214a9de470cSBruce Richardson
215a9de470cSBruce Richardson static int
try_read(uint32_t lc)216a9de470cSBruce Richardson try_read(uint32_t lc)
217a9de470cSBruce Richardson {
218a9de470cSBruce Richardson int32_t rc;
219a9de470cSBruce Richardson uint32_t i;
220a9de470cSBruce Richardson
221a9de470cSBruce Richardson rc = rte_rwlock_read_trylock(&try_rwlock_data.lock);
222a9de470cSBruce Richardson if (rc != 0)
223a9de470cSBruce Richardson return rc;
224a9de470cSBruce Richardson
225a9de470cSBruce Richardson for (i = 0; i != RTE_DIM(try_rwlock_data.data.u64); i++) {
226a9de470cSBruce Richardson
227a9de470cSBruce Richardson /* race condition occurred, lock doesn't work properly */
228a9de470cSBruce Richardson if (try_rwlock_data.data.u64[i] != 0) {
229a9de470cSBruce Richardson printf("%s(%u) error: unexpected data pattern\n",
230a9de470cSBruce Richardson __func__, lc);
231a9de470cSBruce Richardson rte_memdump(stdout, NULL,
232a9de470cSBruce Richardson (void *)(uintptr_t)&try_rwlock_data.data,
233a9de470cSBruce Richardson sizeof(try_rwlock_data.data));
234a9de470cSBruce Richardson rc = -EFAULT;
235a9de470cSBruce Richardson break;
236a9de470cSBruce Richardson }
237a9de470cSBruce Richardson }
238a9de470cSBruce Richardson
239a9de470cSBruce Richardson rte_rwlock_read_unlock(&try_rwlock_data.lock);
240a9de470cSBruce Richardson return rc;
241a9de470cSBruce Richardson }
242a9de470cSBruce Richardson
243a9de470cSBruce Richardson static int
try_write(uint32_t lc)244a9de470cSBruce Richardson try_write(uint32_t lc)
245a9de470cSBruce Richardson {
246a9de470cSBruce Richardson int32_t rc;
247a9de470cSBruce Richardson uint32_t i, v;
248a9de470cSBruce Richardson
249a9de470cSBruce Richardson v = RTE_MAX(lc % UINT8_MAX, 1U);
250a9de470cSBruce Richardson
251a9de470cSBruce Richardson rc = rte_rwlock_write_trylock(&try_rwlock_data.lock);
252a9de470cSBruce Richardson if (rc != 0)
253a9de470cSBruce Richardson return rc;
254a9de470cSBruce Richardson
25514df4f29SStephen Hemminger /* update by bytes in reverse order */
256a9de470cSBruce Richardson for (i = RTE_DIM(try_rwlock_data.data.u8); i-- != 0; ) {
257a9de470cSBruce Richardson
258a9de470cSBruce Richardson /* race condition occurred, lock doesn't work properly */
259a9de470cSBruce Richardson if (try_rwlock_data.data.u8[i] != 0) {
260a9de470cSBruce Richardson printf("%s:%d(%u) error: unexpected data pattern\n",
261a9de470cSBruce Richardson __func__, __LINE__, lc);
262a9de470cSBruce Richardson rte_memdump(stdout, NULL,
263a9de470cSBruce Richardson (void *)(uintptr_t)&try_rwlock_data.data,
264a9de470cSBruce Richardson sizeof(try_rwlock_data.data));
265a9de470cSBruce Richardson rc = -EFAULT;
266a9de470cSBruce Richardson break;
267a9de470cSBruce Richardson }
268a9de470cSBruce Richardson
269a9de470cSBruce Richardson try_rwlock_data.data.u8[i] = v;
270a9de470cSBruce Richardson }
271a9de470cSBruce Richardson
27214df4f29SStephen Hemminger /* restore by bytes in reverse order */
273a9de470cSBruce Richardson for (i = RTE_DIM(try_rwlock_data.data.u8); i-- != 0; ) {
274a9de470cSBruce Richardson
275a9de470cSBruce Richardson /* race condition occurred, lock doesn't work properly */
276a9de470cSBruce Richardson if (try_rwlock_data.data.u8[i] != v) {
277a9de470cSBruce Richardson printf("%s:%d(%u) error: unexpected data pattern\n",
278a9de470cSBruce Richardson __func__, __LINE__, lc);
279a9de470cSBruce Richardson rte_memdump(stdout, NULL,
280a9de470cSBruce Richardson (void *)(uintptr_t)&try_rwlock_data.data,
281a9de470cSBruce Richardson sizeof(try_rwlock_data.data));
282a9de470cSBruce Richardson rc = -EFAULT;
283a9de470cSBruce Richardson break;
284a9de470cSBruce Richardson }
285a9de470cSBruce Richardson
286a9de470cSBruce Richardson try_rwlock_data.data.u8[i] = 0;
287a9de470cSBruce Richardson }
288a9de470cSBruce Richardson
289a9de470cSBruce Richardson rte_rwlock_write_unlock(&try_rwlock_data.lock);
290a9de470cSBruce Richardson return rc;
291a9de470cSBruce Richardson }
292a9de470cSBruce Richardson
293a9de470cSBruce Richardson static int
try_read_lcore(__rte_unused void * data)294a9de470cSBruce Richardson try_read_lcore(__rte_unused void *data)
295a9de470cSBruce Richardson {
296a9de470cSBruce Richardson int32_t rc;
297a9de470cSBruce Richardson uint32_t i, lc;
298a9de470cSBruce Richardson uint64_t ftm, stm, tm;
299a9de470cSBruce Richardson struct try_rwlock_lcore *lcd;
300a9de470cSBruce Richardson
301a9de470cSBruce Richardson lc = rte_lcore_id();
302a9de470cSBruce Richardson lcd = try_lcore_data + lc;
303a9de470cSBruce Richardson lcd->type = LC_TYPE_RDLOCK;
304a9de470cSBruce Richardson
305a9de470cSBruce Richardson ftm = try_rwlock_data.tick;
306a9de470cSBruce Richardson stm = rte_get_timer_cycles();
307a9de470cSBruce Richardson
308a9de470cSBruce Richardson do {
309a9de470cSBruce Richardson for (i = 0; i != ITER_NUM; i++) {
310a9de470cSBruce Richardson rc = try_read(lc);
311a9de470cSBruce Richardson if (rc == 0)
312a9de470cSBruce Richardson lcd->stat.success++;
313a9de470cSBruce Richardson else if (rc == -EBUSY)
314a9de470cSBruce Richardson lcd->stat.fail++;
315a9de470cSBruce Richardson else
316a9de470cSBruce Richardson break;
317a9de470cSBruce Richardson rc = 0;
318a9de470cSBruce Richardson }
319a9de470cSBruce Richardson tm = rte_get_timer_cycles() - stm;
320a9de470cSBruce Richardson } while (tm < ftm && rc == 0);
321a9de470cSBruce Richardson
322a9de470cSBruce Richardson lcd->rc = rc;
323a9de470cSBruce Richardson lcd->stat.tick = tm;
324a9de470cSBruce Richardson return rc;
325a9de470cSBruce Richardson }
326a9de470cSBruce Richardson
327a9de470cSBruce Richardson static int
try_write_lcore(__rte_unused void * data)328a9de470cSBruce Richardson try_write_lcore(__rte_unused void *data)
329a9de470cSBruce Richardson {
330a9de470cSBruce Richardson int32_t rc;
331a9de470cSBruce Richardson uint32_t i, lc;
332a9de470cSBruce Richardson uint64_t ftm, stm, tm;
333a9de470cSBruce Richardson struct try_rwlock_lcore *lcd;
334a9de470cSBruce Richardson
335a9de470cSBruce Richardson lc = rte_lcore_id();
336a9de470cSBruce Richardson lcd = try_lcore_data + lc;
337a9de470cSBruce Richardson lcd->type = LC_TYPE_WRLOCK;
338a9de470cSBruce Richardson
339a9de470cSBruce Richardson ftm = try_rwlock_data.tick;
340a9de470cSBruce Richardson stm = rte_get_timer_cycles();
341a9de470cSBruce Richardson
342a9de470cSBruce Richardson do {
343a9de470cSBruce Richardson for (i = 0; i != ITER_NUM; i++) {
344a9de470cSBruce Richardson rc = try_write(lc);
345a9de470cSBruce Richardson if (rc == 0)
346a9de470cSBruce Richardson lcd->stat.success++;
347a9de470cSBruce Richardson else if (rc == -EBUSY)
348a9de470cSBruce Richardson lcd->stat.fail++;
349a9de470cSBruce Richardson else
350a9de470cSBruce Richardson break;
351a9de470cSBruce Richardson rc = 0;
352a9de470cSBruce Richardson }
353a9de470cSBruce Richardson tm = rte_get_timer_cycles() - stm;
354a9de470cSBruce Richardson } while (tm < ftm && rc == 0);
355a9de470cSBruce Richardson
356a9de470cSBruce Richardson lcd->rc = rc;
357a9de470cSBruce Richardson lcd->stat.tick = tm;
358a9de470cSBruce Richardson return rc;
359a9de470cSBruce Richardson }
360a9de470cSBruce Richardson
361a9de470cSBruce Richardson static void
print_try_lcore_stats(const struct try_rwlock_lcore * tlc,uint32_t lc)362a9de470cSBruce Richardson print_try_lcore_stats(const struct try_rwlock_lcore *tlc, uint32_t lc)
363a9de470cSBruce Richardson {
364a9de470cSBruce Richardson uint64_t f, s;
365a9de470cSBruce Richardson
366a9de470cSBruce Richardson f = RTE_MAX(tlc->stat.fail, 1ULL);
367a9de470cSBruce Richardson s = RTE_MAX(tlc->stat.success, 1ULL);
368a9de470cSBruce Richardson
369a9de470cSBruce Richardson printf("try_lcore_data[%u]={\n"
370a9de470cSBruce Richardson "\trc=%d,\n"
371a9de470cSBruce Richardson "\ttype=%s,\n"
372a9de470cSBruce Richardson "\tfail=%" PRIu64 ",\n"
373a9de470cSBruce Richardson "\tsuccess=%" PRIu64 ",\n"
374a9de470cSBruce Richardson "\tcycles=%" PRIu64 ",\n"
375a9de470cSBruce Richardson "\tcycles/op=%#Lf,\n"
376a9de470cSBruce Richardson "\tcycles/success=%#Lf,\n"
377a9de470cSBruce Richardson "\tsuccess/fail=%#Lf,\n"
378a9de470cSBruce Richardson "};\n",
379a9de470cSBruce Richardson lc,
380a9de470cSBruce Richardson tlc->rc,
381a9de470cSBruce Richardson tlc->type == LC_TYPE_RDLOCK ? "RDLOCK" : "WRLOCK",
382a9de470cSBruce Richardson tlc->stat.fail,
383a9de470cSBruce Richardson tlc->stat.success,
384a9de470cSBruce Richardson tlc->stat.tick,
385a9de470cSBruce Richardson (long double)tlc->stat.tick /
386a9de470cSBruce Richardson (tlc->stat.fail + tlc->stat.success),
387a9de470cSBruce Richardson (long double)tlc->stat.tick / s,
388a9de470cSBruce Richardson (long double)tlc->stat.success / f);
389a9de470cSBruce Richardson }
390a9de470cSBruce Richardson
391a9de470cSBruce Richardson static void
collect_try_lcore_stats(struct try_rwlock_lcore * tlc,const struct try_rwlock_lcore * lc)392a9de470cSBruce Richardson collect_try_lcore_stats(struct try_rwlock_lcore *tlc,
393a9de470cSBruce Richardson const struct try_rwlock_lcore *lc)
394a9de470cSBruce Richardson {
395a9de470cSBruce Richardson tlc->stat.tick += lc->stat.tick;
396a9de470cSBruce Richardson tlc->stat.fail += lc->stat.fail;
397a9de470cSBruce Richardson tlc->stat.success += lc->stat.success;
398a9de470cSBruce Richardson }
399a9de470cSBruce Richardson
400a9de470cSBruce Richardson /*
401a9de470cSBruce Richardson * Process collected results:
402a9de470cSBruce Richardson * - check status
403a9de470cSBruce Richardson * - collect and print statistics
404a9de470cSBruce Richardson */
405a9de470cSBruce Richardson static int
process_try_lcore_stats(void)406a9de470cSBruce Richardson process_try_lcore_stats(void)
407a9de470cSBruce Richardson {
408a9de470cSBruce Richardson int32_t rc;
409a9de470cSBruce Richardson uint32_t lc, rd, wr;
410a9de470cSBruce Richardson struct try_rwlock_lcore rlc, wlc;
411a9de470cSBruce Richardson
412a9de470cSBruce Richardson memset(&rlc, 0, sizeof(rlc));
413a9de470cSBruce Richardson memset(&wlc, 0, sizeof(wlc));
414a9de470cSBruce Richardson
415a9de470cSBruce Richardson rlc.type = LC_TYPE_RDLOCK;
416a9de470cSBruce Richardson wlc.type = LC_TYPE_WRLOCK;
417a9de470cSBruce Richardson rd = 0;
418a9de470cSBruce Richardson wr = 0;
419a9de470cSBruce Richardson
420a9de470cSBruce Richardson rc = 0;
421a9de470cSBruce Richardson RTE_LCORE_FOREACH(lc) {
422a9de470cSBruce Richardson rc |= try_lcore_data[lc].rc;
423a9de470cSBruce Richardson if (try_lcore_data[lc].type == LC_TYPE_RDLOCK) {
424a9de470cSBruce Richardson collect_try_lcore_stats(&rlc, try_lcore_data + lc);
425a9de470cSBruce Richardson rd++;
426a9de470cSBruce Richardson } else {
427a9de470cSBruce Richardson collect_try_lcore_stats(&wlc, try_lcore_data + lc);
428a9de470cSBruce Richardson wr++;
429a9de470cSBruce Richardson }
430a9de470cSBruce Richardson }
431a9de470cSBruce Richardson
432a9de470cSBruce Richardson if (rc == 0) {
433a9de470cSBruce Richardson RTE_LCORE_FOREACH(lc)
434a9de470cSBruce Richardson print_try_lcore_stats(try_lcore_data + lc, lc);
435a9de470cSBruce Richardson
436a9de470cSBruce Richardson if (rd != 0) {
437a9de470cSBruce Richardson printf("aggregated stats for %u RDLOCK cores:\n", rd);
438a9de470cSBruce Richardson print_try_lcore_stats(&rlc, rd);
439a9de470cSBruce Richardson }
440a9de470cSBruce Richardson
441a9de470cSBruce Richardson if (wr != 0) {
442a9de470cSBruce Richardson printf("aggregated stats for %u WRLOCK cores:\n", wr);
443a9de470cSBruce Richardson print_try_lcore_stats(&wlc, wr);
444a9de470cSBruce Richardson }
445a9de470cSBruce Richardson }
446a9de470cSBruce Richardson
447a9de470cSBruce Richardson return rc;
448a9de470cSBruce Richardson }
449a9de470cSBruce Richardson
450a9de470cSBruce Richardson static void
try_test_reset(void)451a9de470cSBruce Richardson try_test_reset(void)
452a9de470cSBruce Richardson {
453a9de470cSBruce Richardson memset(&try_lcore_data, 0, sizeof(try_lcore_data));
454a9de470cSBruce Richardson memset(&try_rwlock_data, 0, sizeof(try_rwlock_data));
455a9de470cSBruce Richardson try_rwlock_data.tick = TEST_SEC * rte_get_tsc_hz();
456a9de470cSBruce Richardson }
457a9de470cSBruce Richardson
458a9de470cSBruce Richardson /* all lcores grab RDLOCK */
459a9de470cSBruce Richardson static int
try_rwlock_test_rda(void)460a9de470cSBruce Richardson try_rwlock_test_rda(void)
461a9de470cSBruce Richardson {
462a9de470cSBruce Richardson try_test_reset();
463a9de470cSBruce Richardson
46414df4f29SStephen Hemminger /* start read test on all available lcores */
465cb056611SStephen Hemminger rte_eal_mp_remote_launch(try_read_lcore, NULL, CALL_MAIN);
466a9de470cSBruce Richardson rte_eal_mp_wait_lcore();
467a9de470cSBruce Richardson
468a9de470cSBruce Richardson return process_try_lcore_stats();
469a9de470cSBruce Richardson }
470a9de470cSBruce Richardson
471cb056611SStephen Hemminger /* all worker lcores grab RDLOCK, main one grabs WRLOCK */
472a9de470cSBruce Richardson static int
try_rwlock_test_rds_wrm(void)473a9de470cSBruce Richardson try_rwlock_test_rds_wrm(void)
474a9de470cSBruce Richardson {
475a9de470cSBruce Richardson try_test_reset();
476a9de470cSBruce Richardson
477cb056611SStephen Hemminger rte_eal_mp_remote_launch(try_read_lcore, NULL, SKIP_MAIN);
478a9de470cSBruce Richardson try_write_lcore(NULL);
479a9de470cSBruce Richardson rte_eal_mp_wait_lcore();
480a9de470cSBruce Richardson
481a9de470cSBruce Richardson return process_try_lcore_stats();
482a9de470cSBruce Richardson }
483a9de470cSBruce Richardson
484cb056611SStephen Hemminger /* main and even worker lcores grab RDLOCK, odd lcores grab WRLOCK */
485a9de470cSBruce Richardson static int
try_rwlock_test_rde_wro(void)486a9de470cSBruce Richardson try_rwlock_test_rde_wro(void)
487a9de470cSBruce Richardson {
488a9de470cSBruce Richardson uint32_t lc, mlc;
489a9de470cSBruce Richardson
490a9de470cSBruce Richardson try_test_reset();
491a9de470cSBruce Richardson
492cb056611SStephen Hemminger mlc = rte_get_main_lcore();
493a9de470cSBruce Richardson
494a9de470cSBruce Richardson RTE_LCORE_FOREACH(lc) {
495a9de470cSBruce Richardson if (lc != mlc) {
496a9de470cSBruce Richardson if ((lc & 1) == 0)
497a9de470cSBruce Richardson rte_eal_remote_launch(try_read_lcore,
498a9de470cSBruce Richardson NULL, lc);
499a9de470cSBruce Richardson else
500a9de470cSBruce Richardson rte_eal_remote_launch(try_write_lcore,
501a9de470cSBruce Richardson NULL, lc);
502a9de470cSBruce Richardson }
503a9de470cSBruce Richardson }
504a9de470cSBruce Richardson try_read_lcore(NULL);
505a9de470cSBruce Richardson rte_eal_mp_wait_lcore();
506a9de470cSBruce Richardson
507a9de470cSBruce Richardson return process_try_lcore_stats();
508a9de470cSBruce Richardson }
509a9de470cSBruce Richardson
510e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_test1_autotest, true, true, rwlock_test1);
511e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_rda_autotest, true, true, try_rwlock_test_rda);
512e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_rds_wrm_autotest, true, true, try_rwlock_test_rds_wrm);
513e0a8442cSBruce Richardson REGISTER_FAST_TEST(rwlock_rde_wro_autotest, true, true, try_rwlock_test_rde_wro);
514