From 047ab5c838a767c8df6a03b273f6230bbbecdcb6 Mon Sep 17 00:00:00 2001
From: Sammy Dabbas <dabbassammy@gmail.com>
Date: Wed, 8 Jul 2026 14:15:44 -0400
Subject: [PATCH 1/2] Fix CPU FlashAttention disabled on Linux/aarch64 by
 detecting L2 cache via cpuinfo

glibc's aarch64 sysconf backend does not implement the cache-size queries, so PosixEnv::GetL2CacheSize() returns 0 and the l2_cache_size_ > 0 gate in MultiHeadAttention silently disables CPU FlashAttention. Query cpuinfo for the L2 size first, mirroring the existing cpuinfo_available_ usage in this file for physical-core count and thread affinity, and fall back to sysconf/sysctl. Guarded by ORT_USE_CPUINFO; x86-64 and Windows are unaffected.
---
 onnxruntime/core/platform/posix/env.cc | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc
index c34d8b3dbf696..7c22ec122cb03 100644
--- a/onnxruntime/core/platform/posix/env.cc
+++ b/onnxruntime/core/platform/posix/env.cc
@@ -302,6 +302,19 @@ class PosixEnv : public Env {
   }
 
   int GetL2CacheSize() const override {
+#ifdef ORT_USE_CPUINFO
+    // Prefer cpuinfo for detection. glibc's aarch64 sysconf backend does not
+    // implement the cache-size queries, so sysconf(_SC_LEVEL2_CACHE_SIZE)
+    // returns 0 on Linux/aarch64, which silently disables cache-tiled kernels
+    // (e.g. CPU FlashAttention in MultiHeadAttention). cpuinfo reads the sizes
+    // from sysfs cacheinfo and works across architectures.
+    if (cpuinfo_available_ && cpuinfo_get_l2_caches_count() > 0) {
+      const auto* l2_cache = cpuinfo_get_l2_cache(0);
+      if (l2_cache != nullptr && l2_cache->size > 0) {
+        return static_cast<int>(l2_cache->size);
+      }
+    }
+#endif  // ORT_USE_CPUINFO
 #ifdef _SC_LEVEL2_CACHE_SIZE
     return static_cast<int>(sysconf(_SC_LEVEL2_CACHE_SIZE));
 #else

From 187fa1973f3b4180bde5b5a90c236648a6a5fa82 Mon Sep 17 00:00:00 2001
From: Sammy Dabbas <dabbassammy@gmail.com>
Date: Fri, 10 Jul 2026 12:17:50 -0400
Subject: [PATCH 2/2] Prefer sysconf L2 cache size and fall back to cpuinfo
 only when it fails

sysconf(_SC_LEVEL2_CACHE_SIZE) is now queried first, so platforms
where it works, such as Linux/x86, keep their existing L2 cache
values unchanged. cpuinfo is used only as a fallback when sysconf
returns a value of zero or less, which is the glibc aarch64 case
where the cache-size queries are unimplemented and CPU
FlashAttention was being disabled.

Both return paths now use narrow<int> instead of static_cast<int>
so that narrowing the cache size to int is checked rather than
silently truncated.
---
 onnxruntime/core/platform/posix/env.cc | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc
index 7c22ec122cb03..c2ad29980b8f0 100644
--- a/onnxruntime/core/platform/posix/env.cc
+++ b/onnxruntime/core/platform/posix/env.cc
@@ -302,21 +302,27 @@ class PosixEnv : public Env {
   }
 
   int GetL2CacheSize() const override {
-#ifdef ORT_USE_CPUINFO
-    // Prefer cpuinfo for detection. glibc's aarch64 sysconf backend does not
-    // implement the cache-size queries, so sysconf(_SC_LEVEL2_CACHE_SIZE)
+#ifdef _SC_LEVEL2_CACHE_SIZE
+    // Prefer sysconf where it is implemented (e.g. Linux/x86), so those
+    // platforms keep their existing, working values. glibc's aarch64 backend
+    // does not implement the cache-size queries, so sysconf(_SC_LEVEL2_CACHE_SIZE)
     // returns 0 on Linux/aarch64, which silently disables cache-tiled kernels
-    // (e.g. CPU FlashAttention in MultiHeadAttention). cpuinfo reads the sizes
-    // from sysfs cacheinfo and works across architectures.
+    // (e.g. CPU FlashAttention in MultiHeadAttention). Only when sysconf reports
+    // no L2 do we fall back to cpuinfo, which reads the sizes from sysfs
+    // cacheinfo and works across architectures.
+    const auto l2_cache_size = sysconf(_SC_LEVEL2_CACHE_SIZE);
+    if (l2_cache_size > 0) {
+      return narrow<int>(l2_cache_size);
+    }
+#ifdef ORT_USE_CPUINFO
     if (cpuinfo_available_ && cpuinfo_get_l2_caches_count() > 0) {
       const auto* l2_cache = cpuinfo_get_l2_cache(0);
       if (l2_cache != nullptr && l2_cache->size > 0) {
-        return static_cast<int>(l2_cache->size);
+        return narrow<int>(l2_cache->size);
       }
     }
 #endif  // ORT_USE_CPUINFO
-#ifdef _SC_LEVEL2_CACHE_SIZE
-    return static_cast<int>(sysconf(_SC_LEVEL2_CACHE_SIZE));
+    return narrow<int>(l2_cache_size);
 #else
     int value = 0;  // unknown
 #if (defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)) && defined(HW_L2CACHESIZE)
