(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
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc index 4168b8b..41d2b48 100644 --- a/absl/base/internal/spinlock.cc +++ b/absl/base/internal/spinlock.cc
@@ -71,17 +71,23 @@ } // 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<int> 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 ff2b087..d0e1649 100644 --- a/absl/base/internal/spinlock.h +++ b/absl/base/internal/spinlock.h
@@ -47,6 +47,7 @@ namespace tcmalloc_internal { class AllocationGuardSpinLockHolder; +class Static; } // namespace tcmalloc_internal } // namespace tcmalloc @@ -173,6 +174,16 @@ // 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<int> adaptive_spin_count_; private: // lockword_ is used to store the following: