From 047ab5c838a767c8df6a03b273f6230bbbecdcb6 Mon Sep 17 00:00:00 2001 From: Sammy Dabbas 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(l2_cache->size); + } + } +#endif // ORT_USE_CPUINFO #ifdef _SC_LEVEL2_CACHE_SIZE return static_cast(sysconf(_SC_LEVEL2_CACHE_SIZE)); #else From 187fa1973f3b4180bde5b5a90c236648a6a5fa82 Mon Sep 17 00:00:00 2001 From: Sammy Dabbas 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 instead of static_cast 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(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(l2_cache->size); + return narrow(l2_cache->size); } } #endif // ORT_USE_CPUINFO -#ifdef _SC_LEVEL2_CACHE_SIZE - return static_cast(sysconf(_SC_LEVEL2_CACHE_SIZE)); + return narrow(l2_cache_size); #else int value = 0; // unknown #if (defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)) && defined(HW_L2CACHESIZE)