From 982f4254a1aa577d71a89f466053c0fb5ca004ed Mon Sep 17 00:00:00 2001 From: Connal de Souza Date: Fri, 31 Oct 2025 10:40:01 -0700 Subject: [PATCH] (Roll forward) Change Abseil's SpinLock adaptive_spin_count to a class static variable that can be set by tcmalloc friend classes. PiperOrigin-RevId: 826545231 Change-Id: Ic8918fdc0ebd46ea0423859ed62d667f7fe0ba57 --- absl/base/internal/spinlock.cc | 20 +++++++++++++------- absl/base/internal/spinlock.h | 11 +++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc index 4168b8b7..41d2b482 100644 --- a/absl/base/internal/spinlock.cc +++ b/absl/base/internal/spinlock.cc @@ -71,17 +71,23 @@ void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock, } // Monitor the lock to see if its value changes within some time period -// (adaptive_spin_count loop iterations). The last value read from the lock +// (adaptive_spin_count_ loop iterations). The last value read from the lock // is returned from the method. +ABSL_CONST_INIT std::atomic SpinLock::adaptive_spin_count_{0}; uint32_t SpinLock::SpinLoop() { // We are already in the slow path of SpinLock, initialize the // adaptive_spin_count here. - ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count; - ABSL_CONST_INIT static int adaptive_spin_count = 0; - LowLevelCallOnce(&init_adaptive_spin_count, - []() { adaptive_spin_count = NumCPUs() > 1 ? 1000 : 1; }); - - int c = adaptive_spin_count; + if (adaptive_spin_count_.load(std::memory_order_relaxed) == 0) { + int current_spin_count = 0; + int new_spin_count = NumCPUs() > 1 ? 1000 : 1; + // If this fails, the value will remain unchanged. We may not spin for the + // intended duration, but that is still safe. We will try again on the next + // call to SpinLoop. + adaptive_spin_count_.compare_exchange_weak( + current_spin_count, new_spin_count, std::memory_order_relaxed, + std::memory_order_relaxed); + } + int c = adaptive_spin_count_.load(std::memory_order_relaxed); uint32_t lock_value; do { lock_value = lockword_.load(std::memory_order_relaxed); diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h index ff2b0872..d0e16491 100644 --- a/absl/base/internal/spinlock.h +++ b/absl/base/internal/spinlock.h @@ -47,6 +47,7 @@ namespace tcmalloc { namespace tcmalloc_internal { class AllocationGuardSpinLockHolder; +class Static; } // namespace tcmalloc_internal } // namespace tcmalloc @@ -173,6 +174,16 @@ class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock { // Provide access to protected method above. Use for testing only. friend struct SpinLockTest; friend class tcmalloc::tcmalloc_internal::AllocationGuardSpinLockHolder; + friend class tcmalloc::tcmalloc_internal::Static; + + static int GetAdaptiveSpinCount() { + return adaptive_spin_count_.load(std::memory_order_relaxed); + } + static void SetAdaptiveSpinCount(int count) { + adaptive_spin_count_.store(count, std::memory_order_relaxed); + } + + static std::atomic adaptive_spin_count_; private: // lockword_ is used to store the following: