[PATCH v2 19/33] test/barrier: test sequentially consistent fence only

Konstantin Ananyev konstantin.v.ananyev at yandex.ru
Sun Oct 4 14:57:57 CEST 2026


> te_smp_mb() is removed by this series, leaving the barrier test with
> one case instead of two.  Drop the use type enum and the barrier
> selector wrapper.
>
> Convert the Peterson lock to explicit atomic accesses with relaxed
> ordering, leaving rte_atomic_thread_fence(rte_memory_order_seq_cst)
> as the only thing preventing store-load reordering.


Run it on both x86 and arm boxes, both passed.
Other arch maintainers, pls review, test.
Acked-by: Konstantin Ananyev <konstantin.v.ananyev at yandex.ru>
Tested-by: Konstantin Ananyev <konstantin.v.ananyev at yandex.ru>

>
> Signed-off-by: Stephen Hemminger <stephen at networkplumber.org>
> ---
>   app/test/test_barrier.c <https://inbox.dpdk.org/dev/20260920181347.747210-20-stephen@networkplumber.org/#Z31app:test:test_barrier.c> | 105 +++++++++++++---------------------------
>   1 file changed, 34 insertions(+), 71 deletions(-)
>
> diff 
> <https://inbox.dpdk.org/dev/20260920181347.747210-20-stephen@networkplumber.org/#iZ31app:test:test_barrier.c> 
> --git a/app/test/test_barrier.c b/app/test/test_barrier.c index 
> 925a88b68a..cb876d8fda 100644 --- a/app/test/test_barrier.c +++ 
> b/app/test/test_barrier.c @@ -2,51 +2,41 @@   * Copyright(c) 2010-2018 Intel Corporation
>    */
>   
> - /* - * This is a simple functional test for rte_smp_mb() 
> implementation. - * I.E. make sure that LOAD and STORE operations that 
> precede the - * rte_smp_mb() call are globally visible across the 
> lcores - * before the LOAD and STORE operations that follows it. - * 
> The test uses simple implementation of Peterson's lock algorithm - * 
> (https://en.wikipedia.org/wiki/Peterson%27s_algorithm) - * for two 
> execution units to make sure that rte_smp_mb() prevents - * store-load 
> reordering to happen. - * Also when executed on a single lcore could 
> be used as a approximate - * estimation of number of cycles particular 
> implementation of rte_smp_mb() - * will take. - */ +/* + * Functional 
> test for rte_atomic_thread_fence(rte_memory_order_seq_cst). + * I.E. 
> make sure that LOAD and STORE operations that precede the fence + * 
> are globally visible across the lcores before the LOAD and STORE + * 
> operations that follow it. + * The test uses a simple implementation 
> of Peterson's lock algorithm + * 
> (https://en.wikipedia.org/wiki/Peterson%27s_algorithm) + * for two 
> execution units, since that algorithm only works if + * store-load 
> reordering is prevented. + * Also when executed on a single lcore it 
> can be used as an approximate + * estimate of the number of cycles a 
> sequentially consistent fence takes. + */  
> +#include <errno.h>  #include <stdio.h>
> -#include <string.h>  #include <stdint.h>
> +#include <stdlib.h>  #include <inttypes.h>
>   
> -#include <rte_memory.h> -#include <rte_per_lcore.h>  #include <rte_launch.h>
>   #include <rte_eal.h>
>   #include <rte_lcore.h>
>   #include <rte_pause.h>
>   #include <rte_random.h>
>   #include <rte_cycles.h>
> -#include <rte_vect.h> -#include <rte_debug.h> +#include 
> <rte_stdatomic.h>  
>   #include "test.h"
>   
>   #define ADD_MAX		8
>   #define ITER_MAX	0x1000000
>   
> -enum plock_use_type { - USE_MB, - USE_SMP_MB, - USE_NUM -}; -  struct plock {
> - volatile uint32_t flag[2]; - volatile uint32_t victim; - enum 
> plock_use_type utype; + RTE_ATOMIC(uint32_t) flag[2]; + 
> RTE_ATOMIC(uint32_t) victim;  };
>   
>   /*
> @@ -69,19 +59,11 @@ struct lcore_plock_test {  	uint32_t lc;              /* given lcore id */
>   };
>   
> -static inline void -store_load_barrier(uint32_t utype) -{ - if (utype 
> == USE_MB) - rte_mb(); - else if (utype == USE_SMP_MB) - rte_smp_mb(); 
> - else - RTE_VERIFY(0); -} -  /*
>    * Peterson lock implementation.
> + * The stores below are relaxed on purpose: the sequentially 
> consistent + * fence is the only thing keeping them ahead of the loads 
> in the spin + * loop, so a broken fence shows up as two lcores in the 
> critical section.   */
>   static void
>   plock_lock(struct plock *l, uint32_t self)
> @@ -90,29 +72,22 @@ plock_lock(struct plock *l, uint32_t self)  
>   	other = self ^ 1;
>   
> - l->flag[self] = 1; - rte_smp_wmb(); - l->victim = self; + 
> rte_atomic_store_explicit(&l->flag[self], 1, 
> rte_memory_order_relaxed); + rte_atomic_store_explicit(&l->victim, 
> self, rte_memory_order_relaxed);  
> - store_load_barrier(l->utype); + 
> rte_atomic_thread_fence(rte_memory_order_seq_cst);  
> - while (l->flag[other] == 1 && l->victim == self) + while 
> (rte_atomic_load_explicit(&l->flag[other], rte_memory_order_relaxed) 
> == 1 && + rte_atomic_load_explicit(&l->victim, 
> rte_memory_order_relaxed) == self)  		rte_pause();
> - rte_smp_rmb(); -}  
> -static void -plock_unlock(struct plock *l, uint32_t self) -{ - 
> rte_smp_wmb(); - l->flag[self] = 0; + 
> rte_atomic_thread_fence(rte_memory_order_acquire);  }
>   
>   static void
> -plock_reset(struct plock *l, enum plock_use_type utype) 
> +plock_unlock(struct plock *l, uint32_t self)  {
> - memset(l, 0, sizeof(*l)); - l->utype = utype; + 
> rte_atomic_store_explicit(&l->flag[self], 0, rte_memory_order_release);  }
>   
>   /*
> @@ -186,7 +161,7 @@ plock_test1_lcore(void *data)   * and local data are the same.
>    */
>   static int
> -plock_test(uint64_t iter, enum plock_use_type utype) 
> +plock_test(uint64_t iter)  {
>   	int32_t rc;
>   	uint32_t i, lc, n;
> @@ -201,8 +176,7 @@ plock_test(uint64_t iter, enum plock_use_type utype)  	lpt = calloc(n, sizeof(*lpt));
>   	sum = calloc(n + 1, sizeof(*sum));
>   
> - printf("%s(iter=%" PRIu64 ", utype=%u) started on %u lcores\n", - 
> __func__, iter, utype, n); + printf("%s(iter=%" PRIu64 ") started on 
> %u lcores\n", __func__, iter, n);  
>   	if (pt == NULL || lpt == NULL || sum == NULL) {
>   		printf("%s: failed to allocate memory for %u lcores\n",
> @@ -213,9 +187,6 @@ plock_test(uint64_t iter, enum plock_use_type utype)  		return -ENOMEM;
>   	}
>   
> - for (i = 0; i != n + 1; i++) - plock_reset(&pt[i].lock, utype); -  	i = 0;
>   	RTE_LCORE_FOREACH(lc) {
>   
> @@ -263,26 +234,18 @@ plock_test(uint64_t iter, enum plock_use_type 
> utype)  	free(lpt);
>   	free(sum);
>   
> - printf("%s(utype=%u) returns %d\n", __func__, utype, rc); + 
> printf("%s returns %d\n", __func__, rc);  	return rc;
>   }
>   
>   static int
>   test_barrier(void)
>   {
> - int32_t i, ret, rc[USE_NUM]; - - for (i = 0; i != RTE_DIM(rc); i++) 
> - rc[i] = plock_test(ITER_MAX, i); + int rc = plock_test(ITER_MAX);  
> - ret = 0; - for (i = 0; i != RTE_DIM(rc); i++) { - printf("%s for 
> utype=%d %s\n", - __func__, i, rc[i] == 0 ? "passed" : "failed"); - 
> ret |= rc[i]; - } + printf("%s %s\n", __func__, rc == 0 ? "passed" : 
> "failed");  
> - return ret; + return rc;  }
>   
>   REGISTER_PERF_TEST(barrier_autotest, test_barrier);
> -- 
> 2.53.0


More information about the dev mailing list