Re: [PATCH] erofs: weaken full memory barriers to r/w barriers (update to test data)

Bingwu Zhang <[email protected]> Thu, 30 Jul 2026 17:54:26 +0800
Newsgroups org.ozlabs.lists.linux-erofs,org.kernel.vger.linux-kernel
Organization AstraFall
Message-ID <[email protected]>
On Thursday, July 30, 2026 12:01:20=E2=80=AFPM China Standard Time Bingwu Z=
hang wrote:
> From: Bingwu Zhang <[email protected]>
>=20
> fs/erofs/{xattr.c,zmap.c} both implemented one-time initialization locks
> with general memory barriers.
>=20
> Weaken these unnecessarily-strong general memory barriers to SMP
> (ordering) read/write barriers for better performance on weakly-ordered
> architectures.
>=20
> Signed-off-by: Bingwu Zhang <[email protected]>
> ---
> (All test results below are done using QEMU with KVM; guest VM root FS
> are mounted with v9fs; test target is an EROFS mounted on a loop device
> backed by a file in tmpfs, in attempt to reduce error caused by physical
> disks; mkfs flags: --zD=3D1 --all-root -zzstd -E48bit)
>=20
> On x86-64, with x86-TSO, a full barrier lowers to a fence instruction and
> read/write barriers are just compiler barriers. This patch removes
> several fence instructions although they don't affect performance much.
>=20
> On weakly-ordered architectures, a full memory barrier could be very
> expensive. Thus, on these platforms, this patch saves more performance
> than x86-64.
>=20
> Test result on x86-64:
> (host: AMD Ryzen 7 255 (@ 3.3GHz))
> (guest VM: ArchLinux, test data: linux.git/drivers @ commit fc02acf6ac0c)
>   Original:
>     read: IOPS=3D1684, BW=3D6737KiB/s (6899kB/s)(1006MiB/152838msec)
>     clat (usec): min=3D25, max=3D26293, avg=3D578.58, stdev=3D426.55
>      lat (usec): min=3D25, max=3D26293, avg=3D578.70, stdev=3D426.56
>    bw (  KiB/s): min=3D 1976, max=3D10904, per=3D100.00%, avg=3D6749.91,
>       stdev=3D1883.80, samples=3D305
>    iops        : min=3D  494, max=3D 2726, avg=3D1687.48, stdev=3D470.95,
> samples=3D305
>=20
>   New:
>    read: IOPS=3D1687, BW=3D6751KiB/s (6913kB/s)(1006MiB/152513msec)
>     clat (usec): min=3D25, max=3D19136, avg=3D577.00, stdev=3D425.66
>      lat (usec): min=3D25, max=3D19136, avg=3D577.09, stdev=3D425.67
>    bw (  KiB/s): min=3D 2192, max=3D11088, per=3D100.00%, avg=3D6770.26
>       stdev=3D1870.55, samples=3D304
>    iops        : min=3D  548, max=3D 2772, avg=3D1692.44, stdev=3D467.65,
> samples=3D304
>=20
> IOPS +0.17%, bandwidth +0.20%, max completion latency -27.22%
note: this line might be inaccurate, too
>=20

To clarify, the test result in the last email may be inaccurate.

I repeated tests and got some updated data.
This time I remembered to drop page caches between tests.

On AArch64,
for 4K randread, IOPS and bandwidth +1.5%, time -1.4%
for 16K randread, IOPS and bandwidth +1.6%, time -1.5%

Sorry for the misleading data in my last email. The data on ARM64 fluctuate=
=20
greatly between tests and I was trying to get an average value.

On x86-64,
for 4K randread, IOPS, bandwidth and time are basically unchanged,
while the max clat still -10.5% for unknown reasons (I don't think this pat=
ch=20
could change so much on x86)

I am not familiar with benchmarking and please let me know if I did anythin=
g=20
wrong.

Thanks!

Best regards,
Bingwu Zhang

