diff options
author | babenko <babenko@yandex-team.com> | 2024-09-09 18:48:41 +0300 |
---|---|---|
committer | babenko <babenko@yandex-team.com> | 2024-09-09 19:02:18 +0300 |
commit | d3e48fe4feee0750b9edd6b987e4637d4f678f29 (patch) | |
tree | 59e6c11bf3828c3683d65a4dcface6fbae8ced9c | |
parent | ab9b1efed10713e3420ece39a521ec5273efd375 (diff) | |
download | ydb-d3e48fe4feee0750b9edd6b987e4637d4f678f29.tar.gz |
YT-22593: Switch (some) trace context tags to std::string and refactor code around [TRIVIAL]
643d86a500b7db9df11009f54364b468b29a409a
29 files changed, 580 insertions, 644 deletions
diff --git a/library/cpp/yt/memory/allocation_tags.h b/library/cpp/yt/memory/allocation_tags.h new file mode 100644 index 0000000000..5bd0f415c6 --- /dev/null +++ b/library/cpp/yt/memory/allocation_tags.h @@ -0,0 +1,16 @@ +#pragma once + +#include <string> +#include <utility> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +using TAllocationTagKey = std::string; +using TAllocationTagValue = std::string; +using TAllocationTag = std::pair<TAllocationTagKey, TAllocationTagValue>; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/memory/allocation_tags_hooks.cpp b/library/cpp/yt/memory/allocation_tags_hooks.cpp new file mode 100644 index 0000000000..dc6d531f3e --- /dev/null +++ b/library/cpp/yt/memory/allocation_tags_hooks.cpp @@ -0,0 +1,27 @@ +#include "allocation_tags_hooks.h" + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK const TAllocationTagsHooks& GetAllocationTagsHooks() +{ + static const TAllocationTagsHooks hooks{ + .CreateAllocationTags = [] () -> void* { + return nullptr; + }, + .CopyAllocationTags = [] (void* /*opaque*/) -> void* { + return nullptr; + }, + .DestroyAllocationTags = [] (void* /*opaque*/) { + }, + .ReadAllocationTags = [] (void* /*opaque*/) -> TRange<TAllocationTag> { + return {}; + }, + }; + return hooks; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/memory/allocation_tags_hooks.h b/library/cpp/yt/memory/allocation_tags_hooks.h new file mode 100644 index 0000000000..57673f68b0 --- /dev/null +++ b/library/cpp/yt/memory/allocation_tags_hooks.h @@ -0,0 +1,23 @@ +#pragma once + +#include "allocation_tags.h" + +#include <library/cpp/yt/memory/range.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +struct TAllocationTagsHooks +{ + void* (*CreateAllocationTags)(); + void* (*CopyAllocationTags)(void* opaque); + void (*DestroyAllocationTags)(void* opaque); + TRange<TAllocationTag> (*ReadAllocationTags)(void* opaque); +}; + +const TAllocationTagsHooks& GetAllocationTagsHooks(); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/memory/ya.make b/library/cpp/yt/memory/ya.make index 9dc4372729..c2d78b0d07 100644 --- a/library/cpp/yt/memory/ya.make +++ b/library/cpp/yt/memory/ya.make @@ -3,6 +3,7 @@ LIBRARY() INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) SRCS( + allocation_tags_hooks.cpp blob.cpp chunked_input_stream.cpp chunked_memory_allocator.cpp diff --git a/yt/yt/core/rpc/helpers.cpp b/yt/yt/core/rpc/helpers.cpp index c6fbdaa099..9341cbc51b 100644 --- a/yt/yt/core/rpc/helpers.cpp +++ b/yt/yt/core/rpc/helpers.cpp @@ -446,10 +446,7 @@ TTraceContextPtr CreateCallTraceContext(std::string service, std::string method) return oldTraceContext; } - auto traceContext = oldTraceContext->CreateChild(Format("RpcClient:%v.%v", service, method)); - traceContext->SetAllocationTagsPtr(oldTraceContext->GetAllocationTagsPtr()); - - return traceContext; + return oldTraceContext->CreateChild(Format("RpcClient:%v.%v", service, method)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/yt/yt/core/rpc/unittests/rpc_allocation_tags_ut.cpp b/yt/yt/core/rpc/unittests/rpc_allocation_tags_ut.cpp index b2ad0c5ddf..919981feb0 100644 --- a/yt/yt/core/rpc/unittests/rpc_allocation_tags_ut.cpp +++ b/yt/yt/core/rpc/unittests/rpc_allocation_tags_ut.cpp @@ -32,6 +32,7 @@ TYPED_TEST(TRpcTest, ResponseWithAllocationTags) auto memoryUsageTracker = this->GetMemoryUsageTracker(); auto previousLimit = memoryUsageTracker->GetLimit(); memoryUsageTracker->SetLimit(2_GB); + static TMemoryTag testMemoryTag = 1 << 20; testMemoryTag++; diff --git a/yt/yt/core/tracing/allocation_hooks.cpp b/yt/yt/core/tracing/allocation_hooks.cpp deleted file mode 100644 index 36be840cfa..0000000000 --- a/yt/yt/core/tracing/allocation_hooks.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "allocation_tags.h" -#include "trace_context.h" - -#include <library/cpp/yt/memory/leaky_singleton.h> - -#include <thread> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -using namespace NTracing; - -static auto* FreeList = LeakySingleton<TAllocationTagsFreeList>(); - -void* CreateAllocationTagsData() -{ - auto* traceContext = TryGetCurrentTraceContext(); - if (!traceContext) { - return nullptr; - } - - // Need to avoid deadlock from TTraceContext->SetAllocationTags due another allocation. - auto allocationTags = traceContext->GetAllocationTagsPtr(); - - return static_cast<void*>(allocationTags.Release()); -} - -void* CopyAllocationTagsData(void* userData) -{ - if (userData) { - auto* allocationTagsPtr = static_cast<TAllocationTags*>(userData); - allocationTagsPtr->Ref(); - } - return userData; -} - -void DestroyAllocationTagsData(void* userData) -{ - auto* allocationTagsPtr = static_cast<TAllocationTags*>(userData); - // NB. No need to check for nullptr here, because ScheduleFree already does that. - FreeList->ScheduleFree(allocationTagsPtr); -} - -const TAllocationTags::TTags* ReadAllocationTagsData(void* userData) -{ - if (!userData) { - return nullptr; - } - - const auto* allocationTagsPtr = static_cast<TAllocationTags*>(userData); - return allocationTagsPtr->GetTagsPtr(); -} - -std::optional<TString> FindTagValue( - const TAllocationTags::TTags& tags, - const TString& key) -{ - return TAllocationTags::FindTagValue(tags, key); -} - -void StartAllocationTagsCleanupThread(TDuration cleanupInterval) -{ - std::thread backgroundThread([cleanupInterval] { - for (;;) { - FreeList->Cleanup(); - Sleep(cleanupInterval); - } - }); - backgroundThread.detach(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT diff --git a/yt/yt/core/tracing/allocation_tags.cpp b/yt/yt/core/tracing/allocation_tags.cpp index e38154db17..7bd7d043a8 100644 --- a/yt/yt/core/tracing/allocation_tags.cpp +++ b/yt/yt/core/tracing/allocation_tags.cpp @@ -4,70 +4,23 @@ namespace NYT::NTracing { //////////////////////////////////////////////////////////////////////////////// -TAllocationTags::TAllocationTags(std::vector<std::pair<TString, TString>> tags) +TAllocationTagList::TAllocationTagList(TAllocationTags tags) : Tags_(std::move(tags)) { } -const TAllocationTags::TTags& TAllocationTags::GetTags() const noexcept +const TAllocationTags& TAllocationTagList::GetTags() const noexcept { return Tags_; } -const TAllocationTags::TTags* TAllocationTags::GetTagsPtr() const noexcept +std::optional<TAllocationTagValue> TAllocationTagList::FindTagValue(const TAllocationTagKey& key) const { - return &Tags_; -} - -std::optional<TAllocationTags::TValue> TAllocationTags::FindTagValue(const TKey& key) const -{ - return FindTagValue(Tags_, key); -} - -std::optional<TAllocationTags::TValue> TAllocationTags::FindTagValue( - const TTags& tags, - const TKey& key) -{ - std::optional<TAllocationTags::TValue> value; - - for (const auto& [key_, value_] : tags) { - if (key_ == key) { - value = value_; - break; + for (const auto& [someKey, someValue] : Tags_) { + if (someKey == key) { + return someValue; } } - - return value; -} - -TAllocationTagsFreeList::~TAllocationTagsFreeList() -{ - Cleanup(); -} - -void TAllocationTagsFreeList::ScheduleFree(TAllocationTags* tagsRawPtr) -{ - if (tagsRawPtr == nullptr) { - return; - } - if (!GetRefCounter(tagsRawPtr)->Unref()) { - return; - } - YT_VERIFY(tagsRawPtr->Next_ == nullptr); - auto guard = Guard(Spinlock_); - tagsRawPtr->Next_ = Head_; - Head_ = tagsRawPtr; -} - -void TAllocationTagsFreeList::Cleanup() -{ - auto guard = Guard(Spinlock_); - auto head = std::exchange(Head_, nullptr); - guard.Release(); - while (head != nullptr) { - auto oldHead = head; - head = head->Next_; - DestroyRefCounted(oldHead); - } + return std::nullopt; } //////////////////////////////////////////////////////////////////////////////// diff --git a/yt/yt/core/tracing/allocation_tags.h b/yt/yt/core/tracing/allocation_tags.h index ea7b5a6447..69960431ce 100644 --- a/yt/yt/core/tracing/allocation_tags.h +++ b/yt/yt/core/tracing/allocation_tags.h @@ -2,59 +2,28 @@ #include "public.h" -#include <library/cpp/yt/threading/spin_lock.h> +#include <yt/yt/core/misc/intrusive_mpsc_stack.h> namespace NYT::NTracing { //////////////////////////////////////////////////////////////////////////////// -class TAllocationTags : public TRefCounted +//! An immutable ref-counted list of allocation tags. +class TAllocationTagList + : public TRefCounted + , public TIntrusiveListItem<TAllocationTagList> { public: - using TKey = TString; - using TValue = TString; - using TTags = std::vector<std::pair<TKey, TValue>>; + explicit TAllocationTagList(TAllocationTags tags); - explicit TAllocationTags(TTags tags); - - const TTags& GetTags() const noexcept; - - const TTags* GetTagsPtr() const noexcept; - - std::optional<TValue> FindTagValue(const TKey& key) const; - - static std::optional<TValue> FindTagValue( - const TTags& tags, - const TKey& key); + const TAllocationTags& GetTags() const noexcept; + std::optional<TAllocationTagValue> FindTagValue(const TAllocationTagKey& key) const; private: - friend class TAllocationTagsFreeList; - - const TTags Tags_; - TAllocationTags* Next_ = nullptr; + const TAllocationTags Tags_; }; -DEFINE_REFCOUNTED_TYPE(TAllocationTags) - -class TAllocationTagsFreeList -{ -public: - //! Decreases refcount of tagsRawPtr. If refcount becomes zero, puts the pointer into queue. - //! - //! The intended usage is - //! list->ScheduleFree(tags.Release()); - //! where tags is TAllocationTagsPtr. - void ScheduleFree(TAllocationTags* tagsRawPtr); - - //! Free all the pointers in the queue. - void Cleanup(); - - ~TAllocationTagsFreeList(); - -private: - YT_DECLARE_SPIN_LOCK(NThreading::TSpinLock, Spinlock_); - TAllocationTags* Head_ = nullptr; -}; +DEFINE_REFCOUNTED_TYPE(TAllocationTagList) //////////////////////////////////////////////////////////////////////////////// diff --git a/yt/yt/core/tracing/allocation_tags_hooks.cpp b/yt/yt/core/tracing/allocation_tags_hooks.cpp new file mode 100644 index 0000000000..1ded85fdc8 --- /dev/null +++ b/yt/yt/core/tracing/allocation_tags_hooks.cpp @@ -0,0 +1,116 @@ +#include "trace_context.h" + +#include <library/cpp/yt/memory/allocation_tags_hooks.h> +#include <library/cpp/yt/memory/leaky_singleton.h> + +#include <util/system/thread.h> + +#include <thread> + +namespace NYT::NTracing { + +//////////////////////////////////////////////////////////////////////////////// + +class TAllocationTagsReclaimer +{ +public: + TAllocationTagsReclaimer() + { + std::thread thread([this] { + TThread::SetCurrentThreadName("AllocTagsReclaim"); + while (true) { + DoReclaim(); + Sleep(ReclaimPeriod); + } + }); + thread.detach(); + } + + void ScheduleReclaim(TAllocationTagList* list) + { + if (GetRefCounter(list)->Unref()) { + ListsToReclaim_.Push(list); + } + } + + static TAllocationTagsReclaimer* Get() + { + return LeakySingleton<TAllocationTagsReclaimer>(); + } + +private: + TIntrusiveMpscStack<TAllocationTagList> ListsToReclaim_; + + static constexpr TDuration ReclaimPeriod = TDuration::Seconds(5); + + void DoReclaim() + { + auto items = ListsToReclaim_.PopAll(); + while (!items.Empty()) { + DestroyRefCounted(items.PopFront()->Node()); + } + } +}; + +void* CreateAllocationTags() +{ + const auto* traceContext = TryGetCurrentTraceContext(); + if (!traceContext) { + return nullptr; + } + + return traceContext->GetAllocationTagList().Release(); +} + +void* CopyAllocationTags(void* opaque) +{ + if (opaque) { + static_cast<TAllocationTagList*>(opaque)->Ref(); + } + + return opaque; +} + +void DestroyAllocationTags(void* opaque) +{ + if (auto* list = static_cast<TAllocationTagList*>(opaque)) { + TAllocationTagsReclaimer::Get()->ScheduleReclaim(list); + } +} + +TRange<TAllocationTag> ReadAllocationTags(void* opaque) +{ + if (!opaque) { + return {}; + } + + const auto* list = static_cast<TAllocationTagList*>(opaque); + return list->GetTags(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NTracing + +namespace NYT { + +using namespace NTracing; + +//////////////////////////////////////////////////////////////////////////////// + +const TAllocationTagsHooks& GetAllocationTagsHooks() +{ + // Boot the reclaimer up here, in a seemingly safe context. + TAllocationTagsReclaimer::Get(); + static const TAllocationTagsHooks hooks{ + .CreateAllocationTags = CreateAllocationTags, + .CopyAllocationTags = CopyAllocationTags, + .DestroyAllocationTags = DestroyAllocationTags, + .ReadAllocationTags = ReadAllocationTags, + }; + return hooks; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/yt/yt/core/tracing/public.h b/yt/yt/core/tracing/public.h index 9d864133aa..1afb4c6009 100644 --- a/yt/yt/core/tracing/public.h +++ b/yt/yt/core/tracing/public.h @@ -4,6 +4,10 @@ #include <library/cpp/yt/misc/guid.h> +#include <library/cpp/yt/small_containers/compact_vector.h> + +#include <library/cpp/yt/memory/allocation_tags.h> + namespace NYT::NTracing { //////////////////////////////////////////////////////////////////////////////// @@ -14,11 +18,16 @@ class TTracingExt; } // namespace NProto +//////////////////////////////////////////////////////////////////////////////// + DECLARE_REFCOUNTED_CLASS(TTraceContext) DECLARE_REFCOUNTED_CLASS(TTracingTransportConfig) -DECLARE_REFCOUNTED_CLASS(TAllocationTags) +constexpr int TypicalAllocationTagCount = 8; +using TAllocationTags = TCompactVector<TAllocationTag, TypicalAllocationTagCount>; + +DECLARE_REFCOUNTED_CLASS(TAllocationTagList) using TTraceId = TGuid; constexpr TTraceId InvalidTraceId = {}; diff --git a/yt/yt/core/tracing/trace_context-inl.h b/yt/yt/core/tracing/trace_context-inl.h index 640fcaa2a6..a856735430 100644 --- a/yt/yt/core/tracing/trace_context-inl.h +++ b/yt/yt/core/tracing/trace_context-inl.h @@ -75,105 +75,60 @@ Y_FORCE_INLINE NProfiling::TCpuDuration TTraceContext::GetElapsedCpuTime() const } template <class T> -void TTraceContext::AddTag(const TString& tagName, const T& tagValue) +void TTraceContext::AddTag(const std::string& tagName, const T& tagValue) { if (!IsRecorded()) { return; } using ::ToString; - AddTag(tagName, ToString(tagValue)); + // TODO(babenko): migrate to std::string + AddTag(tagName, std::string(ToString(tagValue))); } -template <typename TTag> -std::optional<TTag> TTraceContext::DoFindAllocationTag(const TString& key) const +template <typename T> +std::optional<T> TTraceContext::FindAllocationTag(const TAllocationTagKey& key) const { - VERIFY_SPINLOCK_AFFINITY(AllocationTagsLock_); - - TAllocationTagsPtr tags; - - { - // Local guard for copy RefCounted AllocationTags_. - auto guard = Guard(AllocationTagsAsRefCountedLock_); - tags = AllocationTags_; - } - - if (tags) { - auto valueOpt = tags->FindTagValue(key); - - if (valueOpt.has_value()) { - return FromString<TTag>(valueOpt.value()); + // NB: No lock is needed. + if (auto list = AllocationTagList_.Acquire()) { + if (auto optionalValue = list->FindTagValue(key)) { + return FromString<T>(*optionalValue); } } - return std::nullopt; } -template <typename TTag> -std::optional<TTag> TTraceContext::FindAllocationTag(const TString& key) const -{ - auto readerGuard = ReaderGuard(AllocationTagsLock_); - return DoFindAllocationTag<TTag>(key); -} - -template <typename TTag> -std::optional<TTag> TTraceContext::RemoveAllocationTag(const TString& key) -{ - auto writerGuard = NThreading::WriterGuard(AllocationTagsLock_); - auto newTags = DoGetAllocationTags(); - - auto foundTagIt = std::remove_if( - newTags.begin(), - newTags.end(), - [&key] (const auto& pair) { - return pair.first == key; - }); - - std::optional<TTag> oldTag; - - if (foundTagIt != newTags.end()) { - oldTag = FromString<TTag>(foundTagIt->second); - } - - newTags.erase(foundTagIt, newTags.end()); - - DoSetAllocationTags(std::move(newTags)); - - return oldTag; -} - -template <typename TTag> -std::optional<TTag> TTraceContext::SetAllocationTag(const TString& key, TTag newTag) +template <typename T> +std::optional<T> TTraceContext::SetAllocationTag(const TAllocationTagKey& key, const T& value) { - auto newTagString = ToString(newTag); + auto newTagValue = ToString(value); - auto writerGuard = NThreading::WriterGuard(AllocationTagsLock_); - auto newTags = DoGetAllocationTags(); + auto guard = Guard(AllocationTagsLock_); + auto newTags = GetAllocationTags(); if (!newTags.empty()) { - std::optional<TString> oldTag; - - auto tagIt = std::find_if( + auto it = std::find_if( newTags.begin(), newTags.end(), - [&key] (const auto& pair) { + [&] (const auto& pair) { return pair.first == key; }); - if (tagIt != newTags.end()) { - oldTag = std::move(tagIt->second); - tagIt->second = std::move(newTagString); + std::optional<TAllocationTagValue> oldTagValue; + if (it != newTags.end()) { + oldTagValue = std::move(it->second); + it->second = std::move(newTagValue); } else { - newTags.emplace_back(key, std::move(newTagString)); + newTags.emplace_back(key, std::move(newTagValue)); } DoSetAllocationTags(std::move(newTags)); - if (oldTag.has_value()) { - return FromString<TTag>(oldTag.value()); + if (oldTagValue) { + return FromString<T>(*oldTagValue); } } else { - DoSetAllocationTags({{key, std::move(newTagString)}}); + DoSetAllocationTags({{key, std::move(newTagValue)}}); } return std::nullopt; @@ -286,18 +241,18 @@ inline bool TChildTraceContextGuard::IsRecorded(const TTraceContextPtr& traceCon inline TChildTraceContextGuard::TChildTraceContextGuard( const TTraceContextPtr& traceContext, - TString spanName, + const std::string& spanName, std::optional<NProfiling::TCpuInstant> startTime) : TraceContextGuard_(IsRecorded(traceContext) ? traceContext->CreateChild(spanName, startTime) : nullptr) , FinishGuard_(IsRecorded(traceContext) ? TryGetCurrentTraceContext() : nullptr) { } inline TChildTraceContextGuard::TChildTraceContextGuard( - TString spanName, + const std::string& spanName, std::optional<NProfiling::TCpuInstant> startTime) : TChildTraceContextGuard( TryGetCurrentTraceContext(), - std::move(spanName), + spanName, startTime) { } @@ -349,13 +304,13 @@ Y_FORCE_INLINE TTraceContext* GetCurrentTraceContext() return NDetail::CurrentTraceContext(); } -Y_FORCE_INLINE TTraceContextPtr CreateTraceContextFromCurrent(TString spanName) +Y_FORCE_INLINE TTraceContextPtr CreateTraceContextFromCurrent(const std::string& spanName) { auto* context = TryGetCurrentTraceContext(); - return context ? context->CreateChild(std::move(spanName)) : TTraceContext::NewRoot(std::move(spanName)); + return context ? context->CreateChild(spanName) : TTraceContext::NewRoot(spanName); } -Y_FORCE_INLINE TTraceContextPtr GetOrCreateTraceContext(TString spanNameIfCreate) +Y_FORCE_INLINE TTraceContextPtr GetOrCreateTraceContext(const std::string& spanNameIfCreate) { auto* context = TryGetCurrentTraceContext(); return context ? context : TTraceContext::NewRoot(std::move(spanNameIfCreate)); diff --git a/yt/yt/core/tracing/trace_context.cpp b/yt/yt/core/tracing/trace_context.cpp index 5be2f295db..1e3006b60b 100644 --- a/yt/yt/core/tracing/trace_context.cpp +++ b/yt/yt/core/tracing/trace_context.cpp @@ -255,7 +255,7 @@ void FormatValue(TStringBuilderBase* builder, const TSpanContext& context, TStri TTraceContext::TTraceContext( TSpanContext parentSpanContext, - TString spanName, + const std::string& spanName, TTraceContextPtr parentTraceContext, std::optional<NProfiling::TCpuInstant> startTime) : TraceId_(parentSpanContext.TraceId) @@ -266,7 +266,7 @@ TTraceContext::TTraceContext( ? parentTraceContext->State_.load() : (parentSpanContext.Sampled ? ETraceContextState::Sampled : ETraceContextState::Disabled)) , ParentContext_(std::move(parentTraceContext)) - , SpanName_(std::move(spanName)) + , SpanName_(spanName) , RequestId_(ParentContext_ ? ParentContext_->GetRequestId() : TRequestId{}) , TargetEndpoint_(ParentContext_ ? ParentContext_->GetTargetEndpoint() : std::nullopt) , LoggingTag_(ParentContext_ ? ParentContext_->GetLoggingTag() : TString{}) @@ -291,75 +291,56 @@ void TTraceContext::SetLoggingTag(const TString& loggingTag) LoggingTag_ = loggingTag; } -void TTraceContext::ClearAllocationTagsPtr() noexcept +TAllocationTags TTraceContext::GetAllocationTags() const { - auto writerGuard = WriterGuard(AllocationTagsLock_); - auto guard = Guard(AllocationTagsAsRefCountedLock_); - AllocationTags_ = nullptr; + // NB: No lock is needed. + auto list = AllocationTagList_.Acquire(); + return list ? list->GetTags() : TAllocationTags(); } -TAllocationTags::TTags TTraceContext::DoGetAllocationTags() const +void TTraceContext::SetAllocationTags(TAllocationTags&& tags) { - VERIFY_SPINLOCK_AFFINITY(AllocationTagsLock_); + auto guard = Guard(AllocationTagsLock_); + return DoSetAllocationTags(std::move(tags)); +} - TAllocationTagsPtr tags; +void TTraceContext::RemoveAllocationTag(const TAllocationTagKey& key) +{ + auto guard = Guard(AllocationTagsLock_); - { - // Local guard for copy RefCounted AllocationTags_. - auto guard = Guard(AllocationTagsAsRefCountedLock_); - tags = AllocationTags_; - } + auto newTags = GetAllocationTags(); + auto it = std::remove_if( + newTags.begin(), + newTags.end(), + [&] (const auto& pair) { + return pair.first == key; + }); - if (!tags) { - return {}; + if (it == newTags.end()) { + return; } - return tags->GetTags(); + std::swap(newTags.back(), *it); + newTags.pop_back(); + DoSetAllocationTags(std::move(newTags)); } -TAllocationTags::TTags TTraceContext::GetAllocationTags() const +TAllocationTagListPtr TTraceContext::GetAllocationTagList() const noexcept { - auto readerGuard = ReaderGuard(AllocationTagsLock_); - return DoGetAllocationTags(); + return AllocationTagList_.Acquire(); } -TAllocationTagsPtr TTraceContext::GetAllocationTagsPtr() const noexcept +void TTraceContext::SetAllocationTagList(TAllocationTagListPtr list) noexcept { - // Local guard for copy RefCounted AllocationTags_ for allocator callback CreateAllocationTagsData(). - auto guard = Guard(AllocationTagsAsRefCountedLock_); - - return AllocationTags_; + auto guard = Guard(AllocationTagsLock_); + AllocationTagList_.Store(std::move(list)); } -void TTraceContext::SetAllocationTagsPtr(TAllocationTagsPtr allocationTags) noexcept -{ - auto writerGuard = WriterGuard(AllocationTagsLock_); - - // Local guard for setting RefCounted AllocationTags_. - auto guard = Guard(AllocationTagsAsRefCountedLock_); - - AllocationTags_ = std::move(allocationTags); -} - -void TTraceContext::DoSetAllocationTags(TAllocationTags::TTags&& tags) +void TTraceContext::DoSetAllocationTags(TAllocationTags&& tags) { VERIFY_SPINLOCK_AFFINITY(AllocationTagsLock_); - - TAllocationTagsPtr allocationTagsPtr; - if (!tags.empty()) { - // Allocation MUST be done BEFORE Guard(AllocationTagsAsRefCountedSpinlock_) to avoid deadlock with CreateAllocationTagsData(). - allocationTagsPtr = New<TAllocationTags>(std::move(tags)); - } - - auto guard = Guard(AllocationTagsAsRefCountedLock_); - AllocationTags_ = std::move(allocationTagsPtr); -} - -void TTraceContext::SetAllocationTags(TAllocationTags::TTags&& tags) -{ - auto writerGuard = WriterGuard(AllocationTagsLock_); - - return DoSetAllocationTags(std::move(tags)); + auto holder = tags.empty() ? nullptr : New<TAllocationTagList>(std::move(tags)); + AllocationTagList_.Store(std::move(holder)); } void TTraceContext::SetRecorded() @@ -374,19 +355,19 @@ void TTraceContext::SetPropagated(bool value) } TTraceContextPtr TTraceContext::CreateChild( - TString spanName, + const std::string& spanName, std::optional<NProfiling::TCpuInstant> startTime) { auto child = New<TTraceContext>( GetSpanContext(), - std::move(spanName), + spanName, /*parentTraceContext*/ this, startTime); auto guard = Guard(Lock_); child->ProfilingTags_ = ProfilingTags_; child->TargetEndpoint_ = TargetEndpoint_; - child->AllocationTags_ = AllocationTags_; + child->AllocationTagList_.Store(AllocationTagList_.Acquire()); return child; } @@ -469,7 +450,7 @@ void TTraceContext::PackBaggage(const IAttributeDictionaryPtr& baggage) SetBaggage(baggage ? ConvertToYsonString(baggage) : TYsonString{}); } -void TTraceContext::AddTag(const TString& tagKey, const TString& tagValue) +void TTraceContext::AddTag(const std::string& tagKey, const std::string& tagValue) { if (!IsRecorded()) { return; @@ -483,19 +464,19 @@ void TTraceContext::AddTag(const TString& tagKey, const TString& tagValue) Tags_.emplace_back(tagKey, tagValue); } -void TTraceContext::AddProfilingTag(const TString& name, const TString& value) +void TTraceContext::AddProfilingTag(const std::string& name, const std::string& value) { auto guard = Guard(Lock_); ProfilingTags_.emplace_back(name, value); } -void TTraceContext::AddProfilingTag(const TString& name, i64 value) +void TTraceContext::AddProfilingTag(const std::string& name, i64 value) { auto guard = Guard(Lock_); ProfilingTags_.emplace_back(name, value); } -std::vector<std::pair<TString, std::variant<TString, i64>>> TTraceContext::GetProfilingTags() +std::vector<std::pair<std::string, std::variant<std::string, i64>>> TTraceContext::GetProfilingTags() { auto guard = Guard(Lock_); return ProfilingTags_; @@ -654,7 +635,7 @@ void ToProto(NProto::TTracingExt* ext, const TTraceContextPtr& context) } } -TTraceContextPtr TTraceContext::NewRoot(TString spanName, TTraceId traceId) +TTraceContextPtr TTraceContext::NewRoot(const std::string& spanName, TTraceId traceId) { return New<TTraceContext>( TSpanContext{ @@ -663,18 +644,18 @@ TTraceContextPtr TTraceContext::NewRoot(TString spanName, TTraceId traceId) .Sampled = false, .Debug = false, }, - std::move(spanName)); + spanName); } TTraceContextPtr TTraceContext::NewChildFromSpan( TSpanContext parentSpanContext, - TString spanName, + const std::string& spanName, std::optional<TString> endpoint, TYsonString baggage) { auto result = New<TTraceContext>( parentSpanContext, - std::move(spanName)); + spanName); result->SetBaggage(std::move(baggage)); result->SetTargetEndpoint(endpoint); return result; @@ -682,7 +663,7 @@ TTraceContextPtr TTraceContext::NewChildFromSpan( TTraceContextPtr TTraceContext::NewChildFromRpc( const NProto::TTracingExt& ext, - TString spanName, + const std::string& spanName, TRequestId requestId, bool forceTracing) { @@ -692,7 +673,7 @@ TTraceContextPtr TTraceContext::NewChildFromRpc( return nullptr; } - auto root = NewRoot(std::move(spanName)); + auto root = NewRoot(spanName); root->SetRequestId(requestId); root->SetRecorded(); return root; @@ -705,7 +686,7 @@ TTraceContextPtr TTraceContext::NewChildFromRpc( ext.sampled(), ext.debug() }, - std::move(spanName)); + spanName); traceContext->SetRequestId(requestId); if (ext.has_baggage()) { traceContext->SetBaggage(TYsonString(ext.baggage())); @@ -800,7 +781,7 @@ void* AcquireFiberTagStorage() return reinterpret_cast<void*>(traceContext); } -std::vector<std::pair<TString, std::variant<TString, i64>>> ReadFiberTags(void* storage) +std::vector<std::pair<std::string, NTracing::TTraceContext::TProfilingTagValue>> ReadFiberTags(void* storage) { if (auto* traceContext = reinterpret_cast<NTracing::TTraceContext*>(storage)) { return traceContext->GetProfilingTags(); diff --git a/yt/yt/core/tracing/trace_context.h b/yt/yt/core/tracing/trace_context.h index 1a1b70f3ea..8bdf90aabd 100644 --- a/yt/yt/core/tracing/trace_context.h +++ b/yt/yt/core/tracing/trace_context.h @@ -15,6 +15,8 @@ #include <library/cpp/yt/threading/rw_spin_lock.h> #include <library/cpp/yt/threading/spin_lock.h> +#include <library/cpp/yt/memory/atomic_intrusive_ptr.h> + #include <atomic> namespace NYT::NTracing { @@ -127,21 +129,17 @@ public: void SetRequestId(TRequestId requestId); TRequestId GetRequestId() const; - void SetAllocationTags(TAllocationTags::TTags&& tags); - TAllocationTags::TTags GetAllocationTags() const; + TAllocationTags GetAllocationTags() const; + void SetAllocationTags(TAllocationTags&& tags); - TAllocationTagsPtr GetAllocationTagsPtr() const noexcept; - void SetAllocationTagsPtr(TAllocationTagsPtr allocationTags) noexcept; - void ClearAllocationTagsPtr() noexcept; + TAllocationTagListPtr GetAllocationTagList() const noexcept; + void SetAllocationTagList(TAllocationTagListPtr list) noexcept; - template <typename TTag> - std::optional<TTag> FindAllocationTag(const TString& key) const; - template <typename TTag> - std::optional<TTag> SetAllocationTag( - const TString& key, - TTag value); - template <typename TTag> - std::optional<TTag> RemoveAllocationTag(const TString& key); + template <typename T> + std::optional<T> FindAllocationTag(const TAllocationTagKey& key) const; + template <typename T> + std::optional<T> SetAllocationTag(const TAllocationTagKey& key, const T& value); + void RemoveAllocationTag(const TAllocationTagKey& key); //! Sets logging tag. /*! @@ -158,7 +156,7 @@ public: */ TDuration GetDuration() const; - using TTagList = TCompactVector<std::pair<TString, TString>, 4>; + using TTagList = TCompactVector<std::pair<std::string, std::string>, 4>; TTagList GetTags() const; NYson::TYsonString GetBaggage() const; @@ -167,10 +165,10 @@ public: NYTree::IAttributeDictionaryPtr UnpackOrCreateBaggage() const; void PackBaggage(const NYTree::IAttributeDictionaryPtr& baggage); - void AddTag(const TString& tagKey, const TString& tagValue); + void AddTag(const std::string& tagKey, const std::string& tagValue); template <class T> - void AddTag(const TString& tagName, const T& tagValue); + void AddTag(const std::string& tagName, const T& tagValue); //! Adds error tag. Spans containing errors are highlighted in tracing UI. void AddErrorTag(); @@ -192,27 +190,29 @@ public: NProfiling::TCpuDuration GetElapsedCpuTime() const; TDuration GetElapsedTime() const; - static TTraceContextPtr NewRoot(TString spanName, TTraceId traceId = {}); + static TTraceContextPtr NewRoot(const std::string& spanName, TTraceId traceId = {}); static TTraceContextPtr NewChildFromRpc( const NProto::TTracingExt& ext, - TString spanName, + const std::string& spanName, TRequestId requestId = {}, bool forceTracing = false); static TTraceContextPtr NewChildFromSpan( TSpanContext parentSpanContext, - TString spanName, + const std::string& spanName, std::optional<TString> endpoint = {}, NYson::TYsonString baggage = NYson::TYsonString()); TTraceContextPtr CreateChild( - TString spanName, + const std::string& spanName, std::optional<NProfiling::TCpuInstant> startTime = {}); - void AddProfilingTag(const TString& name, const TString& value); - void AddProfilingTag(const TString& name, i64 value); - std::vector<std::pair<TString, std::variant<TString, i64>>> GetProfilingTags(); + void AddProfilingTag(const std::string& name, const std::string& value); + void AddProfilingTag(const std::string& name, i64 value); + + using TProfilingTagValue = std::variant<std::string, i64>; + std::vector<std::pair<std::string, TProfilingTagValue>> GetProfilingTags(); friend void ToProto(NProto::TTracingExt* ext, const TTraceContextPtr& context); @@ -244,29 +244,20 @@ private: TAsyncChildrenList AsyncChildren_; NYson::TYsonString Baggage_; - std::vector<std::pair<TString, std::variant<TString, i64>>> ProfilingTags_; + std::vector<std::pair<std::string, TProfilingTagValue>> ProfilingTags_; - // Must NOT allocate memory on the heap in callbacks with modifying AllocationTags_ to avoid deadlock with allocator. - YT_DECLARE_SPIN_LOCK(NThreading::TReaderWriterSpinLock, AllocationTagsLock_); - YT_DECLARE_SPIN_LOCK(NThreading::TSpinLock, AllocationTagsAsRefCountedLock_); - TAllocationTagsPtr AllocationTags_; + // Must NOT allocate memory while modifying AllocationTagList_ to avoid deadlock with allocator. + YT_DECLARE_SPIN_LOCK(NThreading::TSpinLock, AllocationTagsLock_); + TAtomicIntrusivePtr<TAllocationTagList> AllocationTagList_; TTraceContext( TSpanContext parentSpanContext, - TString spanName, + const std::string& spanName, TTraceContextPtr parentTraceContext = nullptr, std::optional<NProfiling::TCpuInstant> startTime = {}); DECLARE_NEW_FRIEND() - void DoSetAllocationTags(TAllocationTags::TTags&& tags); - - template <typename TTag> - std::optional<TTag> DoSetAllocationTag(const TString& key, TTag newTag); - - TAllocationTags::TTags DoGetAllocationTags() const; - - template <typename TTag> - std::optional<TTag> DoFindAllocationTag(const TString& key) const; + void DoSetAllocationTags(TAllocationTags&& tags); void SubmitToTracer(const ITracerPtr& tracer); }; @@ -292,7 +283,7 @@ TTraceContext* TryGetTraceContextFromPropagatingStorage(const NConcurrency::TPro //! Creates a new trace context. If the current trace context exists, it becomes the parent of the //! created trace context. -TTraceContextPtr CreateTraceContextFromCurrent(TString spanName); +TTraceContextPtr CreateTraceContextFromCurrent(const std::string& spanName); //////////////////////////////////////////////////////////////////////////////// @@ -384,10 +375,10 @@ class TChildTraceContextGuard public: TChildTraceContextGuard( const TTraceContextPtr& traceContext, - TString spanName, + const std::string& spanName, std::optional<NProfiling::TCpuInstant> startTime = {}); explicit TChildTraceContextGuard( - TString spanName, + const std::string& spanName, std::optional<NProfiling::TCpuInstant> startTime = {}); TChildTraceContextGuard(TChildTraceContextGuard&& other) = default; diff --git a/yt/yt/core/tracing/unittests/allocation_tags_ut.cpp b/yt/yt/core/tracing/unittests/allocation_tags_ut.cpp index 9be4ebb8a8..9c567309ee 100644 --- a/yt/yt/core/tracing/unittests/allocation_tags_ut.cpp +++ b/yt/yt/core/tracing/unittests/allocation_tags_ut.cpp @@ -13,26 +13,26 @@ TEST(TAllocationTagsTest, GetSetAllocationTags) auto traceContext = TTraceContext::NewRoot("Root"); TTraceContextGuard guard(traceContext); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("a"), std::nullopt); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("a"), std::nullopt); traceContext->SetAllocationTags({{"user", "first"}, {"sometag", "my"}}); ASSERT_EQ(traceContext->FindAllocationTag<TMemoryTag>("memory_tag"), std::nullopt); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("user"), "first"); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("sometag"), "my"); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("other"), std::nullopt); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("user"), "first"); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("sometag"), "my"); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("other"), std::nullopt); ASSERT_EQ(traceContext->FindAllocationTag<int>("other"), std::nullopt); - traceContext->SetAllocationTag<TString>("a", "e"); + traceContext->SetAllocationTag<std::string>("a", "e"); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("a"), "e"); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("a"), "e"); - traceContext->RemoveAllocationTag<TString>("a"); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("a"), std::nullopt); + traceContext->RemoveAllocationTag("a"); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("a"), std::nullopt); - traceContext->RemoveAllocationTag<TString>("user"); - traceContext->RemoveAllocationTag<TString>("sometag"); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("user"), std::nullopt); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("sometag"), std::nullopt); + traceContext->RemoveAllocationTag("user"); + traceContext->RemoveAllocationTag("sometag"); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("user"), std::nullopt); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("sometag"), std::nullopt); ASSERT_TRUE(traceContext->GetAllocationTags().empty()); traceContext->SetAllocationTag<TMemoryTag>("memory_tag", TMemoryTag{1}); diff --git a/yt/yt/core/ya.make b/yt/yt/core/ya.make index fd9f4b0792..c2c3ccd3ed 100644 --- a/yt/yt/core/ya.make +++ b/yt/yt/core/ya.make @@ -225,7 +225,6 @@ SRCS( threading/spin_wait_slow_path_logger.cpp threading/thread.cpp - GLOBAL tracing/allocation_hooks.cpp tracing/allocation_tags.cpp tracing/config.cpp tracing/public.cpp @@ -308,6 +307,12 @@ SRCS( ytalloc/statistics_producer.cpp ) +IF (OS_LINUX) + SRCS( + GLOBAL tracing/allocation_tags_hooks.cpp + ) +ENDIF() + IF (OS_LINUX OR OS_FREEBSD) EXTRALIBS(-lutil) ENDIF() diff --git a/yt/yt/library/tracing/jaeger/tracer.cpp b/yt/yt/library/tracing/jaeger/tracer.cpp index c3b254e7b5..1a8ab4e81e 100644 --- a/yt/yt/library/tracing/jaeger/tracer.cpp +++ b/yt/yt/library/tracing/jaeger/tracer.cpp @@ -168,6 +168,8 @@ void ToProtoUInt64(TString* proto, i64 i) void ToProto(NProto::Span* proto, const TTraceContextPtr& traceContext) { + using NYT::ToProto; + ToProtoGuid(proto->mutable_trace_id(), traceContext->GetTraceId()); ToProtoUInt64(proto->mutable_span_id(), traceContext->GetSpanId()); @@ -182,8 +184,8 @@ void ToProto(NProto::Span* proto, const TTraceContextPtr& traceContext) for (const auto& [name, value] : traceContext->GetTags()) { auto* protoTag = proto->add_tags(); - protoTag->set_key(name); - protoTag->set_v_str(value); + protoTag->set_key(ToProto<TProtobufString>(name)); + protoTag->set_v_str(ToProto<TProtobufString>(value)); } for (const auto& logEntry : traceContext->GetLogEntries()) { diff --git a/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.cpp b/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.cpp index 9586d7292c..f79052d105 100644 --- a/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.cpp +++ b/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.cpp @@ -22,17 +22,17 @@ class TAllocationTagProfiler { public: TAllocationTagProfiler( - std::vector<TString> tagNames, + std::vector<TAllocationTagKey> tagKeys, IInvokerPtr invoker, std::optional<TDuration> updatePeriod, std::optional<i64> samplingRate, NProfiling::TProfiler profiler) : Profiler_(std::move(profiler)) - , TagNames_(std::move(tagNames)) + , TagKeys_(std::move(tagKeys)) , UpdateExecutor_(New<TPeriodicExecutor>( std::move(invoker), BIND(&TAllocationTagProfiler::UpdateGauges, MakeWeak(this)), - std::move(updatePeriod))) + updatePeriod)) { if (samplingRate) { tcmalloc::MallocExtension::SetProfileSamplingRate(*samplingRate); @@ -43,35 +43,35 @@ public: private: const NProfiling::TProfiler Profiler_; - const std::vector<TString> TagNames_; + const std::vector<TAllocationTagKey> TagKeys_; const NConcurrency::TPeriodicExecutorPtr UpdateExecutor_; - THashMap<TString, THashMap<TString, NProfiling::TGauge>> HeapUsageByType_; + THashMap<TAllocationTagKey, THashMap<TAllocationTagValue, NProfiling::TGauge>> Guages_; void UpdateGauges() { - auto memorySnapshot = GetMemoryUsageSnapshot(); - YT_VERIFY(memorySnapshot); + auto memorySnapshot = GetGlobalMemoryUsageSnapshot(); - for (const auto& tagName : TagNames_) { - auto& heapUsageMap = HeapUsageByType_.emplace(tagName, THashMap<TString, TGauge>{}).first->second; - const auto& snapshotSlice = memorySnapshot->GetUsage(tagName); + for (const auto& tagKey : TagKeys_) { + auto& guages = Guages_.emplace(tagKey, THashMap<TAllocationTagValue, TGauge>{}).first->second; + const auto& slice = memorySnapshot->GetUsageSlice(tagKey); - for (auto& [tagValue, gauge] : heapUsageMap) { - if (auto it = snapshotSlice.find(tagValue)) { + for (auto& [tagValue, gauge] : guages) { + if (auto it = slice.find(tagValue)) { gauge.Update(it->second); } else { gauge.Update(0.0); } } - for (const auto& [tagValue, usage] : snapshotSlice) { - auto it = heapUsageMap.find(tagValue); - if (it == heapUsageMap.end()) { - it = heapUsageMap.emplace(tagValue, Profiler_ - .WithTag(tagName, tagValue) - .Gauge(Format("/%v", NYPath::ToYPathLiteral(tagName)))) + for (const auto& [tagValue, usage] : slice) { + auto it = guages.find(tagValue); + if (it == guages.end()) { + it = guages.emplace(tagValue, Profiler_ + // TODO(babenko): migrate to std::string + .WithTag(TString(tagKey), TString(tagValue)) + .Gauge(Format("/%v", NYPath::ToYPathLiteral(tagKey)))) .first; it->second.Update(usage); } @@ -95,14 +95,14 @@ public: //////////////////////////////////////////////////////////////////////////////// IAllocationTagProfilerPtr CreateAllocationTagProfiler( - std::vector<TString> tagNames, + std::vector<TAllocationTagKey> tagKeys, IInvokerPtr invoker, std::optional<TDuration> updatePeriod, std::optional<i64> samplingRate, NYT::NProfiling::TProfiler profiler) { return New<TAllocationTagProfiler>( - std::move(tagNames), + std::move(tagKeys), std::move(invoker), std::move(updatePeriod), std::move(samplingRate), diff --git a/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.h b/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.h index 9db2c37312..18c4c904d4 100644 --- a/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.h +++ b/yt/yt/library/ytprof/allocation_tag_profiler/allocation_tag_profiler.h @@ -25,7 +25,7 @@ DEFINE_REFCOUNTED_TYPE(IAllocationTagProfiler); //////////////////////////////////////////////////////////////////////////////// IAllocationTagProfilerPtr CreateAllocationTagProfiler( - std::vector<TString> tagNames, + std::vector<TAllocationTagKey> tagKeys, IInvokerPtr invoker, std::optional<TDuration> updatePeriod, std::optional<i64> samplingRate, diff --git a/yt/yt/library/ytprof/api/api.h b/yt/yt/library/ytprof/api/api.h index c04b1ebcf5..854e2ab7fe 100644 --- a/yt/yt/library/ytprof/api/api.h +++ b/yt/yt/library/ytprof/api/api.h @@ -41,7 +41,7 @@ std::array<TAtomicSignalPtr<TProfilerTag>, MaxActiveTags>* GetCpuProfilerTags(); // Hooks for yt/yt/core fibers. void* AcquireFiberTagStorage(); -std::vector<std::pair<TString, std::variant<TString, i64>>> ReadFiberTags(void* storage); +std::vector<std::pair<std::string, std::variant<std::string, i64>>> ReadFiberTags(void* storage); void ReleaseFiberTagStorage(void* storage); TCpuInstant GetTraceContextTimingCheckpoint(); diff --git a/yt/yt/library/ytprof/cpu_profiler.cpp b/yt/yt/library/ytprof/cpu_profiler.cpp index 3e64ea3836..3fd656c056 100644 --- a/yt/yt/library/ytprof/cpu_profiler.cpp +++ b/yt/yt/library/ytprof/cpu_profiler.cpp @@ -22,7 +22,7 @@ namespace NYT::NYTProf { //////////////////////////////////////////////////////////////////////////////// -#if not defined(_linux_) +#if !defined(_linux_) TCpuProfiler::TCpuProfiler(TCpuProfilerOptions options) : TSignalSafeProfiler(options) @@ -37,7 +37,7 @@ void TCpuProfiler::EnableProfiler() void TCpuProfiler::DisableProfiler() { } -void TCpuProfiler::AnnotateProfile(NProto::Profile* /* profile */, const std::function<i64(const TString&)>& /* stringify */) +void TCpuProfiler::AnnotateProfile(NProto::Profile* /*profile*/, const TStringify& /*stringify*/) { } i64 TCpuProfiler::EncodeValue(i64 value) @@ -136,7 +136,7 @@ void TCpuProfiler::DisableProfiler() } } -void TCpuProfiler::AnnotateProfile(NProto::Profile* profile, const std::function<i64(const TString&)>& stringify) +void TCpuProfiler::AnnotateProfile(NProto::Profile* profile, const TStringify& stringify) { auto sampleType = profile->add_sample_type(); sampleType->set_type(stringify("sample")); diff --git a/yt/yt/library/ytprof/cpu_profiler.h b/yt/yt/library/ytprof/cpu_profiler.h index cd98012d83..08982f2920 100644 --- a/yt/yt/library/ytprof/cpu_profiler.h +++ b/yt/yt/library/ytprof/cpu_profiler.h @@ -58,7 +58,7 @@ private: void EnableProfiler() override; void DisableProfiler() override; - void AnnotateProfile(NProto::Profile* profile, const std::function<i64(const TString&)>& stringify) override; + void AnnotateProfile(NProto::Profile* profile, const TStringify& stringify) override; i64 EncodeValue(i64 value) override; }; diff --git a/yt/yt/library/ytprof/heap_profiler.cpp b/yt/yt/library/ytprof/heap_profiler.cpp index 822b96ffc2..9168d929a8 100644 --- a/yt/yt/library/ytprof/heap_profiler.cpp +++ b/yt/yt/library/ytprof/heap_profiler.cpp @@ -4,59 +4,21 @@ #include <library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.h> +#include <yt/yt/core/misc/protobuf_helpers.h> + +#include <library/cpp/yt/memory/allocation_tags_hooks.h> #include <library/cpp/yt/memory/atomic_intrusive_ptr.h> #include <library/cpp/yt/memory/leaky_singleton.h> #include <library/cpp/yt/memory/new.h> -#include <library/cpp/yt/threading/rw_spin_lock.h> - -#include <util/generic/hash_set.h> #include <util/string/join.h> -#include <util/string/cast.h> -#include <tcmalloc/malloc_extension.h> +#include <util/system/thread.h> +#include <mutex> #include <thread> -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void* CreateAllocationTagsData() -{ - return nullptr; -} - -Y_WEAK void* CopyAllocationTagsData(void* userData) -{ - return userData; -} - -Y_WEAK void DestroyAllocationTagsData(void* /*userData*/) -{ } - -Y_WEAK const std::vector<std::pair<TString, TString>>* ReadAllocationTagsData(void* /*userData*/) -{ - return nullptr; -} - -Y_WEAK std::optional<TString> FindTagValue( - const std::vector<std::pair<TString, TString>>& tags, - const TString& key) -{ - Y_UNUSED(tags); - Y_UNUSED(key); - return ::ToString(NullMemoryTag); -} - -Y_WEAK void StartAllocationTagsCleanupThread(TDuration /*cleanupInterval*/) -{ } - -//////////////////////////////////////////////////////////////////////////////// - -namespace NYTProf { - -using namespace NThreading; +namespace NYT::NYTProf { //////////////////////////////////////////////////////////////////////////////// @@ -65,25 +27,29 @@ NProto::Profile ConvertAllocationProfile(const tcmalloc::Profile& snapshot) NProto::Profile profile; profile.add_string_table(); - auto addString = [&] (TString str) { + auto addString = [&] (const std::string& str) { auto index = profile.string_table_size(); - profile.add_string_table(str); + profile.add_string_table(ToProto<TProtobufString>(str)); return index; }; - auto sampleType = profile.add_sample_type(); - sampleType->set_type(addString("allocations")); - sampleType->set_unit(addString("count")); + auto bytesUnitId = addString("bytes"); - sampleType = profile.add_sample_type(); - sampleType->set_type(addString("space")); + { + auto* sampleType = profile.add_sample_type(); + sampleType->set_type(addString("allocations")); + sampleType->set_unit(addString("count")); + } - auto bytesUnitId = addString("bytes"); - sampleType->set_unit(bytesUnitId); + { + auto* sampleType = profile.add_sample_type(); + sampleType->set_type(addString("space")); + sampleType->set_unit(bytesUnitId); - auto periodType = profile.mutable_period_type(); - periodType->set_type(sampleType->type()); - periodType->set_unit(sampleType->unit()); + auto* periodType = profile.mutable_period_type(); + periodType->set_type(sampleType->type()); + periodType->set_unit(sampleType->unit()); + } profile.set_period(snapshot.Period()); @@ -93,21 +59,21 @@ NProto::Profile ConvertAllocationProfile(const tcmalloc::Profile& snapshot) THashMap<void*, ui64> locations; snapshot.Iterate([&] (const tcmalloc::Profile::Sample& sample) { - auto sampleProto = profile.add_sample(); - sampleProto->add_value(sample.count); - sampleProto->add_value(sample.sum); + auto* protoSample = profile.add_sample(); + protoSample->add_value(sample.count); + protoSample->add_value(sample.sum); - auto allocatedSizeLabel = sampleProto->add_label(); + auto* allocatedSizeLabel = protoSample->add_label(); allocatedSizeLabel->set_key(allocatedSizeId); allocatedSizeLabel->set_num(sample.allocated_size); allocatedSizeLabel->set_num_unit(bytesUnitId); - auto requestedSizeLabel = sampleProto->add_label(); + auto* requestedSizeLabel = protoSample->add_label(); requestedSizeLabel->set_key(requestedSizeId); requestedSizeLabel->set_num(sample.requested_size); requestedSizeLabel->set_num_unit(bytesUnitId); - auto requestedAlignmentLabel = sampleProto->add_label(); + auto* requestedAlignmentLabel = protoSample->add_label(); requestedAlignmentLabel->set_key(requestedAlignmentId); requestedAlignmentLabel->set_num(sample.requested_alignment); requestedAlignmentLabel->set_num_unit(bytesUnitId); @@ -117,27 +83,25 @@ NProto::Profile ConvertAllocationProfile(const tcmalloc::Profile& snapshot) auto it = locations.find(ip); if (it != locations.end()) { - sampleProto->add_location_id(it->second); + protoSample->add_location_id(it->second); continue; } auto locationId = locations.size() + 1; - auto location = profile.add_location(); + auto* location = profile.add_location(); location->set_address(reinterpret_cast<ui64>(ip)); location->set_id(locationId); - sampleProto->add_location_id(locationId); + protoSample->add_location_id(locationId); locations[ip] = locationId; } // TODO(gepardo): Deduplicate values in string table - if (const auto* data = ReadAllocationTagsData(sample.user_data)) { - for (const auto& [key, value] : *data) { - auto label = sampleProto->add_label(); - label->set_key(addString(key)); - label->set_str(addString(value)); - } + for (const auto& [key, value] : GetAllocationTagsHooks().ReadAllocationTags(sample.user_data)) { + auto* label = protoSample->add_label(); + label->set_key(addString(key)); + label->set_str(addString(value)); } }); @@ -158,23 +122,55 @@ NProto::Profile ReadHeapProfile(tcmalloc::ProfileType profileType) return ConvertAllocationProfile(snapshot); } +int AbslStackUnwinder( + void** frames, + int* /*framesSizes*/, + int maxFrames, + int skipFrames, + const void* /*uc*/, + int* /*minDroppedFrames*/) +{ + NBacktrace::TLibunwindCursor cursor; + + for (int i = 0; i < skipFrames + 1; ++i) { + cursor.MoveNext(); + } + + int count = 0; + for (int i = 0; i < maxFrames; ++i) { + if (cursor.IsFinished()) { + return count; + } + + // IP point's to return address. Subtract 1 to get accurate line information for profiler. + frames[i] = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(cursor.GetCurrentIP()) - 1); + count++; + + cursor.MoveNext(); + } + return count; +} + +//////////////////////////////////////////////////////////////////////////////// + TMemoryUsageSnapshot::TMemoryUsageSnapshot(TMemoryUsageSnapshot::TData&& data) noexcept : Data_(std::move(data)) { } -const THashMap<TString, size_t>& TMemoryUsageSnapshot::GetUsage(const TString& tagName) const noexcept +const THashMap<TAllocationTagValue, size_t>& TMemoryUsageSnapshot::GetUsageSlice(const TAllocationTagKey& key) const noexcept { - if (auto it = Data_.find(tagName)) { + if (auto it = Data_.find(key)) { return it->second; } - return EmptyHashMap_; + static const THashMap<TAllocationTagValue, size_t> empty; + return empty; } -size_t TMemoryUsageSnapshot::GetUsage(const TString& tagName, const TString& tag) const noexcept +size_t TMemoryUsageSnapshot::GetUsage(const TAllocationTagKey& key, const TAllocationTagKey& value) const noexcept { - if (auto it = Data_.find(tagName)) { - if (auto usageIt = it->second.find(tag)) { + if (auto it = Data_.find(key)) { + if (auto usageIt = it->second.find(value)) { return usageIt->second; } } @@ -184,8 +180,13 @@ size_t TMemoryUsageSnapshot::GetUsage(const TString& tagName, const TString& tag //////////////////////////////////////////////////////////////////////////////// -struct TMemoryUsageSnapshotStorage +struct TGlobalMemoryUsageSnapshot { + static TGlobalMemoryUsageSnapshot* Get() + { + return LeakySingleton<TGlobalMemoryUsageSnapshot>(); + } + TAtomicIntrusivePtr<TMemoryUsageSnapshot> Snapshot{New<TMemoryUsageSnapshot>()}; }; @@ -195,85 +196,51 @@ TMemoryUsageSnapshotPtr CollectMemoryUsageSnapshot() auto snapshot = tcmalloc::MallocExtension::SnapshotCurrent(tcmalloc::ProfileType::kHeap); snapshot.Iterate([&] (const tcmalloc::Profile::Sample& sample) { - if (const auto* data = ReadAllocationTagsData(sample.user_data)) { - for (const auto& [tagName, tag] : *data) { - usage[tagName][tag] += sample.sum; - } + for (const auto& [tagKey, tagValue] : GetAllocationTagsHooks().ReadAllocationTags(sample.user_data)) { + usage[tagKey][tagValue] += sample.sum; } }); return New<TMemoryUsageSnapshot>(std::move(usage)); } -void UpdateMemoryUsageSnapshot(TMemoryUsageSnapshotPtr usageSnapshot) +void SetGlobalMemoryUsageSnapshot(TMemoryUsageSnapshotPtr snapshot) { - auto snapshot = LeakySingleton<TMemoryUsageSnapshotStorage>(); - snapshot->Snapshot.Store(std::move(usageSnapshot)); + TGlobalMemoryUsageSnapshot::Get()->Snapshot.Store(std::move(snapshot)); } -TMemoryUsageSnapshotPtr GetMemoryUsageSnapshot() +TMemoryUsageSnapshotPtr GetGlobalMemoryUsageSnapshot() { - const auto snapshot = LeakySingleton<TMemoryUsageSnapshotStorage>(); - return snapshot->Snapshot.Acquire(); + return TGlobalMemoryUsageSnapshot::Get()->Snapshot.Acquire(); } -int AbslStackUnwinder( - void** frames, - int*, - int maxFrames, - int skipFrames, - const void*, - int*) +void EnableMemoryProfilingTags(std::optional<TDuration> snapshotUpdatePeriod) { - NBacktrace::TLibunwindCursor cursor; - - for (int i = 0; i < skipFrames + 1; ++i) { - cursor.MoveNext(); - } - - int count = 0; - for (int i = 0; i < maxFrames; ++i) { - if (cursor.IsFinished()) { - return count; - } - - // IP point's to return address. Subtract 1 to get accurate line information for profiler. - frames[i] = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(cursor.GetCurrentIP()) - 1); - count++; - - cursor.MoveNext(); - } - return count; -} - -void EnableMemoryProfilingTags(std::optional<TDuration> updateSnapshotPeriod) -{ - StartAllocationTagsCleanupThread(TDuration::Seconds(1)); - tcmalloc::MallocExtension::SetSampleUserDataCallbacks( - &CreateAllocationTagsData, - &CopyAllocationTagsData, - &DestroyAllocationTagsData); - - if (updateSnapshotPeriod) { - std::thread backgroundThread([updateSnapshotPeriod] { - TInstant lastUpdateTime; - TInstant currentTime; - - while (true) { - lastUpdateTime = Now(); - UpdateMemoryUsageSnapshot(CollectMemoryUsageSnapshot()); - - currentTime = Now(); - if (lastUpdateTime + updateSnapshotPeriod.value() > currentTime) { - Sleep(lastUpdateTime + updateSnapshotPeriod.value() - currentTime); + static std::once_flag onceFlag; + std::call_once(onceFlag, [&] { + const auto& hooks = GetAllocationTagsHooks(); + tcmalloc::MallocExtension::SetSampleUserDataCallbacks( + hooks.CreateAllocationTags, + hooks.CopyAllocationTags, + hooks.DestroyAllocationTags); + + if (snapshotUpdatePeriod) { + std::thread thread([snapshotUpdatePeriod] { + TThread::SetCurrentThreadName("MemSnapUpdate"); + while (true) { + auto lastUpdateTime = Now(); + SetGlobalMemoryUsageSnapshot(CollectMemoryUsageSnapshot()); + auto currentTime = Now(); + if (lastUpdateTime + *snapshotUpdatePeriod > currentTime) { + Sleep(lastUpdateTime + *snapshotUpdatePeriod - currentTime); + } } - } - }); - backgroundThread.detach(); - } + }); + thread.detach(); + } + }); } //////////////////////////////////////////////////////////////////////////////// -} // namespace NYTProf -} // namespace NYT +} // namespace NYT::NYTProf diff --git a/yt/yt/library/ytprof/heap_profiler.h b/yt/yt/library/ytprof/heap_profiler.h index ca2eb9ae48..faaa2d4560 100644 --- a/yt/yt/library/ytprof/heap_profiler.h +++ b/yt/yt/library/ytprof/heap_profiler.h @@ -6,6 +6,8 @@ #include <util/datetime/base.h> +#include <library/cpp/yt/memory/allocation_tags.h> + #include <util/generic/hash.h> #include <tcmalloc/malloc_extension.h> @@ -15,51 +17,48 @@ namespace NYT::NYTProf { //////////////////////////////////////////////////////////////////////////////// NProto::Profile ConvertAllocationProfile(const tcmalloc::Profile& snapshot); - NProto::Profile ReadHeapProfile(tcmalloc::ProfileType profileType); -int AbslStackUnwinder(void** frames, int*, - int maxFrames, int skipFrames, - const void*, - int*); +int AbslStackUnwinder( + void** frames, + int* framesSizes, + int maxFrames, + int skipFrames, + const void* uc, + int* minDroppedFrames); //////////////////////////////////////////////////////////////////////////////// -class TMemoryUsageSnapshot - : public virtual TRefCounted +class TMemoryUsageSnapshot final { public: - using TData = THashMap<TString, THashMap<TString, size_t>>; + using TData = THashMap<TAllocationTagKey, THashMap<TAllocationTagValue, size_t>>; TMemoryUsageSnapshot() = default; - - TMemoryUsageSnapshot(TMemoryUsageSnapshot&& other) noexcept = default; - explicit TMemoryUsageSnapshot(TData&& data) noexcept; - const THashMap<TString, size_t>& GetUsage(const TString& tagName) const noexcept; - - size_t GetUsage(const TString& tagName, const TString& tag) const noexcept; + const THashMap<TAllocationTagKey, size_t>& GetUsageSlice(const TAllocationTagKey& key) const noexcept; + size_t GetUsage(const TAllocationTagKey& key, const TAllocationTagValue& value) const noexcept; private: const TData Data_; - static inline const THashMap<TString, size_t> EmptyHashMap_; }; DEFINE_REFCOUNTED_TYPE(TMemoryUsageSnapshot) //////////////////////////////////////////////////////////////////////////////// +//! Builds the current snapshot of memory usage. TMemoryUsageSnapshotPtr CollectMemoryUsageSnapshot(); -//! Update snapshot in LeakySingleton. -void UpdateMemoryUsageSnapshot(TMemoryUsageSnapshotPtr usageSnapshot); +//! Updates the global memory usage snapshot. +void SetGlobalMemoryUsageSnapshot(TMemoryUsageSnapshotPtr snapshot); -//! Get snapshot from LeakySingleton. -TMemoryUsageSnapshotPtr GetMemoryUsageSnapshot(); +//! Gets the global memory usage snapshot. +TMemoryUsageSnapshotPtr GetGlobalMemoryUsageSnapshot(); -//! If put updateSnapshotPeriod will start updating snapshot in LeakySingleton. -void EnableMemoryProfilingTags(std::optional<TDuration> updateSnapshotPeriod = std::nullopt); +//! If updateSnapshotPeriod is non-null, starts updating global snapshot in background thread. +void EnableMemoryProfilingTags(std::optional<TDuration> snapshotUpdatePeriod = {}); //////////////////////////////////////////////////////////////////////////////// diff --git a/yt/yt/library/ytprof/signal_safe_profiler.cpp b/yt/yt/library/ytprof/signal_safe_profiler.cpp index 754ceb26c3..6a735eb26b 100644 --- a/yt/yt/library/ytprof/signal_safe_profiler.cpp +++ b/yt/yt/library/ytprof/signal_safe_profiler.cpp @@ -15,29 +15,28 @@ #endif #include <yt/yt/core/misc/proc.h> +#include "yt/yt/core/misc/protobuf_helpers.h" #include <library/cpp/yt/cpu_clock/clock.h> +#include <library/cpp/yt/misc/hash.h> + namespace NYT::NYTProf { //////////////////////////////////////////////////////////////////////////////// TProfileLocation::operator size_t() const { - size_t hash = Tid; - hash = CombineHashes(hash, std::hash<TString>()(ThreadName)); - + size_t hash = 0; + HashCombine(hash, Tid); + HashCombine(hash, ThreadName); for (auto ip : Backtrace) { - hash = CombineHashes(hash, ip); + HashCombine(hash, ip); } - for (const auto& tag : Tags) { - hash = CombineHashes(hash, - CombineHashes( - std::hash<TString>{}(tag.first), - std::hash<std::variant<TString, i64>>{}(tag.second))); + HashCombine(hash, tag.first); + HashCombine(hash, std::hash<std::variant<std::string, i64>>()(tag.second)); } - return hash; } @@ -48,7 +47,7 @@ Y_WEAK void* AcquireFiberTagStorage() return nullptr; } -Y_WEAK std::vector<std::pair<TString, std::variant<TString, i64>>> ReadFiberTags(void* /* storage */) +Y_WEAK std::vector<std::pair<std::string, std::variant<std::string, i64>>> ReadFiberTags(void* /* storage */) { return {}; } @@ -298,16 +297,15 @@ NProto::Profile TSignalSafeProfiler::ReadProfile() NProto::Profile profile; profile.add_string_table(); - THashMap<TString, ui64> stringTable; - auto stringify = [&] (const TString& str) -> i64 { + THashMap<std::string, i64> stringTable; + auto stringify = [&] (const std::string& str) -> i64 { if (auto it = stringTable.find(str); it != stringTable.end()) { return it->second; - } else { - auto nameId = profile.string_table_size(); - profile.add_string_table(str); - stringTable[str] = nameId; - return nameId; } + auto nameId = profile.string_table_size(); + profile.add_string_table(ToProto<TProtobufString>(str)); + stringTable[str] = nameId; + return nameId; }; AnnotateProfile(&profile, stringify); @@ -331,9 +329,9 @@ NProto::Profile TSignalSafeProfiler::ReadProfile() auto label = sample->add_label(); label->set_key(stringify(tag.first)); - if (auto intValue = std::get_if<i64>(&tag.second)) { + if (auto* intValue = std::get_if<i64>(&tag.second)) { label->set_num(*intValue); - } else if (auto strValue = std::get_if<TString>(&tag.second)) { + } else if (const auto* strValue = std::get_if<std::string>(&tag.second)) { label->set_str(stringify(*strValue)); } } diff --git a/yt/yt/library/ytprof/signal_safe_profiler.h b/yt/yt/library/ytprof/signal_safe_profiler.h index e44516861c..09316039a0 100644 --- a/yt/yt/library/ytprof/signal_safe_profiler.h +++ b/yt/yt/library/ytprof/signal_safe_profiler.h @@ -26,7 +26,7 @@ struct TProfileLocation { size_t Tid = 0; TString ThreadName; - std::vector<std::pair<TString, std::variant<TString, i64>>> Tags; + std::vector<std::pair<std::string, std::variant<std::string, i64>>> Tags; std::vector<ui64> Backtrace; bool operator == (const TProfileLocation& other) const = default; @@ -82,7 +82,8 @@ protected: virtual void EnableProfiler() = 0; virtual void DisableProfiler() = 0; - virtual void AnnotateProfile(NProto::Profile* profile, const std::function<i64(const TString&)>& stringify) = 0; + using TStringify = std::function<i64(const std::string& str)>; + virtual void AnnotateProfile(NProto::Profile* profile, const TStringify& stringify) = 0; virtual i64 EncodeValue(i64 value) = 0; void RecordSample(NBacktrace::TFramePointerCursor* cursor, i64 value); diff --git a/yt/yt/library/ytprof/spinlock_profiler.cpp b/yt/yt/library/ytprof/spinlock_profiler.cpp index a5a03461da..87961cb359 100644 --- a/yt/yt/library/ytprof/spinlock_profiler.cpp +++ b/yt/yt/library/ytprof/spinlock_profiler.cpp @@ -94,7 +94,7 @@ void TSpinlockProfiler::OnEvent(const void* lock, int64_t waitCycles) HandlingEvent_.store(false); } -void TSpinlockProfiler::AnnotateProfile(NProto::Profile* profile, const std::function<i64(const TString&)>& stringify) +void TSpinlockProfiler::AnnotateProfile(NProto::Profile* profile, const TStringify& stringify) { auto sampleType = profile->add_sample_type(); sampleType->set_type(stringify("sample")); @@ -118,7 +118,6 @@ i64 TSpinlockProfiler::EncodeValue(i64 value) //////////////////////////////////////////////////////////////////////////////// - TBlockingProfiler::TBlockingProfiler(TSpinlockProfilerOptions options) : TSignalSafeProfiler(options) , Options_(options) @@ -204,7 +203,7 @@ void TBlockingProfiler::OnEvent( HandlingEvent_.store(false); } -void TBlockingProfiler::AnnotateProfile(NProto::Profile* profile, const std::function<i64(const TString&)>& stringify) +void TBlockingProfiler::AnnotateProfile(NProto::Profile* profile, const TStringify& stringify) { auto sampleType = profile->add_sample_type(); sampleType->set_type(stringify("sample")); diff --git a/yt/yt/library/ytprof/spinlock_profiler.h b/yt/yt/library/ytprof/spinlock_profiler.h index 6df576c3b7..e8aceec85a 100644 --- a/yt/yt/library/ytprof/spinlock_profiler.h +++ b/yt/yt/library/ytprof/spinlock_profiler.h @@ -36,7 +36,7 @@ private: void EnableProfiler() override; void DisableProfiler() override; - void AnnotateProfile(NProto::Profile* profile, const std::function<i64(const TString&)>& stringify) override; + void AnnotateProfile(NProto::Profile* profile, const TStringify& stringify) override; i64 EncodeValue(i64 value) override; static void OnEvent(const void *lock, int64_t waitCycles); @@ -63,7 +63,7 @@ private: void EnableProfiler() override; void DisableProfiler() override; - void AnnotateProfile(NProto::Profile* profile, const std::function<i64(const TString&)>& stringify) override; + void AnnotateProfile(NProto::Profile* profile, const TStringify& stringify) override; i64 EncodeValue(i64 value) override; static void OnEvent( diff --git a/yt/yt/library/ytprof/unittests/heap_profiler_ut.cpp b/yt/yt/library/ytprof/unittests/heap_profiler_ut.cpp index 42dcf6e802..6935216130 100644 --- a/yt/yt/library/ytprof/unittests/heap_profiler_ut.cpp +++ b/yt/yt/library/ytprof/unittests/heap_profiler_ut.cpp @@ -33,22 +33,22 @@ using namespace NTracing; //////////////////////////////////////////////////////////////////////////////// -constexpr auto MemoryAllocationTag = "memory_allocation_tag"; -const std::vector<TString> MemoryAllocationTags = {"0", "1", "2", "3", "4", "5", "6", "7"}; +const std::string MemoryAllocationTagKey = "memory_allocation_tag"; +const std::vector<std::string> MemoryAllocationTagValues = {"0", "1", "2", "3", "4", "5", "6", "7"}; //////////////////////////////////////////////////////////////////////////////// template <size_t Index> Y_NO_INLINE auto BlowHeap() { - std::vector<TString> data; + std::vector<std::string> data; for (int i = 0; i < 10240; i++) { - data.push_back(TString(1024, 'x')); + data.push_back(std::string(1_KB, 'x')); } return data; } -TEST(HeapProfiler, ReadProfile) +TEST(THeapProfilerTest, ReadProfile) { absl::SetStackUnwinder(AbslStackUnwinder); tcmalloc::MallocExtension::SetProfileSamplingRate(256_KB); @@ -56,6 +56,7 @@ TEST(HeapProfiler, ReadProfile) auto token = tcmalloc::MallocExtension::StartAllocationProfiling(); EnableMemoryProfilingTags(); + auto traceContext = TTraceContext::NewRoot("Root"); TTraceContextGuard guard(traceContext); @@ -64,18 +65,18 @@ TEST(HeapProfiler, ReadProfile) auto h0 = BlowHeap<0>(); auto tag = TMemoryTag(1); - traceContext->SetAllocationTags({{"user", "second"}, {"sometag", "notmy"}, {MemoryAllocationTag, ToString(tag)}}); - auto currentTag = traceContext->FindAllocationTag<TMemoryTag>(MemoryAllocationTag); + traceContext->SetAllocationTags({{"user", "second"}, {"sometag", "notmy"}, {MemoryAllocationTagKey, ToString(tag)}}); + auto currentTag = traceContext->FindAllocationTag<TMemoryTag>(MemoryAllocationTagKey); ASSERT_EQ(currentTag, tag); auto h1 = BlowHeap<1>(); - traceContext->ClearAllocationTagsPtr(); + traceContext->SetAllocationTagList(nullptr); auto h2 = BlowHeap<2>(); h2.clear(); - auto usage = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTag, ToString(tag)); + auto usage = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTagKey, ToString(tag)); ASSERT_GE(usage, 5_MB); auto dumpProfile = [] (auto name, auto type) { @@ -98,124 +99,124 @@ TEST(HeapProfiler, ReadProfile) output.Finish(); } -TEST(HeapProfiler, AllocationTagsWithMemoryTag) +TEST(THeapProfilerTest, AllocationTagsWithMemoryTag) { EnableMemoryProfilingTags(); auto traceContext = TTraceContext::NewRoot("Root"); TTraceContextGuard guard(traceContext); - ASSERT_EQ(traceContext->FindAllocationTag<TString>(MemoryAllocationTag), std::nullopt); - traceContext->SetAllocationTags({{"user", "first user"}, {MemoryAllocationTag, MemoryAllocationTags[0]}}); - ASSERT_EQ(traceContext->FindAllocationTag<TString>("user"), "first user"); - ASSERT_EQ(traceContext->FindAllocationTag<TString>(MemoryAllocationTag), MemoryAllocationTags[0]); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>(MemoryAllocationTagKey), std::nullopt); + traceContext->SetAllocationTags({{"user", "first user"}, {MemoryAllocationTagKey, MemoryAllocationTagValues[0]}}); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>("user"), "first user"); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>(MemoryAllocationTagKey), MemoryAllocationTagValues[0]); - std::vector<std::vector<TString>> heap; + std::vector<std::vector<std::string>> heap; heap.push_back(BlowHeap<0>()); - traceContext->SetAllocationTags({{"user", "second user"}, {MemoryAllocationTag, MemoryAllocationTags[1]}}); - ASSERT_EQ(traceContext->FindAllocationTag<TMemoryTag>(MemoryAllocationTag), 1); + traceContext->SetAllocationTags({{"user", "second user"}, {MemoryAllocationTagKey, MemoryAllocationTagValues[1]}}); + ASSERT_EQ(traceContext->FindAllocationTag<TMemoryTag>(MemoryAllocationTagKey), 1); heap.push_back(BlowHeap<1>()); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[0]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[0]); - auto usage1 = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTag, MemoryAllocationTags[1]); + auto usage1 = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTagKey, MemoryAllocationTagValues[1]); ASSERT_NEAR(usage1, 12_MB, 8_MB); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[2]); - ASSERT_EQ(traceContext->FindAllocationTag<TString>(MemoryAllocationTag), MemoryAllocationTags[2]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[2]); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>(MemoryAllocationTagKey), MemoryAllocationTagValues[2]); { volatile auto h = BlowHeap<2>(); } - traceContext->ClearAllocationTagsPtr(); - ASSERT_EQ(traceContext->FindAllocationTag<TString>(MemoryAllocationTag), std::nullopt); + traceContext->SetAllocationTagList(nullptr); + ASSERT_EQ(traceContext->FindAllocationTag<std::string>(MemoryAllocationTagKey), std::nullopt); heap.push_back(BlowHeap<0>()); { - auto snapshot = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTag); - ASSERT_EQ(snapshot[MemoryAllocationTags[1]], usage1); - ASSERT_LE(snapshot[MemoryAllocationTags[2]], 1_MB); + auto slice = CollectMemoryUsageSnapshot()->GetUsageSlice(MemoryAllocationTagKey); + ASSERT_EQ(slice[MemoryAllocationTagValues[1]], usage1); + ASSERT_LE(slice[MemoryAllocationTagValues[2]], 1_MB); } - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[6]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[6]); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[3]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[3]); heap.push_back(BlowHeap<3>()); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[4]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[4]); heap.push_back(BlowHeap<4>()); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[7]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[7]); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[5]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[5]); heap.push_back(BlowHeap<5>()); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[4]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[4]); heap.push_back(BlowHeap<4>()); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[7]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[7]); - traceContext->SetAllocationTagsPtr(nullptr); + traceContext->SetAllocationTagList(nullptr); - auto snapshot = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTag); + auto slice = CollectMemoryUsageSnapshot()->GetUsageSlice(MemoryAllocationTagKey); constexpr auto maxDifference = 10_MB; - ASSERT_NEAR(snapshot[MemoryAllocationTags[1]], snapshot[MemoryAllocationTags[3]], maxDifference); - ASSERT_NEAR(snapshot[MemoryAllocationTags[3]], snapshot[MemoryAllocationTags[5]], maxDifference); - ASSERT_NEAR(snapshot[MemoryAllocationTags[1]], snapshot[MemoryAllocationTags[5]], maxDifference); + ASSERT_NEAR(slice[MemoryAllocationTagValues[1]], slice[MemoryAllocationTagValues[3]], maxDifference); + ASSERT_NEAR(slice[MemoryAllocationTagValues[3]], slice[MemoryAllocationTagValues[5]], maxDifference); + ASSERT_NEAR(slice[MemoryAllocationTagValues[1]], slice[MemoryAllocationTagValues[5]], maxDifference); - ASSERT_NEAR(snapshot[MemoryAllocationTags[4]], 20_MB, 15_MB); + ASSERT_NEAR(slice[MemoryAllocationTagValues[4]], 20_MB, 15_MB); - ASSERT_NEAR(snapshot[MemoryAllocationTags[4]], snapshot[MemoryAllocationTags[1]] + snapshot[MemoryAllocationTags[3]], 2 * maxDifference); - ASSERT_NEAR(snapshot[MemoryAllocationTags[4]], snapshot[MemoryAllocationTags[1]] + snapshot[MemoryAllocationTags[5]], 2 * maxDifference); - ASSERT_NEAR(snapshot[MemoryAllocationTags[4]], snapshot[MemoryAllocationTags[3]] + snapshot[MemoryAllocationTags[5]], 2 * maxDifference); + ASSERT_NEAR(slice[MemoryAllocationTagValues[4]], slice[MemoryAllocationTagValues[1]] + slice[MemoryAllocationTagValues[3]], 2 * maxDifference); + ASSERT_NEAR(slice[MemoryAllocationTagValues[4]], slice[MemoryAllocationTagValues[1]] + slice[MemoryAllocationTagValues[5]], 2 * maxDifference); + ASSERT_NEAR(slice[MemoryAllocationTagValues[4]], slice[MemoryAllocationTagValues[3]] + slice[MemoryAllocationTagValues[5]], 2 * maxDifference); - ASSERT_LE(snapshot[MemoryAllocationTags[6]], 1_MB); - ASSERT_LE(snapshot[MemoryAllocationTags[7]], 1_MB); + ASSERT_LE(slice[MemoryAllocationTagValues[6]], 1_MB); + ASSERT_LE(slice[MemoryAllocationTagValues[7]], 1_MB); } template <size_t Index> Y_NO_INLINE auto BlowHeap(int64_t megabytes) { - std::vector<TString> data; + std::vector<std::string> data; megabytes <<= 10; for (int64_t i = 0; i < megabytes; i++) { - data.push_back(TString( 1024, 'x')); + data.push_back(std::string(1_KB, 'x')); } return data; } -TEST(HeapProfiler, HugeAllocationsTagsWithMemoryTag) +TEST(THeapProfilerTest, HugeAllocationsTagsWithMemoryTag) { EnableMemoryProfilingTags(); auto traceContext = TTraceContext::NewRoot("Root"); TCurrentTraceContextGuard guard(traceContext); - std::vector<std::vector<TString>> heap; + std::vector<std::vector<std::string>> heap; heap.push_back(BlowHeap<0>()); - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[1]); - ASSERT_EQ(traceContext->FindAllocationTag<TMemoryTag>(MemoryAllocationTag), 1); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[1]); + ASSERT_EQ(traceContext->FindAllocationTag<TMemoryTag>(MemoryAllocationTagKey), 1); heap.push_back(BlowHeap<1>(100)); { - traceContext->SetAllocationTagsPtr(nullptr); - auto usage = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTag, MemoryAllocationTags[1]); + traceContext->SetAllocationTagList(nullptr); + auto usage = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTagKey, MemoryAllocationTagValues[1]); ASSERT_GE(usage, 100_MB); ASSERT_LE(usage, 150_MB); } - traceContext->SetAllocationTag(MemoryAllocationTag, MemoryAllocationTags[2]); + traceContext->SetAllocationTag(MemoryAllocationTagKey, MemoryAllocationTagValues[2]); heap.push_back(BlowHeap<1>(1000)); - traceContext->SetAllocationTagsPtr(nullptr); - auto usage = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTag, MemoryAllocationTags[2]); + traceContext->SetAllocationTagList(nullptr); + auto usage = CollectMemoryUsageSnapshot()->GetUsage(MemoryAllocationTagKey, MemoryAllocationTagValues[2]); ASSERT_GE(usage, 1000_MB); ASSERT_LE(usage, 1300_MB); } |