]>
git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/test/test/test_barrier.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2018 Intel Corporation
6 * This is a simple functional test for rte_smp_mb() implementation.
7 * I.E. make sure that LOAD and STORE operations that precede the
8 * rte_smp_mb() call are globally visible across the lcores
9 * before the the LOAD and STORE operations that follows it.
10 * The test uses simple implementation of Peterson's lock algorithm
11 * (https://en.wikipedia.org/wiki/Peterson%27s_algorithm)
12 * for two execution units to make sure that rte_smp_mb() prevents
13 * store-load reordering to happen.
14 * Also when executed on a single lcore could be used as a approxiamate
15 * estimation of number of cycles particular implementation of rte_smp_mb()
24 #include <rte_memory.h>
25 #include <rte_per_lcore.h>
26 #include <rte_launch.h>
27 #include <rte_atomic.h>
29 #include <rte_lcore.h>
30 #include <rte_pause.h>
31 #include <rte_random.h>
32 #include <rte_cycles.h>
34 #include <rte_debug.h>
39 #define ITER_MAX 0x1000000
48 volatile uint32_t flag
[2];
49 volatile uint32_t victim
;
50 enum plock_use_type utype
;
54 * Lock plus protected by it two counters.
63 * Each active lcore shares plock_test struct with it's left and right
66 struct lcore_plock_test
{
67 struct plock_test
*pt
[2]; /* shared, lock-protected data */
68 uint32_t sum
[2]; /* local copy of the shared data */
69 uint32_t iter
; /* number of iterations to perfom */
70 uint32_t lc
; /* given lcore id */
74 store_load_barrier(uint32_t utype
)
78 else if (utype
== USE_SMP_MB
)
85 * Peterson lock implementation.
88 plock_lock(struct plock
*l
, uint32_t self
)
97 store_load_barrier(l
->utype
);
99 while (l
->flag
[other
] == 1 && l
->victim
== self
)
104 plock_unlock(struct plock
*l
, uint32_t self
)
111 plock_reset(struct plock
*l
, enum plock_use_type utype
)
113 memset(l
, 0, sizeof(*l
));
118 * grab the lock, update both counters, release the lock.
121 plock_add(struct plock_test
*pt
, uint32_t self
, uint32_t n
)
123 plock_lock(&pt
->lock
, self
);
126 plock_unlock(&pt
->lock
, self
);
130 plock_test1_lcore(void *data
)
133 uint32_t i
, lc
, ln
, n
;
134 struct lcore_plock_test
*lpt
;
139 /* find lcore_plock_test struct for given lcore */
140 for (ln
= rte_lcore_count(); ln
!= 0 && lpt
->lc
!= lc
; lpt
++, ln
--)
144 printf("%s(%u) error at init\n", __func__
, lc
);
148 n
= rte_rand() % ADD_MAX
;
149 tm
= rte_get_timer_cycles();
152 * for each iteration:
153 * - update shared, locked protected data in a safe manner
154 * - update local copy of the shared data
156 for (i
= 0; i
!= lpt
->iter
; i
++) {
158 plock_add(lpt
->pt
[0], 0, n
);
159 plock_add(lpt
->pt
[1], 1, n
);
164 n
= (n
+ 1) % ADD_MAX
;
167 tm
= rte_get_timer_cycles() - tm
;
169 printf("%s(%u): %u iterations finished, in %" PRIu64
170 " cycles, %#Lf cycles/iteration, "
171 "local sum={%u, %u}\n",
172 __func__
, lc
, i
, tm
, (long double)tm
/ i
,
173 lpt
->sum
[0], lpt
->sum
[1]);
178 * For N active lcores we allocate N+1 lcore_plock_test structures.
179 * Each active lcore shares one lcore_plock_test structure with its
180 * left lcore neighbor and one lcore_plock_test structure with its
181 * right lcore neighbor.
182 * During the test each lcore updates data in both shared structures and
183 * its local copies. Then at validation phase we check that our shared
184 * and local data are the same.
187 plock_test(uint32_t iter
, enum plock_use_type utype
)
192 struct plock_test
*pt
;
193 struct lcore_plock_test
*lpt
;
195 /* init phase, allocate and initialize shared data */
197 n
= rte_lcore_count();
198 pt
= calloc(n
+ 1, sizeof(*pt
));
199 lpt
= calloc(n
, sizeof(*lpt
));
200 sum
= calloc(n
+ 1, sizeof(*sum
));
202 printf("%s(iter=%u, utype=%u) started on %u lcores\n",
203 __func__
, iter
, utype
, n
);
205 if (pt
== NULL
|| lpt
== NULL
) {
206 printf("%s: failed to allocate memory for %u lcores\n",
214 for (i
= 0; i
!= n
+ 1; i
++)
215 plock_reset(&pt
[i
].lock
, utype
);
218 RTE_LCORE_FOREACH(lc
) {
222 lpt
[i
].pt
[0] = pt
+ i
;
223 lpt
[i
].pt
[1] = pt
+ i
+ 1;
227 lpt
[i
- 1].pt
[1] = pt
;
229 for (i
= 0; i
!= n
; i
++)
230 printf("lpt[%u]={lc=%u, pt={%p, %p},};\n",
231 i
, lpt
[i
].lc
, lpt
[i
].pt
[0], lpt
[i
].pt
[1]);
234 /* test phase - start and wait for completion on each active lcore */
236 rte_eal_mp_remote_launch(plock_test1_lcore
, lpt
, CALL_MASTER
);
237 rte_eal_mp_wait_lcore();
239 /* validation phase - make sure that shared and local data match */
241 for (i
= 0; i
!= n
; i
++) {
242 sum
[i
] += lpt
[i
].sum
[0];
243 sum
[i
+ 1] += lpt
[i
].sum
[1];
249 for (i
= 0; i
!= n
; i
++) {
250 printf("%s: sum[%u]=%u, pt[%u].val=%u, pt[%u].iter=%u;\n",
251 __func__
, i
, sum
[i
], i
, pt
[i
].val
, i
, pt
[i
].iter
);
253 /* race condition occurred, lock doesn't work properly */
254 if (sum
[i
] != pt
[i
].val
|| 2 * iter
!= pt
[i
].iter
) {
255 printf("error: local and shared sums don't much\n");
264 printf("%s(utype=%u) returns %d\n", __func__
, utype
, rc
);
271 int32_t i
, ret
, rc
[USE_NUM
];
273 for (i
= 0; i
!= RTE_DIM(rc
); i
++)
274 rc
[i
] = plock_test(ITER_MAX
, i
);
277 for (i
= 0; i
!= RTE_DIM(rc
); i
++) {
278 printf("%s for utype=%d %s\n",
279 __func__
, i
, rc
[i
] == 0 ? "passed" : "failed");
286 REGISTER_TEST_COMMAND(barrier_autotest
, test_barrier
);