> Test result on ARM64:
> (host: HUAWEI Kunpeng 920 @ 2.6GHz, both host & VM are AOSC OS)
> (test data:
> 1. AOSC OS: aosc-os_base_20260621_arm64.squashfs, /usr/bin directory is
>    repacked as EROFS.
> 2. linux.git at commit fc02acf6ac0c, drivers/ subdirectory
> )
>   Original:
>    read: IOPS=3D12.3k, BW=3D47.9MiB/s (50.2MB/s)(1291MiB/26950msec)
>     clat (nsec): min=3D910, max=3D37500k, avg=3D56026.68, stdev=3D198628.=
59
>      lat (nsec): min=3D960, max=3D37500k, avg=3D56167.70, stdev=3D198639.=
09
>    bw (  KiB/s): min=3D 3888, max=3D94328, per=3D100.00%, avg=3D49790.64,
>       stdev=3D31594.09, samples=3D53
>    iops        : min=3D  972, max=3D23582, avg=3D12447.57, stdev=3D7898.5=
1,
> samples=3D53
>=20
>   New:
>    read: IOPS=3D13.8k, BW=3D54.0MiB/s (56.6MB/s)(1315MiB/24375msec)
>     clat (nsec): min=3D930, max=3D34271k, avg=3D53069.97, stdev=3D145651.=
76
>      lat (nsec): min=3D980, max=3D34271k, avg=3D53221.68, stdev=3D145661.=
24
>    bw (  KiB/s): min=3D 5843, max=3D95054, per=3D100.00%, avg=3D55988.58,
>       stdev=3D30477.44, samples=3D48
>    iops        : min=3D 1460, max=3D23763, avg=3D13997.00, stdev=3D7619.3=
7,
> samples=3D48
>=20
> IOPS min +50.20%, avg +12.44%
> bandwidth min +50.28%, max +0.76%, avg +12.44%
> completion latency max -8.61%, avg -5.27%
>=20
> I am not pretty sure why the minimum completion latencies vary so much on
> AArch64. Even when I repeat the test with the same kernel without
> rebooting/re-mounting, clat min fluctuates randomly, sometimes spiking to
> over 1000 and sometimes dropping to as low as 2, but I think this patch
> still improves the overall throughput performance.
> ---
>  fs/erofs/xattr.c | 8 ++++----
>  fs/erofs/zmap.c  | 8 ++++----
>  2 files changed, 8 insertions(+), 8 deletions(-)
>=20
> diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c
> index df7ea019526d..0b252cfe616a 100644
> --- a/fs/erofs/xattr.c
> +++ b/fs/erofs/xattr.c
> @@ -44,10 +44,10 @@ static int erofs_init_inode_xattrs(struct inode *inod=
e)
>  	/* the most case is that xattrs of this inode are initialized. */
>  	if (test_bit(EROFS_I_EA_INITED_BIT, &vi->flags)) {
>  		/*
> -		 * paired with smp_mb() at the end of the function to=20
ensure
> +		 * paired with smp_wmb() at the end of the function to=20
ensure
>  		 * fields will only be observed after the bit is set.
>  		 */
> -		smp_mb();
> +		smp_rmb();
>  		return 0;
>  	}
>  	if (wait_on_bit_lock(&vi->flags, EROFS_I_BL_XATTR_BIT,=20
TASK_KILLABLE))
> @@ -111,8 +111,8 @@ static int erofs_init_inode_xattrs(struct inode *inod=
e)
>  		vi->xattr_shared_xattrs[i] =3D le32_to_cpu(*xattr_id);
>  	}
>=20
> -	/* paired with smp_mb() at the beginning of the function. */
> -	smp_mb();
> +	/* paired with smp_rmb() at the beginning of the function. */
> +	smp_wmb();
>  	set_bit(EROFS_I_EA_INITED_BIT, &vi->flags);
>  out_unlock:
>  	erofs_put_metabuf(&buf);
> diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
> index 5811556a7b71..d5b001a537f4 100644
> --- a/fs/erofs/zmap.c
> +++ b/fs/erofs/zmap.c
> @@ -628,10 +628,10 @@ static int z_erofs_fill_inode(struct inode *inode,
> struct erofs_map_blocks *map)
>=20
>  	if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) {
>  		/*
> -		 * paired with smp_mb() at the end of the function to=20
ensure
> +		 * paired with smp_wmb() at the end of the function to=20
ensure
>  		 * fields will only be observed after the bit is set.
>  		 */
> -		smp_mb();
> +		smp_rmb();
>  		return 0;
>  	}
>=20
> @@ -704,8 +704,8 @@ static int z_erofs_fill_inode(struct inode *inode,
> struct erofs_map_blocks *map) goto out_unlock;
>  	}
>  done:
> -	/* paired with smp_mb() at the beginning of the function */
> -	smp_mb();
> +	/* paired with smp_rmb() at the beginning of the function */
> +	smp_wmb();
>  	set_bit(EROFS_I_Z_INITED_BIT, &vi->flags);
>  out_unlock:
>  	clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags);
>=20
> ---
> base-commit: 11028ab62899e4191e074ee364c712b77823a9c4
> change-id: 20260729-erofs-weaken-dbar-9fd2edff90e5
>=20
> Best regards,
> --
> Bingwu Zhang <[email protected]>