Browse Source

Active spinlock tracking from pr3151306. Added TracelessGuards to disable mentioned tracking

1) Добавлена возможность инструментировать ваш любимый мьютекс/спинлок/что-либо с методами Acquire/Release со схожим смыслом. Делается это засчет методов ```NThreading::NDetail::RecordSpinlockAcquired```/```NThreading::NDetail::RecordSpinlockReleased```. Они отслеживают число захваченных спинлоков.

2) Добавлен макрос ```REGISTER_TRACKED_SPIN_LOCK_CLASS```, который позволяет номинально проверить на этапе компиляции, что данный спинлок отслеживается.

3) Добавлен метод ```NThreading::VerifyNoSpinlockAffinity```, который коркается, если число захваченных спинлоков больше нуля.

4) Добавлены Traceless версии (почти) всех гардов, чтобы можно было не отслеживать конкретную критическую секцию, если очень нужно.

5) Внутри файберного ```WaitUntilSet``` вызывается ```VerifyNoSpinlockAffinity``` -- делать ```WaitFor``` или ```Yield``` внутри отслеживаемых критических секций нельзя. Если очень хочется -- используем TracelessGuard нужного вида.

6) Теперь отслеживаются такие спинлоки и их наследники: ```TSpinLock```, ```TRecursiveSpinLock```, ```TReaderWriterSpinLock```.

7) Зарегистрированы как отслеживаемые все вышеперечисленные спинлоки и их Padded версии.

8) Все эти действия имеют эффект только в дебаг сборке. В релизе вся эта диагностика стирается.
arkady-e1ppa 1 year ago
parent
commit
6b40f0f106

+ 1 - 0
library/cpp/yt/threading/CMakeLists.darwin-x86_64.txt

@@ -31,6 +31,7 @@ target_sources(cpp-yt-threading PRIVATE
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/recursive_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/rw_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_base.cpp
+  ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_count.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait_hook.cpp

+ 1 - 0
library/cpp/yt/threading/CMakeLists.linux-aarch64.txt

@@ -32,6 +32,7 @@ target_sources(cpp-yt-threading PRIVATE
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/recursive_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/rw_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_base.cpp
+  ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_count.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait_hook.cpp

+ 1 - 0
library/cpp/yt/threading/CMakeLists.linux-x86_64.txt

@@ -32,6 +32,7 @@ target_sources(cpp-yt-threading PRIVATE
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/recursive_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/rw_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_base.cpp
+  ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_count.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait_hook.cpp

+ 1 - 0
library/cpp/yt/threading/CMakeLists.windows-x86_64.txt

@@ -28,6 +28,7 @@ target_sources(cpp-yt-threading PRIVATE
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/recursive_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/rw_spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_base.cpp
+  ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock_count.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_lock.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait.cpp
   ${CMAKE_SOURCE_DIR}/library/cpp/yt/threading/spin_wait_hook.cpp

+ 5 - 1
library/cpp/yt/threading/recursive_spin_lock-inl.h

@@ -30,7 +30,10 @@ inline bool TRecursiveSpinLock::TryAcquire() noexcept
         return false;
     }
     auto newValue = (oldRecursionDepth + 1) | (static_cast<TValue>(currentThreadId) << ThreadIdShift);
-    return Value_.compare_exchange_weak(oldValue, newValue);
+
+    bool acquired = Value_.compare_exchange_weak(oldValue, newValue);
+    NDetail::RecordSpinLockAcquired(acquired);
+    return acquired;
 }
 
 inline void TRecursiveSpinLock::Release() noexcept
@@ -41,6 +44,7 @@ inline void TRecursiveSpinLock::Release() noexcept
     YT_ASSERT((value >> ThreadIdShift) == GetSequentialThreadId());
 #endif
     --Value_;
+    NDetail::RecordSpinLockReleased();
 }
 
 inline bool TRecursiveSpinLock::IsLocked() const noexcept

+ 3 - 0
library/cpp/yt/threading/recursive_spin_lock.h

@@ -2,6 +2,7 @@
 
 #include "public.h"
 #include "spin_lock_base.h"
+#include "spin_lock_count.h"
 
 #include <library/cpp/yt/system/thread_id.h>
 
@@ -44,6 +45,8 @@ private:
     void AcquireSlow() noexcept;
 };
 
+REGISTER_TRACKED_SPIN_LOCK_CLASS(TRecursiveSpinLock)
+
 ////////////////////////////////////////////////////////////////////////////////
 
 } // namespace NYT::NThreading

+ 11 - 2
library/cpp/yt/threading/rw_spin_lock-inl.h

@@ -32,6 +32,7 @@ inline void TReaderWriterSpinLock::ReleaseReader() noexcept
 {
     auto prevValue = Value_.fetch_sub(ReaderDelta, std::memory_order::release);
     Y_ASSERT((prevValue & ~WriterMask) != 0);
+    NDetail::RecordSpinLockReleased();
 }
 
 inline void TReaderWriterSpinLock::AcquireWriter() noexcept
