aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarkady-e1ppa <arkady-e1ppa@yandex-team.com>2023-11-16 17:24:02 +0300
committerarkady-e1ppa <arkady-e1ppa@yandex-team.com>2023-11-16 18:51:45 +0300
commit6b40f0f1060a3e9d54347e52c7dc8fb278e6e86b (patch)
treeda4c8447ff495a023682292e1ac90309312ddb8f
parent8f8023320207d4dfa6e9b6c595fe272382595cdd (diff)
downloadydb-6b40f0f1060a3e9d54347e52c7dc8fb278e6e86b.tar.gz
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) Все эти действия имеют эффект только в дебаг сборке. В релизе вся эта диагностика стирается.
-rw-r--r--library/cpp/yt/threading/CMakeLists.darwin-x86_64.txt1
-rw-r--r--library/cpp/yt/threading/CMakeLists.linux-aarch64.txt1
-rw-r--r--library/cpp/yt/threading/CMakeLists.linux-x86_64.txt1
-rw-r--r--library/cpp/yt/threading/CMakeLists.windows-x86_64.txt1
-rw-r--r--library/cpp/yt/threading/recursive_spin_lock-inl.h6
-rw-r--r--library/cpp/yt/threading/recursive_spin_lock.h3
-rw-r--r--library/cpp/yt/threading/rw_spin_lock-inl.h13
-rw-r--r--library/cpp/yt/threading/rw_spin_lock.h16
-rw-r--r--library/cpp/yt/threading/spin_lock-inl.h6
-rw-r--r--library/cpp/yt/threading/spin_lock.h15
-rw-r--r--library/cpp/yt/threading/spin_lock_count-inl.h41
-rw-r--r--library/cpp/yt/threading/spin_lock_count.cpp43
-rw-r--r--library/cpp/yt/threading/spin_lock_count.h62
-rw-r--r--library/cpp/yt/threading/traceless_guard-inl.h115
-rw-r--r--library/cpp/yt/threading/traceless_guard.h29
-rw-r--r--library/cpp/yt/threading/ya.make1
-rw-r--r--yt/yt/core/concurrency/fiber_scheduler_thread.cpp3
-rw-r--r--yt/yt/library/ytprof/http/handler.cpp5
18 files changed, 342 insertions, 20 deletions
diff --git a/library/cpp/yt/threading/CMakeLists.darwin-x86_64.txt b/library/cpp/yt/threading/CMakeLists.darwin-x86_64.txt
index 7dbacb9da4..289553555a 100644
--- a/library/cpp/yt/threading/CMakeLists.darwin-x86_64.txt
+++ b/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
diff --git a/library/cpp/yt/threading/CMakeLists.linux-aarch64.txt b/library/cpp/yt/threading/CMakeLists.linux-aarch64.txt
index 644ee262f0..ae9721da48 100644
--- a/library/cpp/yt/threading/CMakeLists.linux-aarch64.txt
+++ b/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
diff --git a/library/cpp/yt/threading/CMakeLists.linux-x86_64.txt b/library/cpp/yt/threading/CMakeLists.linux-x86_64.txt
index 644ee262f0..ae9721da48 100644
--- a/library/cpp/yt/threading/CMakeLists.linux-x86_64.txt
+++ b/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
diff --git a/library/cpp/yt/threading/CMakeLists.windows-x86_64.txt b/library/cpp/yt/threading/CMakeLists.windows-x86_64.txt
index eedf3ebee2..c00337a5ca 100644
--- a/library/cpp/yt/threading/CMakeLists.windows-x86_64.txt
+++ b/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
diff --git a/library/cpp/yt/threading/recursive_spin_lock-inl.h b/library/cpp/yt/threading/recursive_spin_lock-inl.h
index ab829255d0..aca27ba1cf 100644
--- a/library/cpp/yt/threading/recursive_spin_lock-inl.h
+++ b/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
diff --git a/library/cpp/yt/threading/recursive_spin_lock.h b/library/cpp/yt/threading/recursive_spin_lock.h
index 59a39d9f8f..87df7166a5 100644
--- a/library/cpp/yt/threading/recursive_spin_lock.h
+++ b/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
diff --git a/library/cpp/yt/threading/rw_spin_lock-inl.h b/library/cpp/yt/threading/rw_spin_lock-inl.h
index 173059757c..779de1b64a 100644
--- a/library/cpp/yt/threading/rw_spin_lock-inl.h
+++ b/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
diff --git a/library/cpp/yt/threading/rw_spin_lock.h b/library/cpp/yt/threading/rw_spin_lock.h
index d1235dfc4a..a915e677e8 100644
--- a/library/cpp/yt/threading/rw_spin_lock.h
+++ b/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
{
diff --git a/library/cpp/yt/threading/spin_lock-inl.h b/library/cpp/yt/threading/spin_lock-inl.h
index 2e7b038eaf..b986c74e75 100644
--- a/library/cpp/yt/threading/spin_lock-inl.h
+++ b/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
diff --git a/library/cpp/yt/threading/spin_lock.h b/library/cpp/yt/threading/spin_lock.h
index d0d5c3cdbf..b8277ebc8d 100644
--- a/library/cpp/yt/threading/spin_lock.h
+++ b/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)
////////////////////////////////////////////////////////////////////////////////
diff --git a/library/cpp/yt/threading/spin_lock_count-inl.h b/library/cpp/yt/threading/spin_lock_count-inl.h
new file mode 100644
index 0000000000..196f833a87
--- /dev/null
+++ b/library/cpp/yt/threading/spin_lock_count-inl.h
@@ -0,0 +1,41 @@
+#pragma once
+#ifndef SPIN_LOCK_COUNT_INL_H_
+#error "Direct inclusion of this file is not allowed, include spin_lock_count.h"
+#endif
+#undef SPIN_LOCK_COUNT_INL_H_
+
+#include "public.h"
+#include "spin_lock_base.h"
+
+#ifdef NDEBUG
+#include <util/system/compiler.h>
+#endif
+
+#include <cstdint>
+
+namespace NYT::NThreading::NPrivate {
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef NDEBUG
+
+Y_FORCE_INLINE void RecordSpinLockAcquired([[maybe_unused]] bool isAcquired = true)
+{ }
+
+Y_FORCE_INLINE void RecordSpinLockReleased()
+{ }
+
+Y_FORCE_INLINE void VerifyNoSpinLockAffinity()
+{ }
+
+#else
+
+void RecordSpinLockAcquired(bool isAcquired = true);
+void RecordSpinLockReleased();
+void VerifyNoSpinLockAffinity();
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NThreading::NPrivate
diff --git a/library/cpp/yt/threading/spin_lock_count.cpp b/library/cpp/yt/threading/spin_lock_count.cpp
new file mode 100644
index 0000000000..501a8bd73e
--- /dev/null
+++ b/library/cpp/yt/threading/spin_lock_count.cpp
@@ -0,0 +1,43 @@
+
+#include "spin_lock_count.h"
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/yt/misc/tls.h>
+
+#include <util/system/types.h>
+
+namespace NYT::NThreading::NPrivate {
+
+#ifndef NDEBUG
+
+////////////////////////////////////////////////////////////////////////////////
+
+YT_THREAD_LOCAL(i64) ActiveSpinLockCount = 0;
+
+////////////////////////////////////////////////////////////////////////////////
+
+void RecordSpinLockAcquired(bool isAcquired)
+{
+ if (isAcquired) {
+ ActiveSpinLockCount++;
+ }
+}
+
+void RecordSpinLockReleased()
+{
+ YT_VERIFY(ActiveSpinLockCount > 0);
+ ActiveSpinLockCount--;
+}
+
+void VerifyNoSpinLockAffinity()
+{
+ YT_VERIFY(ActiveSpinLockCount == 0);
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NThreading::NPrivate
+
diff --git a/library/cpp/yt/threading/spin_lock_count.h b/library/cpp/yt/threading/spin_lock_count.h
new file mode 100644
index 0000000000..3640f231b2
--- /dev/null
+++ b/library/cpp/yt/threading/spin_lock_count.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#define SPIN_LOCK_COUNT_INL_H_
+#include "spin_lock_count-inl.h"
+#undef SPIN_LOCK_COUNT_INL_H_
+
+namespace NYT::NThreading {
+
+// Tracks the number of spinlocks currently held by the thread.
+// Generally useful to ensure that we are not holding a spinlock
+// in a given context.
+// Tracking is only active in debug builds.
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+// In order to properly support tracking in your spinlock you have to do two steps:
+// 1) Insert RecordSpinlockAcquired and RecordSpinlockReleased inside your
+// (Try)Acquire and Release calls.
+// 2) (Optional) Write REGISTER_TRACKED_SPIN_LOCK_CLASS(TSpinLock) for your spinlock
+// so that you can use algorithms aware of spinlock tracking.
+
+using NPrivate::RecordSpinLockAcquired;
+using NPrivate::RecordSpinLockReleased;
+
+template <class TSpinLock>
+struct TIsTrackedSpinLock
+ : public std::false_type
+{ };
+
+#define REGISTER_TRACKED_SPIN_LOCK_CLASS(Name) \
+ namespace NDetail { \
+ \
+ template <> \
+ struct TIsTrackedSpinLock<Name> \
+ : public std::true_type \
+ { }; \
+ \
+ } \
+
+} // namespace NDetail
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+concept CTrackedSpinLock = NDetail::TIsTrackedSpinLock<T>::value;
+//! Semantic requirements:
+//! 1) T must have a method successful call to which begins critical section (e.g. Acquire).
+//! 2) T must have a method successful call to which ends critical section (e.g. Release).
+//! In (1) and (2) "successful" is expected to have a definition given by T's author.
+//! 3) Beggining of a critical section CS must be sequenced before RecordSpinlockAcquired(true) call.
+//! 4) RecordSpinlockAcquired(true) call must be sequenced before RecordSpinlockReleased() call.
+//! 5) RecordSpinlockReleased() must be sequenced before the ending of the CS.
+
+////////////////////////////////////////////////////////////////////////////////
+
+using NPrivate::VerifyNoSpinLockAffinity;
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NThreading
diff --git a/library/cpp/yt/threading/traceless_guard-inl.h b/library/cpp/yt/threading/traceless_guard-inl.h
new file mode 100644
index 0000000000..e03d5196c4
--- /dev/null
+++ b/library/cpp/yt/threading/traceless_guard-inl.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#ifndef TRACELESS_GUARD_INL_H_
+#error "Direct inclusion of this file is not allowed, include traceless_guard.h"
+#endif
+#undef TRACELESS_GUARD_INL_H_
+
+#include "rw_spin_lock.h"
+#include "spin_lock_count.h"
+
+#include <util/system/guard.h>
+
+#include <concepts>
+
+namespace NYT::NThreading::NPrivate {
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef NDEBUG
+
+template <class T, class TOps = TCommonLockOps<T>>
+using TTracelessGuard = TGuard<T, TOps>;
+
+template <class T, class TOps = TCommonLockOps<T>>
+using TTracelessInverseGuard = TInverseGuard<T, TOps>;
+
+template <class T, class TOps = TTryLockOps<T>>
+using TTracelessTryGuard = TTryGuard<T, TOps>;
+
+template <class T>
+using TTracelessReaderGuard = TReaderGuard<T>;
+
+template <class T>
+using TTracelessWriterGuard = TWriterGuard<T>;
+
+#else
+
+template <class TOps>
+struct TTracelessOps
+ : public TOps
+{
+ template <class T>
+ static void Acquire(T* t) noexcept
+ {
+ TOps::Acquire(t);
+ NDetail::RecordSpinLockReleased();
+ }
+
+ template <class T>
+ static void Release(T* t) noexcept
+ {
+ NDetail::RecordSpinLockAcquired();
+ TOps::Release(t);
+ }
+
+ template <class T>
+ requires requires (T* t) { { TOps::TryAcquire(t) } -> std::same_as<bool>; }
+ static bool TryAcquire(T* t) noexcept
+ {
+ bool isAcquired = TOps::TryAcquire(t);
+
+ if (isAcquired) {
+ NDetail::RecordSpinLockReleased();
+ }
+
+ return isAcquired;
+ }
+};
+
+template <CTrackedSpinLock T, class TOps = TCommonLockOps<T>>
+using TTracelessGuard = TGuard<T, TTracelessOps<TOps>>;
+
+template <CTrackedSpinLock T, class TOps = TCommonLockOps<T>>
+using TTracelessInverseGuard = TInverseGuard<T, TTracelessOps<TOps>>;
+
+template <CTrackedSpinLock T, class TOps = TTryLockOps<T>>
+using TTracelessTryGuard = TTryGuard<T, TTracelessOps<TOps>>;
+
+template <CTrackedSpinLock T>
+using TTracelessReaderGuard = TGuard<T, TTracelessOps<TReaderSpinlockTraits<T>>>;
+
+template <CTrackedSpinLock T>
+using TTracelessWriterGuard = TGuard<T, TTracelessOps<TWriterSpinlockTraits<T>>>;
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <CTrackedSpinLock T>
+TTracelessGuard<T> TracelessGuard(const T& mutex)
+{
+ return {&mutex};
+}
+
+template <CTrackedSpinLock T>
+TTracelessTryGuard<T> TracelessTryGuard(const T& mutex)
+{
+ return {&mutex};
+}
+
+template <CTrackedSpinLock T>
+TTracelessReaderGuard<T> TracelessReaderGuard(const T& mutex)
+{
+ return {&mutex};
+}
+
+template <CTrackedSpinLock T>
+TTracelessWriterGuard<T> TracelessWriterGuard(const T& mutex)
+{
+ return {&mutex};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NThreading::NPrivate
diff --git a/library/cpp/yt/threading/traceless_guard.h b/library/cpp/yt/threading/traceless_guard.h
new file mode 100644
index 0000000000..10ad0ded98
--- /dev/null
+++ b/library/cpp/yt/threading/traceless_guard.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#define TRACELESS_GUARD_INL_H_
+#include "traceless_guard-inl.h"
+#undef TRACELESS_GUARD_INL_H_
+
+namespace NYT::NThreading {
+
+// This guards are zero-cost replacements for normal ones
+// which allow user to avoid spinlocks being tracked.
+
+////////////////////////////////////////////////////////////////////////////////
+
+using NPrivate::TTracelessGuard;
+using NPrivate::TTracelessInverseGuard;
+using NPrivate::TTracelessTryGuard;
+using NPrivate::TTracelessReaderGuard;
+using NPrivate::TTracelessWriterGuard;
+
+////////////////////////////////////////////////////////////////////////////////
+
+using NPrivate::TracelessGuard;
+using NPrivate::TracelessTryGuard;
+using NPrivate::TracelessReaderGuard;
+using NPrivate::TracelessWriterGuard;
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NThreading
diff --git a/library/cpp/yt/threading/ya.make b/library/cpp/yt/threading/ya.make
index 4f1d7fbdde..3b2cb13d4f 100644
--- a/library/cpp/yt/threading/ya.make
+++ b/library/cpp/yt/threading/ya.make
@@ -14,6 +14,7 @@ SRCS(
recursive_spin_lock.cpp
rw_spin_lock.cpp
spin_lock_base.cpp
+ spin_lock_count.cpp
spin_lock.cpp
spin_wait.cpp
spin_wait_hook.cpp
diff --git a/yt/yt/core/concurrency/fiber_scheduler_thread.cpp b/yt/yt/core/concurrency/fiber_scheduler_thread.cpp
index 60f0d81b8f..7fcb074e84 100644
--- a/yt/yt/core/concurrency/fiber_scheduler_thread.cpp
+++ b/yt/yt/core/concurrency/fiber_scheduler_thread.cpp
@@ -11,6 +11,8 @@
#include <yt/yt/core/misc/shutdown.h>
#include <yt/yt/core/misc/singleton.h>
+#include <library/cpp/yt/threading/spin_lock_count.h>
+
#include <yt/yt/core/tracing/trace_context.h>
#include <library/cpp/yt/memory/memory_tag.h>
@@ -948,6 +950,7 @@ void WaitUntilSet(TFuture<void> future, IInvokerPtr invoker)
return;
}
+ NThreading::VerifyNoSpinLockAffinity();
YT_VERIFY(invoker != GetSyncInvoker());
// Ensure canceler created.
diff --git a/yt/yt/library/ytprof/http/handler.cpp b/yt/yt/library/ytprof/http/handler.cpp
index 382ffc1fec..2dbc631957 100644
--- a/yt/yt/library/ytprof/http/handler.cpp
+++ b/yt/yt/library/ytprof/http/handler.cpp
@@ -18,6 +18,8 @@
#include <library/cpp/cgiparam/cgiparam.h>
+#include <library/cpp/yt/threading/traceless_guard.h>
+
#include <util/system/mutex.h>
namespace NYT::NYTProf {
@@ -40,7 +42,8 @@ public:
void HandleRequest(const IRequestPtr& req, const IResponseWriterPtr& rsp) override
{
try {
- TTryGuard guard(Lock_);
+ auto guard = NThreading::TracelessTryGuard(Lock_);
+
if (!guard) {
rsp->SetStatus(EStatusCode::TooManyRequests);
WaitFor(rsp->WriteBody(TSharedRef::FromString("Profile fetch already running")))