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

From: Bingwu Zhang

Date: Thu Jul 30 2026 - 06:14:24 EST


On Thursday, July 30, 2026 12:01:20 PM China Standard Time Bingwu Zhang wrote:
> From: Bingwu Zhang <xtex@xxxxxxxxxxxxx>
>
> fs/erofs/{xattr.c,zmap.c} both implemented one-time initialization locks
> with general memory barriers.
>
> Weaken these unnecessarily-strong general memory barriers to SMP
> (ordering) read/write barriers for better performance on weakly-ordered
> architectures.
>
> Signed-off-by: Bingwu Zhang <xtex@xxxxxxxxxxxxx>
> ---
> (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=1 --all-root -zzstd -E48bit)
>
> 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.
>
> On weakly-ordered architectures, a full memory barrier could be very
> expensive. Thus, on these platforms, this patch saves more performance
> than x86-64.
>
> 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=1684, BW=6737KiB/s (6899kB/s)(1006MiB/152838msec)
> clat (usec): min=25, max=26293, avg=578.58, stdev=426.55
> lat (usec): min=25, max=26293, avg=578.70, stdev=426.56
> bw ( KiB/s): min= 1976, max=10904, per=100.00%, avg=6749.91,
> stdev=1883.80, samples=305
> iops : min= 494, max= 2726, avg=1687.48, stdev=470.95,
> samples=305
>
> New:
> read: IOPS=1687, BW=6751KiB/s (6913kB/s)(1006MiB/152513msec)
> clat (usec): min=25, max=19136, avg=577.00, stdev=425.66
> lat (usec): min=25, max=19136, avg=577.09, stdev=425.67
> bw ( KiB/s): min= 2192, max=11088, per=100.00%, avg=6770.26
> stdev=1870.55, samples=304
> iops : min= 548, max= 2772, avg=1692.44, stdev=467.65,
> samples=304
>
> IOPS +0.17%, bandwidth +0.20%, max completion latency -27.22%
note: this line might be inaccurate, too
>

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
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 patch
could change so much on x86)

I am not familiar with benchmarking and please let me know if I did anything
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=12.3k, BW=47.9MiB/s (50.2MB/s)(1291MiB/26950msec)
> clat (nsec): min=910, max=37500k, avg=56026.68, stdev=198628.59
> lat (nsec): min=960, max=37500k, avg=56167.70, stdev=198639.09
> bw ( KiB/s): min= 3888, max=94328, per=100.00%, avg=49790.64,
> stdev=31594.09, samples=53
> iops : min= 972, max=23582, avg=12447.57, stdev=7898.51,
> samples=53
>
> New:
> read: IOPS=13.8k, BW=54.0MiB/s (56.6MB/s)(1315MiB/24375msec)
> clat (nsec): min=930, max=34271k, avg=53069.97, stdev=145651.76
> lat (nsec): min=980, max=34271k, avg=53221.68, stdev=145661.24
> bw ( KiB/s): min= 5843, max=95054, per=100.00%, avg=55988.58,
> stdev=30477.44, samples=48
> iops : min= 1460, max=23763, avg=13997.00, stdev=7619.37,
> samples=48
>
> 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%
>
> 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(-)
>
> 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 *inode)
> /* 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
ensure
> + * paired with smp_wmb() at the end of the function to
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,
TASK_KILLABLE))
> @@ -111,8 +111,8 @@ static int erofs_init_inode_xattrs(struct inode *inode)
> vi->xattr_shared_xattrs[i] = le32_to_cpu(*xattr_id);
> }
>
> - /* 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)
>
> if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) {
> /*
> - * paired with smp_mb() at the end of the function to
ensure
> + * paired with smp_wmb() at the end of the function to
ensure
> * fields will only be observed after the bit is set.
> */
> - smp_mb();
> + smp_rmb();
> return 0;
> }
>
> @@ -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);
>
> ---
> base-commit: 11028ab62899e4191e074ee364c712b77823a9c4
> change-id: 20260729-erofs-weaken-dbar-9fd2edff90e5
>
> Best regards,
> --
> Bingwu Zhang <xtex@xxxxxxxxxxxxx>