@@ -46,6 +47,7 @@ inline void TReaderWriterSpinLock::ReleaseWriter() noexcept
 {
     auto prevValue = Value_.fetch_and(~WriterMask, std::memory_order::release);
     Y_ASSERT(prevValue & WriterMask);
+    NDetail::RecordSpinLockReleased();
 }
 
 inline bool TReaderWriterSpinLock::IsLocked() const noexcept
@@ -70,6 +72,7 @@ inline bool TReaderWriterSpinLock::TryAcquireReader() noexcept
         Value_.fetch_sub(ReaderDelta, std::memory_order::relaxed);
         return false;
     }
+    NDetail::RecordSpinLockAcquired();
     return true;
 }
 
@@ -89,13 +92,19 @@ inline bool TReaderWriterSpinLock::TryAcquireReaderForkFriendly() noexcept
         return false;
     }
     auto newValue = oldValue + ReaderDelta;
-    return Value_.compare_exchange_weak(oldValue, newValue, std::memory_order::acquire);
+
+    bool acquired = Value_.compare_exchange_weak(oldValue, newValue, std::memory_order::acquire);
+    NDetail::RecordSpinLockAcquired(acquired);
+    return acquired;
 }
 
 inline bool TReaderWriterSpinLock::TryAcquireWriter() noexcept
 {
     auto expected = UnlockedValue;
-    return Value_.compare_exchange_weak(expected, WriterMask, std::memory_order::acquire);
+
+    bool acquired =  Value_.compare_exchange_weak(expected, WriterMask, std::memory_order::acquire);
+    NDetail::RecordSpinLockAcquired(acquired);
+    return acquired;
 }
 
 inline bool TReaderWriterSpinLock::TryAndTryAcquireWriter() noexcept

+ 8 - 8
library/cpp/yt/threading/rw_spin_lock.h

@@ -2,6 +2,7 @@
 
 #include "public.h"
 #include "spin_lock_base.h"
+#include "spin_lock_count.h"
 
 #include <library/cpp/yt/memory/public.h>
 
@@ -106,16 +107,16 @@ private:
     void AcquireWriterSlow() noexcept;
 };
 
+REGISTER_TRACKED_SPIN_LOCK_CLASS(TReaderWriterSpinLock)
+
 ////////////////////////////////////////////////////////////////////////////////
 
-//! A variant of TReaderWriterSpinLock occupyig the whole cache line.
-class TPaddedReaderWriterSpinLock
+//! A variant of TReaderWriterSpinLock occupying the whole cache line.
+class alignas(CacheLineSize) TPaddedReaderWriterSpinLock
     : public TReaderWriterSpinLock
-{
-private:
-    [[maybe_unused]]
-    char Padding_[CacheLineSize - sizeof(TReaderWriterSpinLock)];
-};
+{ };
+
+REGISTER_TRACKED_SPIN_LOCK_CLASS(TPaddedReaderWriterSpinLock)
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -133,7 +134,6 @@ struct TForkFriendlyReaderSpinlockTraits
     static void Release(T* spinlock);
 };
 
-
 template <class T>
 struct TWriterSpinlockTraits
 {

+ 5 - 1
library/cpp/yt/threading/spin_lock-inl.h

@@ -30,6 +30,7 @@ inline void TSpinLock::Release() noexcept
 #else
     YT_ASSERT(Value_.exchange(UnlockedValue, std::memory_order::release) != UnlockedValue);
 #endif
+    NDetail::RecordSpinLockReleased();
 }
 
 inline bool TSpinLock::IsLocked() const noexcept
@@ -45,11 +46,14 @@ inline bool TSpinLock::TryAcquire() noexcept
 #else
     auto newValue = LockedValue;
 #endif
-    return Value_.compare_exchange_weak(
+
+    bool acquired = Value_.compare_exchange_weak(
         expectedValue,
         newValue,
         std::memory_order::acquire,
         std::memory_order::relaxed);
+    NDetail::RecordSpinLockAcquired(acquired);
+    return acquired;
 }
 
 inline bool TSpinLock::TryAndTryAcquire() noexcept

+ 8 - 7
library/cpp/yt/threading/spin_lock.h

@@ -2,6 +2,7 @@
 
 #include "public.h"
 #include "spin_lock_base.h"
+#include "spin_lock_count.h"
 
 #include <library/cpp/yt/misc/port.h>
 
@@ -62,16 +63,16 @@ private:
     void AcquireSlow() noexcept;
 };
 
+REGISTER_TRACKED_SPIN_LOCK_CLASS(TSpinLock)
+
 ////////////////////////////////////////////////////////////////////////////////
 
-//! A variant of TReaderWriterSpinLock occupyig the whole cache line.
-class TPaddedSpinLock
+//! A variant of TSpinLock occupying the whole cache line.
+class alignas(CacheLineSize) TPaddedSpinLock
     : public TSpinLock
-{
-private:
-    [[maybe_unused]]
-    char Padding_[CacheLineSize - sizeof(TSpinLock)];
-};
+{ };
+
+REGISTER_TRACKED_SPIN_LOCK_CLASS(TPaddedSpinLock)
 
 ////////////////////////////////////////////////////////////////////////////////
 

Some files were not shown because too many files changed in this diff