]>
git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/app/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 uint64_t sum
[2]; /* local copy of the shared data */
69 uint64_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
)
98 store_load_barrier(l
->utype
);
100 while (l
->flag
[other
] == 1 && l
->victim
== self
)
106 plock_unlock(struct plock
*l
, uint32_t self
)
113 plock_reset(struct plock
*l
, enum plock_use_type utype
)
115 memset(l
, 0, sizeof(*l
));
120 * grab the lock, update both counters, release the lock.
123 plock_add(struct plock_test
*pt
, uint32_t self
, uint32_t n
)
125 plock_lock(&pt
->lock
, self
);
128 plock_unlock(&pt
->lock
, self
);
132 plock_test1_lcore(void *data
)
137 struct lcore_plock_test
*lpt
;
142 /* find lcore_plock_test struct for given lcore */
143 for (ln
= rte_lcore_count(); ln
!= 0 && lpt
->lc
!= lc
; lpt
++, ln
--)
147 printf("%s(%u) error at init\n", __func__
, lc
);
151 n
= rte_rand() % ADD_MAX
;
152 tm
= rte_get_timer_cycles();
155 * for each iteration:
156 * - update shared, locked protected data in a safe manner
157 * - update local copy of the shared data
159 for (i
= 0; i
!= lpt
->iter
; i
++) {
161 plock_add(lpt
->pt
[0], 0, n
);
162 plock_add(lpt
->pt
[1], 1, n
);
167 n
= (n
+ 1) % ADD_MAX
;
170 tm
= rte_get_timer_cycles() - tm
;
172 printf("%s(%u): %" PRIu64
" iterations finished, in %" PRIu64
173 " cycles, %#Lf cycles/iteration, "
174 "local sum={%" PRIu64
", %" PRIu64
"}\n",
175 __func__
, lc
, i
, tm
, (long double)tm
/ i
,
176 lpt
->sum
[0], lpt
->sum
[1]);
181 * For N active lcores we allocate N+1 lcore_plock_test structures.
182 * Each active lcore shares one lcore_plock_test structure with its
183 * left lcore neighbor and one lcore_plock_test structure with its
184 * right lcore neighbor.
185 * During the test each lcore updates data in both shared structures and
186 * its local copies. Then at validation phase we check that our shared
187 * and local data are the same.
190 plock_test(uint64_t iter
, enum plock_use_type utype
)
195 struct plock_test
*pt
;
196 struct lcore_plock_test
*lpt
;
198 /* init phase, allocate and initialize shared data */
200 n
= rte_lcore_count();
201 pt
= calloc(n
+ 1, sizeof(*pt
));
202 lpt
= calloc(n
, sizeof(*lpt
));
203 sum
= calloc(n
+ 1, sizeof(*sum
));
205 printf("%s(iter=%" PRIu64
", utype=%u) started on %u lcores\n",
206 __func__
, iter
, utype
, n
);
208 if (pt
== NULL
|| lpt
== NULL
|| sum
== NULL
) {
209 printf("%s: failed to allocate memory for %u lcores\n",
217 for (i
= 0; i
!= n
+ 1; i
++)
218 plock_reset(&pt
[i
].lock
, utype
);
221 RTE_LCORE_FOREACH(lc
) {
225 lpt
[i
].pt
[0] = pt
+ i
;
226 lpt
[i
].pt
[1] = pt
+ i
+ 1;
230 lpt
[i
- 1].pt
[1] = pt
;
232 for (i
= 0; i
!= n
; i
++)
233 printf("lpt[%u]={lc=%u, pt={%p, %p},};\n",
234 i
, lpt
[i
].lc
, lpt
[i
].pt
[0], lpt
[i
].pt
[1]);
237 /* test phase - start and wait for completion on each active lcore */
239 rte_eal_mp_remote_launch(plock_test1_lcore
, lpt
, CALL_MASTER
);
240 rte_eal_mp_wait_lcore();
242 /* validation phase - make sure that shared and local data match */
244 for (i
= 0; i
!= n
; i
++) {
245 sum
[i
] += lpt
[i
].sum
[0];
246 sum
[i
+ 1] += lpt
[i
].sum
[1];
252 for (i
= 0; i
!= n
; i
++) {
253 printf("%s: sum[%u]=%" PRIu64
", pt[%u].val=%" PRIu64
", pt[%u].iter=%" PRIu64
";\n",
254 __func__
, i
, sum
[i
], i
, pt
[i
].val
, i
, pt
[i
].iter
);
256 /* race condition occurred, lock doesn't work properly */
257 if (sum
[i
] != pt
[i
].val
|| 2 * iter
!= pt
[i
].iter
) {
258 printf("error: local and shared sums don't match\n");
267 printf("%s(utype=%u) returns %d\n", __func__
, utype
, rc
);
274 int32_t i
, ret
, rc
[USE_NUM
];
276 for (i
= 0; i
!= RTE_DIM(rc
); i
++)
277 rc
[i
] = plock_test(ITER_MAX
, i
);
280 for (i
= 0; i
!= RTE_DIM(rc
); i
++) {
281 printf("%s for utype=%d %s\n",
282 __func__
, i
, rc
[i
] == 0 ? "passed" : "failed");
289 REGISTER_TEST_COMMAND(barrier_autotest
, test_barrier
);