[glibc] x86: Fix non-temporal memset unreachable on AMD Zen 3/4/5

Adhemerval Zanella via Glibc-cvs <[email protected]> Wed, 20 May 2026 20:23:24 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=54abc8566fea592e795cb443949266ef206462a8

commit 54abc8566fea592e795cb443949266ef206462a8
Author: zombie12138 <[email protected]>
Date:   Tue May 5 22:38:01 2026 -0700

    x86: Fix non-temporal memset unreachable on AMD Zen 3/4/5
    
    On AMD Zen 3/4/5 with ERMS, the non-temporal memset path is unreachable
    because rep_stosb_threshold is set to SIZE_MAX (vectorized loop is faster
    than ERMS on these CPUs), but the non-temporal code path is nested inside
    the rep_stosb branch.
    
    The existing rescue logic at the Avoid_STOSB check only covers the case
    where the CPU lacks ERMS hardware support.  It does not cover AMD Zen 3+
    where ERMS is supported but deliberately unused for performance reasons.
    
    Extend the condition to also lower rep_stosb_threshold when:
    - The user has not explicitly set x86_rep_stosb_threshold (respect tunables)
    - rep_stosb_threshold is higher than memset_non_temporal_threshold (NT gated)
    
    This makes the non-temporal path reachable for large memset operations,
    providing ~2x speedup on pre-faulted buffers larger than L3 cache.
    
    Tested on AMD Ryzen 7 8745HS (Zen 4):
    - Pre-faulted 64MB memset: 2.02 ms -> 0.94 ms (2.15x faster)
    - First-touch 64MB memset: 19.3 ms -> 21.3 ms (11% regression, expected:
      kernel clear_page cache warming bypassed by NT stores)
    
            * sysdeps/x86/dl-cacheinfo.h (dl_init_cacheinfo): Extend
            rep_stosb_threshold lowering condition to cover AMD Zen 3/4/5
            where ERMS is supported but stosb is disabled via threshold.
    
    Signed-off-by: zombie12138 <[email protected]>
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34129
    Reviewed-by: Adhemerval Zanella  <[email protected]>

Diff:
---
 sysdeps/x86/dl-cacheinfo.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
index d18326f404..bc5abb8a6e 100644
--- a/sysdeps/x86/dl-cacheinfo.h
+++ b/sysdeps/x86/dl-cacheinfo.h
@@ -1308,7 +1308,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
   /* Do `rep_stosb_thresh = non_temporal_thresh` after setting/getting the
      final value of `x86_memset_non_temporal_threshold`. In some cases this can
      be a matter of correctness.  */
-  if (CPU_FEATURES_ARCH_P (cpu_features, Avoid_STOSB))
+  if (CPU_FEATURES_ARCH_P (cpu_features, Avoid_STOSB)
+      || (!TUNABLE_IS_INITIALIZED (x86_rep_stosb_threshold)
+	  && rep_stosb_threshold > memset_non_temporal_threshold))
     rep_stosb_threshold
 	= TUNABLE_GET (x86_memset_non_temporal_threshold, long int, NULL);
   TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1,