diff options
author | monster <monster@yandex-team.ru> | 2022-02-10 16:47:19 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:47:19 +0300 |
commit | b23c1d7a8015c2006a148fd93b84cdeb0aee17a3 (patch) | |
tree | 9814fbd1c3effac9b8377c5d604b367b14e2db55 /library/cpp/actors | |
parent | dd76ae1f6213d065375ab296699f764faafbe5bd (diff) | |
download | ydb-b23c1d7a8015c2006a148fd93b84cdeb0aee17a3.tar.gz |
Restoring authorship annotation for <monster@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/actors')
25 files changed, 1022 insertions, 1022 deletions
diff --git a/library/cpp/actors/core/README.md b/library/cpp/actors/core/README.md index 3cd4354c6d..439a8dd459 100644 --- a/library/cpp/actors/core/README.md +++ b/library/cpp/actors/core/README.md @@ -1,99 +1,99 @@ -## Memory tracker - -https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/actors/core/memory_track.h - -Использование: - -* отслеживание аллокаций экземпляров конкретного класса через new/delete и new[]/delete[] -* отслеживание аллокаций в контейнерах -* ручное отслеживание моментов аллокации/деаллокации - ----- - -### Отслеживание аллокаций класса через new/delete - -Использование с автоматически генерируемой меткой: - -```cpp -#include <library/cpp/actors/core/memory_track.h> - -struct TTypeLabeled - : public NActors::NMemory::TTrack<TTypeLabeled> -{ - char payload[16]; -}; -``` - -Использование с пользовательским именем метки: - -```cpp -#include <library/cpp/actors/core/memory_track.h> - -static const char NamedLabel[] = "NamedLabel"; - -struct TNameLabeled - : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> -{ - char payload[32]; -}; -``` - ----- - -### Отслеживание аллокаций в контейнерах - -```cpp -#include <library/cpp/actors/core/memory_track.h> - -static const char InContainerLabel[] = "InContainerLabel"; - -struct TInContainer { - char payload[16]; -}; - -std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; - -std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; - -using TKey = int; - -std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; - -std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; - -std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; - -std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; -``` - ----- - -### Ручное отслеживание аллокаций/деаллокаций - -```cpp -#include <library/cpp/actors/core/memory_track.h> - -static const char ManualLabel[] = "ManualLabel"; - -... -NActors::NMemory::TLabel<ManualLabel>::Add(size); - -... -NActors::NMemory::TLabel<ManualLabel>::Sub(size); -``` - ----- - -### Собираемые метрики - -Сервис **utils**, пользовательская метка **label**, сенсоры: - -- MT/Count: количество аллокаций в моменте -- MT/Memory: аллоцированная память в моменте -- MT/PeakCount: пиковое значение количества аллокаций (сэмплится с фиксированной частотой) -- MT/PeakMemory: пиковое значение аллоцированной памяти - +## Memory tracker + +https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/actors/core/memory_track.h + +Использование: + +* отслеживание аллокаций экземпляров конкретного класса через new/delete и new[]/delete[] +* отслеживание аллокаций в контейнерах +* ручное отслеживание моментов аллокации/деаллокации + +---- + +### Отслеживание аллокаций класса через new/delete + +Использование с автоматически генерируемой меткой: + +```cpp +#include <library/cpp/actors/core/memory_track.h> + +struct TTypeLabeled + : public NActors::NMemory::TTrack<TTypeLabeled> +{ + char payload[16]; +}; +``` + +Использование с пользовательским именем метки: + +```cpp +#include <library/cpp/actors/core/memory_track.h> + +static const char NamedLabel[] = "NamedLabel"; + +struct TNameLabeled + : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> +{ + char payload[32]; +}; +``` + +---- + +### Отслеживание аллокаций в контейнерах + +```cpp +#include <library/cpp/actors/core/memory_track.h> + +static const char InContainerLabel[] = "InContainerLabel"; + +struct TInContainer { + char payload[16]; +}; + +std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; + +std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; + +using TKey = int; + +std::map<TKey, TInContainer, std::less<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; + +std::map<TKey, TInContainer, std::less<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; + +std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; + +std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; +``` + +---- + +### Ручное отслеживание аллокаций/деаллокаций + +```cpp +#include <library/cpp/actors/core/memory_track.h> + +static const char ManualLabel[] = "ManualLabel"; + +... +NActors::NMemory::TLabel<ManualLabel>::Add(size); + +... +NActors::NMemory::TLabel<ManualLabel>::Sub(size); +``` + +---- + +### Собираемые метрики + +Сервис **utils**, пользовательская метка **label**, сенсоры: + +- MT/Count: количество аллокаций в моменте +- MT/Memory: аллоцированная память в моменте +- MT/PeakCount: пиковое значение количества аллокаций (сэмплится с фиксированной частотой) +- MT/PeakMemory: пиковое значение аллоцированной памяти + diff --git a/library/cpp/actors/core/actorsystem.h b/library/cpp/actors/core/actorsystem.h index 7df0a9f633..40499d7586 100644 --- a/library/cpp/actors/core/actorsystem.h +++ b/library/cpp/actors/core/actorsystem.h @@ -332,8 +332,8 @@ namespace NActors { TActorId LookupLocalService(const TActorId& x) const; TActorId RegisterLocalService(const TActorId& serviceId, const TActorId& actorId); - ui32 GetMaxActivityType() const { - return SystemSetup ? SystemSetup->MaxActivityType : 1; + ui32 GetMaxActivityType() const { + return SystemSetup ? SystemSetup->MaxActivityType : 1; } TInstant Timestamp() const { diff --git a/library/cpp/actors/core/event.h b/library/cpp/actors/core/event.h index dbdb45daac..6ff02aaf94 100644 --- a/library/cpp/actors/core/event.h +++ b/library/cpp/actors/core/event.h @@ -46,8 +46,8 @@ namespace NActors { }; // fat handle - class IEventHandle : TNonCopyable { - struct TOnNondelivery { + class IEventHandle : TNonCopyable { + struct TOnNondelivery { TActorId Recipient; TOnNondelivery(const TActorId& recipient) diff --git a/library/cpp/actors/core/executor_thread.cpp b/library/cpp/actors/core/executor_thread.cpp index ae5f111dff..446b651efd 100644 --- a/library/cpp/actors/core/executor_thread.cpp +++ b/library/cpp/actors/core/executor_thread.cpp @@ -137,7 +137,7 @@ namespace NActors { NHPTimer::STime hpprev = hpstart; IActor* actor = nullptr; - ui32 prevActivityType = std::numeric_limits<ui32>::max(); + ui32 prevActivityType = std::numeric_limits<ui32>::max(); TActorId recipient; for (ui32 executed = 0; executed < Ctx.EventsPerMailbox; ++executed) { TAutoPtr<IEventHandle> ev(mailbox->Pop()); @@ -170,14 +170,14 @@ namespace NActors { ui32 evTypeForTracing = ev->Type; - ui32 activityType = actor->GetActivityType(); - if (activityType != prevActivityType) { - prevActivityType = activityType; - NProfiling::TMemoryTagScope::Reset(ActorSystem->MemProfActivityBase + activityType); + ui32 activityType = actor->GetActivityType(); + if (activityType != prevActivityType) { + prevActivityType = activityType; + NProfiling::TMemoryTagScope::Reset(ActorSystem->MemProfActivityBase + activityType); } - actor->Receive(ev, ctx); - + actor->Receive(ev, ctx); + size_t dyingActorsCnt = DyingActors.size(); Ctx.UpdateActorsStats(dyingActorsCnt); if (dyingActorsCnt) { @@ -273,7 +273,7 @@ namespace NActors { } } - NProfiling::TMemoryTagScope::Reset(0); + NProfiling::TMemoryTagScope::Reset(0); TlsActivationContext = nullptr; UnlockFromExecution(mailbox, Ctx.Executor, reclaimAsFree, hint, Ctx.WorkerId, RevolvingWriteCounter); } diff --git a/library/cpp/actors/core/mailbox.h b/library/cpp/actors/core/mailbox.h index 277a259932..0bd9c4d314 100644 --- a/library/cpp/actors/core/mailbox.h +++ b/library/cpp/actors/core/mailbox.h @@ -397,7 +397,7 @@ namespace NActors { static_assert(sizeof(TRevolvingMailbox) == 128, "expect sizeof(TRevolvingMailbox) == 128"); struct THTSwapMailbox: public TMailboxHeader { - using TQueueType = NThreading::THTSwapQueue<IEventHandle*>; + using TQueueType = NThreading::THTSwapQueue<IEventHandle*>; TQueueType Queue; NHPTimer::STime ScheduleMoment; @@ -447,7 +447,7 @@ namespace NActors { "expect sizeof(THTSwapMailbox) == 64"); struct TReadAsFilledMailbox: public TMailboxHeader { - using TQueueType = NThreading::TReadAsFilledQueue<IEventHandle>; + using TQueueType = NThreading::TReadAsFilledQueue<IEventHandle>; TQueueType Queue; NHPTimer::STime ScheduleMoment; diff --git a/library/cpp/actors/core/memory_track.cpp b/library/cpp/actors/core/memory_track.cpp index 79392ef686..5f422116be 100644 --- a/library/cpp/actors/core/memory_track.cpp +++ b/library/cpp/actors/core/memory_track.cpp @@ -1,38 +1,38 @@ -#include "memory_track.h" -#include "memory_tracker.h" - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -TThreadLocalInfo::TThreadLocalInfo() - : Metrics(TMemoryTracker::Instance()->GetCount()) -{ - TMemoryTracker::Instance()->OnCreateThread(this); -} - -TThreadLocalInfo::~TThreadLocalInfo() { - TMemoryTracker::Instance()->OnDestroyThread(this); -} - -TMetric* TThreadLocalInfo::GetMetric(size_t index) { - if (Y_UNLIKELY(index >= Metrics.size())) { - return &Null; - } - return &Metrics[index]; -} - -const std::vector<TMetric>& TThreadLocalInfo::GetMetrics() const { - return Metrics; -} - -size_t TBaseLabel::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { - return TMemoryTracker::Instance()->RegisterStaticMemoryLabel(name, hasSensor); -} - -} - -} -} - +#include "memory_track.h" +#include "memory_tracker.h" + +namespace NActors { +namespace NMemory { + +namespace NPrivate { + +TThreadLocalInfo::TThreadLocalInfo() + : Metrics(TMemoryTracker::Instance()->GetCount()) +{ + TMemoryTracker::Instance()->OnCreateThread(this); +} + +TThreadLocalInfo::~TThreadLocalInfo() { + TMemoryTracker::Instance()->OnDestroyThread(this); +} + +TMetric* TThreadLocalInfo::GetMetric(size_t index) { + if (Y_UNLIKELY(index >= Metrics.size())) { + return &Null; + } + return &Metrics[index]; +} + +const std::vector<TMetric>& TThreadLocalInfo::GetMetrics() const { + return Metrics; +} + +size_t TBaseLabel::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { + return TMemoryTracker::Instance()->RegisterStaticMemoryLabel(name, hasSensor); +} + +} + +} +} + diff --git a/library/cpp/actors/core/memory_track.h b/library/cpp/actors/core/memory_track.h index 97a7c5dfae..6035333eeb 100644 --- a/library/cpp/actors/core/memory_track.h +++ b/library/cpp/actors/core/memory_track.h @@ -1,293 +1,293 @@ -#pragma once - -#include <vector> - +#pragma once + +#include <vector> + #include <util/system/type_name.h> -#include <util/thread/singleton.h> - -#define ENABLE_MEMORY_TRACKING - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -class TMetric { - std::atomic<ssize_t> Memory; - std::atomic<ssize_t> Count; - - void Copy(const TMetric& other) { - Memory.store(other.GetMemory(), std::memory_order_relaxed); - Count.store(other.GetCount(), std::memory_order_relaxed); - } - -public: - TMetric() - : Memory(0) - , Count(0) - {} - - inline TMetric(const TMetric& other) { - Copy(other); - } - - inline TMetric(TMetric&& other) { - Copy(other); - } - - inline TMetric& operator=(const TMetric& other) { - Copy(other); - return *this; - } - - inline TMetric& operator=(TMetric&& other) { - Copy(other); - return *this; - } - - inline ssize_t GetMemory() const { - return Memory.load(std::memory_order_relaxed); - } - inline void SetMemory(ssize_t value) { - Memory.store(value, std::memory_order_relaxed); - } - - inline ssize_t GetCount() const { - return Count.load(std::memory_order_relaxed); - } - inline void SetCount(ssize_t value) { - Count.store(value, std::memory_order_relaxed); - } - - inline void operator+=(const TMetric& other) { - SetMemory(GetMemory() + other.GetMemory()); - SetCount(GetCount() + other.GetCount()); - } - - inline void CalculatePeak(const TMetric& other) { - SetMemory(Max(GetMemory(), other.GetMemory())); - SetCount(Max(GetCount(), other.GetCount())); - } - - inline void Add(size_t size) { - SetMemory(GetMemory() + size); - SetCount(GetCount() + 1); - } - - inline void Sub(size_t size) { - SetMemory(GetMemory() - size); - SetCount(GetCount() - 1); - } -}; - - -class TThreadLocalInfo { -public: - TThreadLocalInfo(); - ~TThreadLocalInfo(); - - TMetric* GetMetric(size_t index); - const std::vector<TMetric>& GetMetrics() const; - -private: - std::vector<TMetric> Metrics; - - inline static TMetric Null = {}; -}; - - -class TBaseLabel { -protected: - static size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); - - inline static TMetric* GetLocalMetric(size_t index) { - return FastTlsSingleton<TThreadLocalInfo>()->GetMetric(index); - } -}; - - -template <const char* Name> -class TNameLabel - : TBaseLabel -{ -public: - static void Add(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Add(size); -#else - Y_UNUSED(size); -#endif - } - - static void Sub(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Sub(size); -#else - Y_UNUSED(size); -#endif - } - -private: -#if defined(ENABLE_MEMORY_TRACKING) - inline static size_t Index = Max<size_t>(); - inline static struct TMetricInit { - TMetricInit() { - Index = RegisterStaticMemoryLabel(Name, true); - } - } MetricInit; - - inline static thread_local TMetric* Metric = nullptr; -#endif -}; - - -template <typename TType> -class TTypeLabel - : TBaseLabel -{ -public: - static void Add(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Add(size); -#else - Y_UNUSED(size); -#endif - } - - static void Sub(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Sub(size); -#else - Y_UNUSED(size); -#endif - } - -private: -#if defined(ENABLE_MEMORY_TRACKING) - inline static size_t Index = Max<size_t>(); - inline static struct TMetricInit { - TMetricInit() { - Index = RegisterStaticMemoryLabel(TypeName<TType>().c_str(), false); - } - } MetricInit; - - inline static thread_local TMetric* Metric = nullptr; -#endif -}; - - -template <typename T> -struct TTrackHelper { -#if defined(ENABLE_MEMORY_TRACKING) - void* operator new(size_t size) { - T::Add(size); - return malloc(size); - } - - void* operator new[](size_t size) { - T::Add(size); - return malloc(size); - } - - void operator delete(void* ptr, size_t size) { - T::Sub(size); - free(ptr); - } - - void operator delete[](void* ptr, size_t size) { - T::Sub(size); - free(ptr); - } -#endif -}; - -template <typename TType, typename T> -struct TAllocHelper { - typedef size_t size_type; - typedef TType value_type; - typedef TType* pointer; - typedef const TType* const_pointer; - - struct propagate_on_container_copy_assignment : public std::false_type {}; - struct propagate_on_container_move_assignment : public std::false_type {}; - struct propagate_on_container_swap : public std::false_type {}; - - pointer allocate(size_type n, const void* hint = nullptr) { - Y_UNUSED(hint); - auto size = n * sizeof(TType); - T::Add(size); - return (pointer)malloc(size); - } - - void deallocate(pointer ptr, size_t n) { - auto size = n * sizeof(TType); - T::Sub(size); - free((void*)ptr); - } -}; - -} // NPrivate - - -template <const char* Name> -using TLabel = NPrivate::TNameLabel<Name>; - -template <typename TType, const char* Name = nullptr> -struct TTrack - : public NPrivate::TTrackHelper<NPrivate::TNameLabel<Name>> -{ -}; - -template <typename TType> -struct TTrack<TType, nullptr> - : public NPrivate::TTrackHelper<NPrivate::TTypeLabel<TType>> -{ -}; - -template <typename TType, const char* Name = nullptr> -struct TAlloc - : public NPrivate::TAllocHelper<TType, NPrivate::TNameLabel<Name>> -{ - template<typename U> - struct rebind { - typedef TAlloc<U, Name> other; - }; -}; - -template <typename TType> -struct TAlloc<TType, nullptr> - : public NPrivate::TAllocHelper<TType, NPrivate::TTypeLabel<TType>> -{ - template<typename U> - struct rebind { - typedef TAlloc<U> other; - }; -}; - -} -} - +#include <util/thread/singleton.h> + +#define ENABLE_MEMORY_TRACKING + +namespace NActors { +namespace NMemory { + +namespace NPrivate { + +class TMetric { + std::atomic<ssize_t> Memory; + std::atomic<ssize_t> Count; + + void Copy(const TMetric& other) { + Memory.store(other.GetMemory(), std::memory_order_relaxed); + Count.store(other.GetCount(), std::memory_order_relaxed); + } + +public: + TMetric() + : Memory(0) + , Count(0) + {} + + inline TMetric(const TMetric& other) { + Copy(other); + } + + inline TMetric(TMetric&& other) { + Copy(other); + } + + inline TMetric& operator=(const TMetric& other) { + Copy(other); + return *this; + } + + inline TMetric& operator=(TMetric&& other) { + Copy(other); + return *this; + } + + inline ssize_t GetMemory() const { + return Memory.load(std::memory_order_relaxed); + } + inline void SetMemory(ssize_t value) { + Memory.store(value, std::memory_order_relaxed); + } + + inline ssize_t GetCount() const { + return Count.load(std::memory_order_relaxed); + } + inline void SetCount(ssize_t value) { + Count.store(value, std::memory_order_relaxed); + } + + inline void operator+=(const TMetric& other) { + SetMemory(GetMemory() + other.GetMemory()); + SetCount(GetCount() + other.GetCount()); + } + + inline void CalculatePeak(const TMetric& other) { + SetMemory(Max(GetMemory(), other.GetMemory())); + SetCount(Max(GetCount(), other.GetCount())); + } + + inline void Add(size_t size) { + SetMemory(GetMemory() + size); + SetCount(GetCount() + 1); + } + + inline void Sub(size_t size) { + SetMemory(GetMemory() - size); + SetCount(GetCount() - 1); + } +}; + + +class TThreadLocalInfo { +public: + TThreadLocalInfo(); + ~TThreadLocalInfo(); + + TMetric* GetMetric(size_t index); + const std::vector<TMetric>& GetMetrics() const; + +private: + std::vector<TMetric> Metrics; + + inline static TMetric Null = {}; +}; + + +class TBaseLabel { +protected: + static size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); + + inline static TMetric* GetLocalMetric(size_t index) { + return FastTlsSingleton<TThreadLocalInfo>()->GetMetric(index); + } +}; + + +template <const char* Name> +class TNameLabel + : TBaseLabel +{ +public: + static void Add(size_t size) { +#if defined(ENABLE_MEMORY_TRACKING) + Y_UNUSED(MetricInit); + + if (Y_UNLIKELY(!Metric)) { + Metric = GetLocalMetric(Index); + } + + Metric->Add(size); +#else + Y_UNUSED(size); +#endif + } + + static void Sub(size_t size) { +#if defined(ENABLE_MEMORY_TRACKING) + Y_UNUSED(MetricInit); + + if (Y_UNLIKELY(!Metric)) { + Metric = GetLocalMetric(Index); + } + + Metric->Sub(size); +#else + Y_UNUSED(size); +#endif + } + +private: +#if defined(ENABLE_MEMORY_TRACKING) + inline static size_t Index = Max<size_t>(); + inline static struct TMetricInit { + TMetricInit() { + Index = RegisterStaticMemoryLabel(Name, true); + } + } MetricInit; + + inline static thread_local TMetric* Metric = nullptr; +#endif +}; + + +template <typename TType> +class TTypeLabel + : TBaseLabel +{ +public: + static void Add(size_t size) { +#if defined(ENABLE_MEMORY_TRACKING) + Y_UNUSED(MetricInit); + + if (Y_UNLIKELY(!Metric)) { + Metric = GetLocalMetric(Index); + } + + Metric->Add(size); +#else + Y_UNUSED(size); +#endif + } + + static void Sub(size_t size) { +#if defined(ENABLE_MEMORY_TRACKING) + Y_UNUSED(MetricInit); + + if (Y_UNLIKELY(!Metric)) { + Metric = GetLocalMetric(Index); + } + + Metric->Sub(size); +#else + Y_UNUSED(size); +#endif + } + +private: +#if defined(ENABLE_MEMORY_TRACKING) + inline static size_t Index = Max<size_t>(); + inline static struct TMetricInit { + TMetricInit() { + Index = RegisterStaticMemoryLabel(TypeName<TType>().c_str(), false); + } + } MetricInit; + + inline static thread_local TMetric* Metric = nullptr; +#endif +}; + + +template <typename T> +struct TTrackHelper { +#if defined(ENABLE_MEMORY_TRACKING) + void* operator new(size_t size) { + T::Add(size); + return malloc(size); + } + + void* operator new[](size_t size) { + T::Add(size); + return malloc(size); + } + + void operator delete(void* ptr, size_t size) { + T::Sub(size); + free(ptr); + } + + void operator delete[](void* ptr, size_t size) { + T::Sub(size); + free(ptr); + } +#endif +}; + +template <typename TType, typename T> +struct TAllocHelper { + typedef size_t size_type; + typedef TType value_type; + typedef TType* pointer; + typedef const TType* const_pointer; + + struct propagate_on_container_copy_assignment : public std::false_type {}; + struct propagate_on_container_move_assignment : public std::false_type {}; + struct propagate_on_container_swap : public std::false_type {}; + + pointer allocate(size_type n, const void* hint = nullptr) { + Y_UNUSED(hint); + auto size = n * sizeof(TType); + T::Add(size); + return (pointer)malloc(size); + } + + void deallocate(pointer ptr, size_t n) { + auto size = n * sizeof(TType); + T::Sub(size); + free((void*)ptr); + } +}; + +} // NPrivate + + +template <const char* Name> +using TLabel = NPrivate::TNameLabel<Name>; + +template <typename TType, const char* Name = nullptr> +struct TTrack + : public NPrivate::TTrackHelper<NPrivate::TNameLabel<Name>> +{ +}; + +template <typename TType> +struct TTrack<TType, nullptr> + : public NPrivate::TTrackHelper<NPrivate::TTypeLabel<TType>> +{ +}; + +template <typename TType, const char* Name = nullptr> +struct TAlloc + : public NPrivate::TAllocHelper<TType, NPrivate::TNameLabel<Name>> +{ + template<typename U> + struct rebind { + typedef TAlloc<U, Name> other; + }; +}; + +template <typename TType> +struct TAlloc<TType, nullptr> + : public NPrivate::TAllocHelper<TType, NPrivate::TTypeLabel<TType>> +{ + template<typename U> + struct rebind { + typedef TAlloc<U> other; + }; +}; + +} +} + diff --git a/library/cpp/actors/core/memory_tracker.cpp b/library/cpp/actors/core/memory_tracker.cpp index 42b93a2868..8a12452c71 100644 --- a/library/cpp/actors/core/memory_tracker.cpp +++ b/library/cpp/actors/core/memory_tracker.cpp @@ -1,103 +1,103 @@ -#include "memory_tracker.h" - -#include <util/generic/xrange.h> - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -TMemoryTracker* TMemoryTracker::Instance() { - return SingletonWithPriority<TMemoryTracker, 0>(); -} - -void TMemoryTracker::Initialize() { - GlobalMetrics.resize(Indices.size()); -} - -const std::map<TString, size_t>& TMemoryTracker::GetMetricIndices() const { - return Indices; -} - -const std::unordered_set<size_t>& TMemoryTracker::GetSensors() const { - return Sensors; -} - -TString TMemoryTracker::GetName(size_t index) const { - return Names[index]; -} - -size_t TMemoryTracker::GetCount() const { - return Indices.size(); -} - -void TMemoryTracker::GatherMetrics(std::vector<TMetric>& metrics) const { - metrics.resize(0); - auto count = GetCount(); - - if (!count || GlobalMetrics.size() != count) { - return; - } - - TReadGuard guard(LockThreadInfo); - - metrics.resize(count); - for (size_t i : xrange(count)) { - metrics[i] += GlobalMetrics[i]; - } - - for (auto info : ThreadInfo) { - auto& localMetrics = info->GetMetrics(); - if (localMetrics.size() == count) { - for (size_t i : xrange(count)) { - metrics[i] += localMetrics[i]; - } - } - } -} - -size_t TMemoryTracker::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { - size_t index = 0; - auto found = Indices.find(name); - if (found == Indices.end()) { - TString str(name); - auto next = Names.size(); - Indices.emplace(str, next); - Names.push_back(str); - index = next; - } else { - index = found->second; - } - - if (hasSensor) { - Sensors.emplace(index); - } - return index; -} - -void TMemoryTracker::OnCreateThread(TThreadLocalInfo* info) { - TWriteGuard guard(LockThreadInfo); - ThreadInfo.insert(info); -} - -void TMemoryTracker::OnDestroyThread(TThreadLocalInfo* info) { - TWriteGuard guard(LockThreadInfo); - - auto count = GetCount(); - if (count && GlobalMetrics.size() == count) { - const auto& localMetrics = info->GetMetrics(); - if (localMetrics.size() == count) { - for (size_t i : xrange(count)) { - GlobalMetrics[i] += localMetrics[i]; - } - } - } - - ThreadInfo.erase(info); -} - -} - -} -} - +#include "memory_tracker.h" + +#include <util/generic/xrange.h> + +namespace NActors { +namespace NMemory { + +namespace NPrivate { + +TMemoryTracker* TMemoryTracker::Instance() { + return SingletonWithPriority<TMemoryTracker, 0>(); +} + +void TMemoryTracker::Initialize() { + GlobalMetrics.resize(Indices.size()); +} + +const std::map<TString, size_t>& TMemoryTracker::GetMetricIndices() const { + return Indices; +} + +const std::unordered_set<size_t>& TMemoryTracker::GetSensors() const { + return Sensors; +} + +TString TMemoryTracker::GetName(size_t index) const { + return Names[index]; +} + +size_t TMemoryTracker::GetCount() const { + return Indices.size(); +} + +void TMemoryTracker::GatherMetrics(std::vector<TMetric>& metrics) const { + metrics.resize(0); + auto count = GetCount(); + + if (!count || GlobalMetrics.size() != count) { + return; + } + + TReadGuard guard(LockThreadInfo); + + metrics.resize(count); + for (size_t i : xrange(count)) { + metrics[i] += GlobalMetrics[i]; + } + + for (auto info : ThreadInfo) { + auto& localMetrics = info->GetMetrics(); + if (localMetrics.size() == count) { + for (size_t i : xrange(count)) { + metrics[i] += localMetrics[i]; + } + } + } +} + +size_t TMemoryTracker::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { + size_t index = 0; + auto found = Indices.find(name); + if (found == Indices.end()) { + TString str(name); + auto next = Names.size(); + Indices.emplace(str, next); + Names.push_back(str); + index = next; + } else { + index = found->second; + } + + if (hasSensor) { + Sensors.emplace(index); + } + return index; +} + +void TMemoryTracker::OnCreateThread(TThreadLocalInfo* info) { + TWriteGuard guard(LockThreadInfo); + ThreadInfo.insert(info); +} + +void TMemoryTracker::OnDestroyThread(TThreadLocalInfo* info) { + TWriteGuard guard(LockThreadInfo); + + auto count = GetCount(); + if (count && GlobalMetrics.size() == count) { + const auto& localMetrics = info->GetMetrics(); + if (localMetrics.size() == count) { + for (size_t i : xrange(count)) { + GlobalMetrics[i] += localMetrics[i]; + } + } + } + + ThreadInfo.erase(info); +} + +} + +} +} + diff --git a/library/cpp/actors/core/memory_tracker.h b/library/cpp/actors/core/memory_tracker.h index 7b29c673cf..e74508191b 100644 --- a/library/cpp/actors/core/memory_tracker.h +++ b/library/cpp/actors/core/memory_tracker.h @@ -1,53 +1,53 @@ -#pragma once - -#include "memory_track.h" - -#include <map> -#include <unordered_map> -#include <unordered_set> - -#include <util/system/rwlock.h> - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -class TMemoryTracker { -public: - static TMemoryTracker* Instance(); - - void Initialize(); - - const std::map<TString, size_t>& GetMetricIndices() const; - const std::unordered_set<size_t>& GetSensors() const; - TString GetName(size_t index) const; - size_t GetCount() const; - - void GatherMetrics(std::vector<TMetric>& metrics) const; - -private: - size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); - - void OnCreateThread(TThreadLocalInfo* info); - void OnDestroyThread(TThreadLocalInfo* info); - -private: - std::map<TString, size_t> Indices; - std::vector<TString> Names; - - std::vector<TMetric> GlobalMetrics; - - std::unordered_set<size_t> Sensors; - - std::unordered_set<TThreadLocalInfo*> ThreadInfo; - TRWMutex LockThreadInfo; - - friend class TThreadLocalInfo; - friend class TBaseLabel; -}; - -} - -} -} +#pragma once + +#include "memory_track.h" + +#include <map> +#include <unordered_map> +#include <unordered_set> + +#include <util/system/rwlock.h> + +namespace NActors { +namespace NMemory { + +namespace NPrivate { + +class TMemoryTracker { +public: + static TMemoryTracker* Instance(); + + void Initialize(); + + const std::map<TString, size_t>& GetMetricIndices() const; + const std::unordered_set<size_t>& GetSensors() const; + TString GetName(size_t index) const; + size_t GetCount() const; + + void GatherMetrics(std::vector<TMetric>& metrics) const; + +private: + size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); + + void OnCreateThread(TThreadLocalInfo* info); + void OnDestroyThread(TThreadLocalInfo* info); + +private: + std::map<TString, size_t> Indices; + std::vector<TString> Names; + + std::vector<TMetric> GlobalMetrics; + + std::unordered_set<size_t> Sensors; + + std::unordered_set<TThreadLocalInfo*> ThreadInfo; + TRWMutex LockThreadInfo; + + friend class TThreadLocalInfo; + friend class TBaseLabel; +}; + +} + +} +} diff --git a/library/cpp/actors/core/memory_tracker_ut.cpp b/library/cpp/actors/core/memory_tracker_ut.cpp index a9d3f502f1..d168214da6 100644 --- a/library/cpp/actors/core/memory_tracker_ut.cpp +++ b/library/cpp/actors/core/memory_tracker_ut.cpp @@ -1,262 +1,262 @@ -#include "memory_tracker.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/system/hp_timer.h> -#include <util/system/thread.h> - -namespace NActors { -namespace NMemory { - -Y_UNIT_TEST_SUITE(TMemoryTrackerTest) { - -#if defined(ENABLE_MEMORY_TRACKING) - -using namespace NPrivate; - -size_t FindLabelIndex(const char* label) { - auto indices = TMemoryTracker::Instance()->GetMetricIndices(); - auto it = indices.find(label); - UNIT_ASSERT(it != indices.end()); - return it->second; -} - - -struct TTypeLabeled - : public NActors::NMemory::TTrack<TTypeLabeled> -{ - char payload[16]; -}; - -static constexpr char NamedLabel[] = "NamedLabel"; - -struct TNameLabeled - : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> -{ - char payload[32]; -}; - -Y_UNIT_TEST(Gathering) -{ - TMemoryTracker::Instance()->Initialize(); - - auto* typed = new TTypeLabeled; - auto* typedArray = new TTypeLabeled[3]; - - auto* named = new TNameLabeled; - auto* namedArray = new TNameLabeled[5]; - NActors::NMemory::TLabel<NamedLabel>::Add(100); - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - - auto typeIndex = FindLabelIndex(TypeName<TTypeLabeled>().c_str()); - UNIT_ASSERT(typeIndex < metrics.size()); - UNIT_ASSERT(metrics[typeIndex].GetMemory() == sizeof(TTypeLabeled) * 4 + sizeof(size_t)); - UNIT_ASSERT(metrics[typeIndex].GetCount() == 2); - - auto nameIndex = FindLabelIndex(NamedLabel); - UNIT_ASSERT(nameIndex < metrics.size()); - UNIT_ASSERT(metrics[nameIndex].GetMemory() == sizeof(TNameLabeled) * 6 + sizeof(size_t) + 100); - UNIT_ASSERT(metrics[nameIndex].GetCount() == 3); - - NActors::NMemory::TLabel<NamedLabel>::Sub(100); - delete [] namedArray; - delete named; - - delete [] typedArray; - delete typed; - - TMemoryTracker::Instance()->GatherMetrics(metrics); - - UNIT_ASSERT(metrics[typeIndex].GetMemory() == 0); - UNIT_ASSERT(metrics[typeIndex].GetCount() == 0); - - UNIT_ASSERT(metrics[nameIndex].GetMemory() == 0); - UNIT_ASSERT(metrics[nameIndex].GetCount() == 0); -} - - -static constexpr char InContainerLabel[] = "InContainerLabel"; - -struct TInContainer { - char payload[16]; -}; - -Y_UNIT_TEST(Containers) { - TMemoryTracker::Instance()->Initialize(); - - std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; - vecT.resize(5); - - std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; - vecN.resize(7); - - using TKey = int; - - std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; - mapT.emplace(0, TInContainer()); - mapT.emplace(1, TInContainer()); - - std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; - mapN.emplace(0, TInContainer()); - - std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; - umapT.emplace(0, TInContainer()); - - std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; - umapN.emplace(0, TInContainer()); - umapN.emplace(1, TInContainer()); - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - - auto indices = TMemoryTracker::Instance()->GetMetricIndices(); - for (auto& [name, index] : indices) { - Cerr << "---- " << name - << ": memory = " << metrics[index].GetMemory() - << ", count = " << metrics[index].GetCount() << Endl; - } - - auto vecTIndex = FindLabelIndex(TypeName<TInContainer>().c_str()); - UNIT_ASSERT(metrics[vecTIndex].GetMemory() >= ssize_t(sizeof(TInContainer) * 5)); - UNIT_ASSERT(metrics[vecTIndex].GetCount() == 1); - - auto labelIndex = FindLabelIndex(InContainerLabel); - UNIT_ASSERT(metrics[labelIndex].GetCount() == 5); - UNIT_ASSERT(metrics[labelIndex].GetMemory() >= ssize_t( - sizeof(TInContainer) * 7 + - sizeof(decltype(mapN)::value_type) + - sizeof(decltype(umapN)::value_type) * 2)); -} - - -static constexpr char InThreadLabel[] = "InThreadLabel"; - -struct TInThread - : public NActors::NMemory::TTrack<TInThread, InThreadLabel> -{ - char payload[16]; -}; - -void* ThreadProc(void*) { - return new TInThread; -} - -Y_UNIT_TEST(Threads) { - TMemoryTracker::Instance()->Initialize(); - - auto index = FindLabelIndex(InThreadLabel); - - auto* object1 = new TInThread; - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); - UNIT_ASSERT(metrics[index].GetCount() == 1); - - TThread thread(&ThreadProc, nullptr); - thread.Start(); - auto* object2 = static_cast<TInThread*>(thread.Join()); - - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread) * 2); - UNIT_ASSERT(metrics[index].GetCount() == 2); - - delete object2; - - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); - UNIT_ASSERT(metrics[index].GetCount() == 1); - - delete object1; -} - - -struct TNotTracked { - char payload[16]; -}; - -struct TTracked - : public NActors::NMemory::TTrack<TTracked> -{ - char payload[16]; -}; - -template <typename T> -double MeasureAllocations() { - constexpr size_t objectsCount = 4 << 20; - - std::vector<T*> objects; - objects.resize(objectsCount); - - THPTimer timer; - - for (size_t i = 0; i < objectsCount; ++i) { - objects[i] = new T; - } - - for (size_t i = 0; i < objectsCount; ++i) { - delete objects[i]; - } - - auto seconds = timer.Passed(); - Cerr << "---- objects: " << objectsCount << ", time: " << seconds << Endl; - return seconds; -} - -Y_UNIT_TEST(Performance) { - TMemoryTracker::Instance()->Initialize(); - - constexpr size_t Runs = 16; - - Cerr << "---- warmup" << Endl; - MeasureAllocations<TNotTracked>(); - MeasureAllocations<TTracked>(); - - std::vector<double> noTrack; - std::vector<double> track; - - for (size_t run = 0; run < Runs; ++run) { - Cerr << "---- no track" << Endl; - auto time = MeasureAllocations<TNotTracked>(); - noTrack.push_back(time); - - Cerr << "---- track" << Endl; - time = MeasureAllocations<TTracked>(); - track.push_back(time); - } - - double meanNoTrack = 0, stddevNoTrack = 0; - double meanTrack = 0, stddevTrack = 0; - for (size_t i = 0; i < Runs; ++i) { - meanNoTrack += noTrack[i]; - meanTrack += track[i]; - } - meanNoTrack /= Runs; - meanTrack /= Runs; - - auto sqr = [](double val) { return val * val; }; - - for (size_t i = 0; i < Runs; ++i) { - stddevNoTrack += sqr(noTrack[i] - meanNoTrack); - stddevTrack += sqr(track[i] - meanTrack); - } - stddevNoTrack = sqrt(stddevNoTrack / (Runs - 1)); - stddevTrack = sqrt(stddevTrack / (Runs - 1)); - - Cerr << "---- no track - mean: " << meanNoTrack << ", stddev: " << stddevNoTrack << Endl; - Cerr << "---- track - mean: " << meanTrack << ", stddev: " << stddevTrack << Endl; - Cerr << "---- tracking is slower by " << int((meanTrack / meanNoTrack - 1.0) * 100) << "%" << Endl; -} - -#endif - -} - -} -} +#include "memory_tracker.h" + +#include <library/cpp/testing/unittest/registar.h> + +#include <util/system/hp_timer.h> +#include <util/system/thread.h> + +namespace NActors { +namespace NMemory { + +Y_UNIT_TEST_SUITE(TMemoryTrackerTest) { + +#if defined(ENABLE_MEMORY_TRACKING) + +using namespace NPrivate; + +size_t FindLabelIndex(const char* label) { + auto indices = TMemoryTracker::Instance()->GetMetricIndices(); + auto it = indices.find(label); + UNIT_ASSERT(it != indices.end()); + return it->second; +} + + +struct TTypeLabeled + : public NActors::NMemory::TTrack<TTypeLabeled> +{ + char payload[16]; +}; + +static constexpr char NamedLabel[] = "NamedLabel"; + +struct TNameLabeled + : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> +{ + char payload[32]; +}; + +Y_UNIT_TEST(Gathering) +{ + TMemoryTracker::Instance()->Initialize(); + + auto* typed = new TTypeLabeled; + auto* typedArray = new TTypeLabeled[3]; + + auto* named = new TNameLabeled; + auto* namedArray = new TNameLabeled[5]; + NActors::NMemory::TLabel<NamedLabel>::Add(100); + + std::vector<TMetric> metrics; + TMemoryTracker::Instance()->GatherMetrics(metrics); + + auto typeIndex = FindLabelIndex(TypeName<TTypeLabeled>().c_str()); + UNIT_ASSERT(typeIndex < metrics.size()); + UNIT_ASSERT(metrics[typeIndex].GetMemory() == sizeof(TTypeLabeled) * 4 + sizeof(size_t)); + UNIT_ASSERT(metrics[typeIndex].GetCount() == 2); + + auto nameIndex = FindLabelIndex(NamedLabel); + UNIT_ASSERT(nameIndex < metrics.size()); + UNIT_ASSERT(metrics[nameIndex].GetMemory() == sizeof(TNameLabeled) * 6 + sizeof(size_t) + 100); + UNIT_ASSERT(metrics[nameIndex].GetCount() == 3); + + NActors::NMemory::TLabel<NamedLabel>::Sub(100); + delete [] namedArray; + delete named; + + delete [] typedArray; + delete typed; + + TMemoryTracker::Instance()->GatherMetrics(metrics); + + UNIT_ASSERT(metrics[typeIndex].GetMemory() == 0); + UNIT_ASSERT(metrics[typeIndex].GetCount() == 0); + + UNIT_ASSERT(metrics[nameIndex].GetMemory() == 0); + UNIT_ASSERT(metrics[nameIndex].GetCount() == 0); +} + + +static constexpr char InContainerLabel[] = "InContainerLabel"; + +struct TInContainer { + char payload[16]; +}; + +Y_UNIT_TEST(Containers) { + TMemoryTracker::Instance()->Initialize(); + + std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; + vecT.resize(5); + + std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; + vecN.resize(7); + + using TKey = int; + + std::map<TKey, TInContainer, std::less<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; + mapT.emplace(0, TInContainer()); + mapT.emplace(1, TInContainer()); + + std::map<TKey, TInContainer, std::less<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; + mapN.emplace(0, TInContainer()); + + std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; + umapT.emplace(0, TInContainer()); + + std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, + NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; + umapN.emplace(0, TInContainer()); + umapN.emplace(1, TInContainer()); + + std::vector<TMetric> metrics; + TMemoryTracker::Instance()->GatherMetrics(metrics); + + auto indices = TMemoryTracker::Instance()->GetMetricIndices(); + for (auto& [name, index] : indices) { + Cerr << "---- " << name + << ": memory = " << metrics[index].GetMemory() + << ", count = " << metrics[index].GetCount() << Endl; + } + + auto vecTIndex = FindLabelIndex(TypeName<TInContainer>().c_str()); + UNIT_ASSERT(metrics[vecTIndex].GetMemory() >= ssize_t(sizeof(TInContainer) * 5)); + UNIT_ASSERT(metrics[vecTIndex].GetCount() == 1); + + auto labelIndex = FindLabelIndex(InContainerLabel); + UNIT_ASSERT(metrics[labelIndex].GetCount() == 5); + UNIT_ASSERT(metrics[labelIndex].GetMemory() >= ssize_t( + sizeof(TInContainer) * 7 + + sizeof(decltype(mapN)::value_type) + + sizeof(decltype(umapN)::value_type) * 2)); +} + + +static constexpr char InThreadLabel[] = "InThreadLabel"; + +struct TInThread + : public NActors::NMemory::TTrack<TInThread, InThreadLabel> +{ + char payload[16]; +}; + +void* ThreadProc(void*) { + return new TInThread; +} + +Y_UNIT_TEST(Threads) { + TMemoryTracker::Instance()->Initialize(); + + auto index = FindLabelIndex(InThreadLabel); + + auto* object1 = new TInThread; + + std::vector<TMetric> metrics; + TMemoryTracker::Instance()->GatherMetrics(metrics); + UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); + UNIT_ASSERT(metrics[index].GetCount() == 1); + + TThread thread(&ThreadProc, nullptr); + thread.Start(); + auto* object2 = static_cast<TInThread*>(thread.Join()); + + TMemoryTracker::Instance()->GatherMetrics(metrics); + UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread) * 2); + UNIT_ASSERT(metrics[index].GetCount() == 2); + + delete object2; + + TMemoryTracker::Instance()->GatherMetrics(metrics); + UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); + UNIT_ASSERT(metrics[index].GetCount() == 1); + + delete object1; +} + + +struct TNotTracked { + char payload[16]; +}; + +struct TTracked + : public NActors::NMemory::TTrack<TTracked> +{ + char payload[16]; +}; + +template <typename T> +double MeasureAllocations() { + constexpr size_t objectsCount = 4 << 20; + + std::vector<T*> objects; + objects.resize(objectsCount); + + THPTimer timer; + + for (size_t i = 0; i < objectsCount; ++i) { + objects[i] = new T; + } + + for (size_t i = 0; i < objectsCount; ++i) { + delete objects[i]; + } + + auto seconds = timer.Passed(); + Cerr << "---- objects: " << objectsCount << ", time: " << seconds << Endl; + return seconds; +} + +Y_UNIT_TEST(Performance) { + TMemoryTracker::Instance()->Initialize(); + + constexpr size_t Runs = 16; + + Cerr << "---- warmup" << Endl; + MeasureAllocations<TNotTracked>(); + MeasureAllocations<TTracked>(); + + std::vector<double> noTrack; + std::vector<double> track; + + for (size_t run = 0; run < Runs; ++run) { + Cerr << "---- no track" << Endl; + auto time = MeasureAllocations<TNotTracked>(); + noTrack.push_back(time); + + Cerr << "---- track" << Endl; + time = MeasureAllocations<TTracked>(); + track.push_back(time); + } + + double meanNoTrack = 0, stddevNoTrack = 0; + double meanTrack = 0, stddevTrack = 0; + for (size_t i = 0; i < Runs; ++i) { + meanNoTrack += noTrack[i]; + meanTrack += track[i]; + } + meanNoTrack /= Runs; + meanTrack /= Runs; + + auto sqr = [](double val) { return val * val; }; + + for (size_t i = 0; i < Runs; ++i) { + stddevNoTrack += sqr(noTrack[i] - meanNoTrack); + stddevTrack += sqr(track[i] - meanTrack); + } + stddevNoTrack = sqrt(stddevNoTrack / (Runs - 1)); + stddevTrack = sqrt(stddevTrack / (Runs - 1)); + + Cerr << "---- no track - mean: " << meanNoTrack << ", stddev: " << stddevNoTrack << Endl; + Cerr << "---- track - mean: " << meanTrack << ", stddev: " << stddevTrack << Endl; + Cerr << "---- tracking is slower by " << int((meanTrack / meanNoTrack - 1.0) * 100) << "%" << Endl; +} + +#endif + +} + +} +} diff --git a/library/cpp/actors/core/mon_stats.h b/library/cpp/actors/core/mon_stats.h index e58429ad0a..d55552af0c 100644 --- a/library/cpp/actors/core/mon_stats.h +++ b/library/cpp/actors/core/mon_stats.h @@ -2,13 +2,13 @@ #include "defs.h" #include "actor.h" -#include <library/cpp/monlib/metrics/histogram_snapshot.h> +#include <library/cpp/monlib/metrics/histogram_snapshot.h> #include <util/system/hp_timer.h> namespace NActors { - struct TLogHistogram : public NMonitoring::IHistogramSnapshot { + struct TLogHistogram : public NMonitoring::IHistogramSnapshot { TLogHistogram() { - memset(Buckets, 0, sizeof(Buckets)); + memset(Buckets, 0, sizeof(Buckets)); } inline void Add(ui64 val, ui64 inc = 1) { @@ -17,8 +17,8 @@ namespace NActors { asm volatile("" :: : "memory"); #endif - if (val > 1) { - ind = GetValueBitCount(val - 1); + if (val > 1) { + ind = GetValueBitCount(val - 1); } #if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 7 asm volatile("" :: @@ -36,25 +36,25 @@ namespace NActors { } } - // IHistogramSnapshot - ui32 Count() const override { - return Y_ARRAY_SIZE(Buckets); - } - - NMonitoring::TBucketBound UpperBound(ui32 index) const override { - Y_ASSERT(index < Y_ARRAY_SIZE(Buckets)); - if (index == 0) { - return 1; - } - return NMonitoring::TBucketBound(1ull << (index - 1)) * 2.0; - } - - NMonitoring::TBucketValue Value(ui32 index) const override { - Y_ASSERT(index < Y_ARRAY_SIZE(Buckets)); - return Buckets[index]; - } - - ui64 TotalSamples = 0; + // IHistogramSnapshot + ui32 Count() const override { + return Y_ARRAY_SIZE(Buckets); + } + + NMonitoring::TBucketBound UpperBound(ui32 index) const override { + Y_ASSERT(index < Y_ARRAY_SIZE(Buckets)); + if (index == 0) { + return 1; + } + return NMonitoring::TBucketBound(1ull << (index - 1)) * 2.0; + } + + NMonitoring::TBucketValue Value(ui32 index) const override { + Y_ASSERT(index < Y_ARRAY_SIZE(Buckets)); + return Buckets[index]; + } + + ui64 TotalSamples = 0; ui64 Buckets[65]; }; diff --git a/library/cpp/actors/core/process_stats.cpp b/library/cpp/actors/core/process_stats.cpp index 2cc73216b4..0e1dbd0031 100644 --- a/library/cpp/actors/core/process_stats.cpp +++ b/library/cpp/actors/core/process_stats.cpp @@ -181,9 +181,9 @@ namespace { class TDynamicCounterCollector: public TProcStatCollectingActor<TDynamicCounterCollector> { using TBase = TProcStatCollectingActor<TDynamicCounterCollector>; public: - TDynamicCounterCollector( - ui32 intervalSeconds, - NMonitoring::TDynamicCounterPtr counters) + TDynamicCounterCollector( + ui32 intervalSeconds, + NMonitoring::TDynamicCounterPtr counters) : TBase{TDuration::Seconds(intervalSeconds)} { ProcStatGroup = counters->GetSubgroup("counters", "utils"); @@ -218,7 +218,7 @@ namespace { } private: - NMonitoring::TDynamicCounterPtr ProcStatGroup; + NMonitoring::TDynamicCounterPtr ProcStatGroup; NMonitoring::TDynamicCounters::TCounterPtr VmSize; NMonitoring::TDynamicCounters::TCounterPtr AnonRssSize; NMonitoring::TDynamicCounters::TCounterPtr FileRssSize; @@ -293,8 +293,8 @@ namespace { }; } // namespace - IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters) { - return new TDynamicCounterCollector(intervalSec, counters); + IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters) { + return new TDynamicCounterCollector(intervalSec, counters); } IActor* CreateProcStatCollector(TDuration interval, NMonitoring::TMetricRegistry& registry) { diff --git a/library/cpp/actors/core/process_stats.h b/library/cpp/actors/core/process_stats.h index 236ea829ee..66346d0b5a 100644 --- a/library/cpp/actors/core/process_stats.h +++ b/library/cpp/actors/core/process_stats.h @@ -61,6 +61,6 @@ namespace NActors { long ObtainPageSize(); }; - IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters); + IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters); IActor* CreateProcStatCollector(TDuration interval, NMonitoring::TMetricRegistry& registry); } diff --git a/library/cpp/actors/core/scheduler_queue.h b/library/cpp/actors/core/scheduler_queue.h index 000321e7d3..3b8fac28f0 100644 --- a/library/cpp/actors/core/scheduler_queue.h +++ b/library/cpp/actors/core/scheduler_queue.h @@ -13,7 +13,7 @@ namespace NActors { ISchedulerCookie* Cookie; }; - struct TChunk : TQueueChunkDerived<TEntry, 512, TChunk> {}; + struct TChunk : TQueueChunkDerived<TEntry, 512, TChunk> {}; class TReader; class TWriter; diff --git a/library/cpp/actors/core/ut/ya.make b/library/cpp/actors/core/ut/ya.make index fc3195905b..3ee28d5850 100644 --- a/library/cpp/actors/core/ut/ya.make +++ b/library/cpp/actors/core/ut/ya.make @@ -39,7 +39,7 @@ SRCS( executor_pool_basic_ut.cpp executor_pool_united_ut.cpp log_ut.cpp - memory_tracker_ut.cpp + memory_tracker_ut.cpp scheduler_actor_ut.cpp ) diff --git a/library/cpp/actors/core/ya.make b/library/cpp/actors/core/ya.make index 633de9edc1..880a9d00db 100644 --- a/library/cpp/actors/core/ya.make +++ b/library/cpp/actors/core/ya.make @@ -75,10 +75,10 @@ SRCS( mailbox.h mailbox_queue_revolving.h mailbox_queue_simple.h - memory_track.cpp - memory_track.h - memory_tracker.cpp - memory_tracker.h + memory_track.cpp + memory_track.h + memory_tracker.cpp + memory_tracker.h mon.h mon_stats.h monotonic.cpp diff --git a/library/cpp/actors/helpers/mon_histogram_helper.h b/library/cpp/actors/helpers/mon_histogram_helper.h index 1da0eec1db..a9a57e3823 100644 --- a/library/cpp/actors/helpers/mon_histogram_helper.h +++ b/library/cpp/actors/helpers/mon_histogram_helper.h @@ -16,9 +16,9 @@ namespace NActors { THistogramCounterHelper(const THistogramCounterHelper&) = default; - void Init(NMonitoring::TDynamicCounters* group, const TString& baseName, const TString& unit, - ui64 firstBucket, ui64 bucketCnt, bool useSensorLabelName = true) - { + void Init(NMonitoring::TDynamicCounters* group, const TString& baseName, const TString& unit, + ui64 firstBucket, ui64 bucketCnt, bool useSensorLabelName = true) + { Y_ASSERT(FirstBucketVal == 0); Y_ASSERT(BucketCount == 0); @@ -28,8 +28,8 @@ namespace NActors { Buckets.reserve(BucketCount); for (size_t i = 0; i < BucketCount; ++i) { TString bucketName = GetBucketName(i) + " " + unit; - auto labelName = useSensorLabelName ? "sensor" : "name"; - BucketsHolder.push_back(group->GetSubgroup(labelName, baseName)->GetNamedCounter("range", bucketName, true)); + auto labelName = useSensorLabelName ? "sensor" : "name"; + BucketsHolder.push_back(group->GetSubgroup(labelName, baseName)->GetNamedCounter("range", bucketName, true)); Buckets.push_back(BucketsHolder.back().Get()); } } @@ -48,20 +48,20 @@ namespace NActors { Buckets[ind]->Inc(); } - ui64 GetBucketCount() const { - return BucketCount; - } - - ui64 GetBucketValue(size_t index) const { - Y_ASSERT(index < BucketCount); - return Buckets[index]->Val(); - } - - void SetBucketValue(ui64 index, ui64 value) { - Y_ASSERT(index < BucketCount); - *Buckets[index] = value; - } - + ui64 GetBucketCount() const { + return BucketCount; + } + + ui64 GetBucketValue(size_t index) const { + Y_ASSERT(index < BucketCount); + return Buckets[index]->Val(); + } + + void SetBucketValue(ui64 index, ui64 value) { + Y_ASSERT(index < BucketCount); + *Buckets[index] = value; + } + private: TString GetBucketName(size_t ind) const { Y_ASSERT(FirstBucketVal != 0); diff --git a/library/cpp/actors/interconnect/interconnect_counters.cpp b/library/cpp/actors/interconnect/interconnect_counters.cpp index e4b1412f62..224160d4b4 100644 --- a/library/cpp/actors/interconnect/interconnect_counters.cpp +++ b/library/cpp/actors/interconnect/interconnect_counters.cpp @@ -278,11 +278,11 @@ namespace { InflyLimitReach = AdaptiveCounters->GetCounter("InflyLimitReach", true); InflightDataAmount = AdaptiveCounters->GetCounter("Inflight_Data"); - LegacyPingTimeHist = {}; - LegacyPingTimeHist.Init(AdaptiveCounters.Get(), "PingTimeHist", "mks", 125, 18); - - PingTimeHistogram = AdaptiveCounters->GetHistogram( - "PingTimeUs", NMonitoring::ExponentialHistogram(18, 2, 125)); + LegacyPingTimeHist = {}; + LegacyPingTimeHist.Init(AdaptiveCounters.Get(), "PingTimeHist", "mks", 125, 18); + + PingTimeHistogram = AdaptiveCounters->GetHistogram( + "PingTimeUs", NMonitoring::ExponentialHistogram(18, 2, 125)); } if (updateGlobal) { @@ -299,7 +299,7 @@ namespace { auto disconnectReasonGroup = Counters->GetSubgroup("subsystem", "disconnectReason"); for (const char *reason : TDisconnectReason::Reasons) { - DisconnectByReason[reason] = disconnectReasonGroup->GetCounter(reason, true); + DisconnectByReason[reason] = disconnectReasonGroup->GetCounter(reason, true); } } @@ -329,9 +329,9 @@ namespace { NMonitoring::TDynamicCounters::TCounterPtr SpuriousReadWakeups; NMonitoring::TDynamicCounters::TCounterPtr UsefulWriteWakeups; NMonitoring::TDynamicCounters::TCounterPtr SpuriousWriteWakeups; - NMon::THistogramCounterHelper LegacyPingTimeHist; - NMonitoring::THistogramPtr PingTimeHistogram; - + NMon::THistogramCounterHelper LegacyPingTimeHist; + NMonitoring::THistogramPtr PingTimeHistogram; + std::unordered_map<ui16, TOutputChannel> OutputChannels; TOutputChannel OtherOutputChannel; TInputChannels InputChannels; diff --git a/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp index 16f0223502..0abe9fe659 100644 --- a/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp +++ b/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp @@ -196,7 +196,7 @@ namespace NActors { if (AtomicGet(Context->ControlPacketId) <= HeaderConfirm && !NewPingProtocol) { ui64 sendTime = AtomicGet(Context->ControlPacketSendTimer); TDuration duration = CyclesToDuration(GetCycleCountFast() - sendTime); - const auto durationUs = duration.MicroSeconds(); + const auto durationUs = duration.MicroSeconds(); Metrics->UpdateLegacyPingTimeHist(durationUs); PingQ.push_back(duration); if (PingQ.size() > 16) { @@ -448,8 +448,8 @@ namespace NActors { PingQ.pop_front(); } const TDuration ping = *std::min_element(PingQ.begin(), PingQ.end()); - const auto pingUs = ping.MicroSeconds(); - Context->PingRTT_us = pingUs; + const auto pingUs = ping.MicroSeconds(); + Context->PingRTT_us = pingUs; NewPingProtocol = true; Metrics->UpdateLegacyPingTimeHist(pingUs); } diff --git a/library/cpp/actors/prof/tag.cpp b/library/cpp/actors/prof/tag.cpp index caf516812b..9ccf03e1a9 100644 --- a/library/cpp/actors/prof/tag.cpp +++ b/library/cpp/actors/prof/tag.cpp @@ -1,9 +1,9 @@ #include "tag.h" -#include "tcmalloc.h" +#include "tcmalloc.h" #include <library/cpp/charset/ci_string.h> #include <library/cpp/containers/atomizer/atomizer.h> -#include <library/cpp/malloc/api/malloc.h> +#include <library/cpp/malloc/api/malloc.h> #if defined(PROFILE_MEMORY_ALLOCATIONS) #include <library/cpp/lfalloc/dbg_info/dbg_info.h> @@ -76,11 +76,11 @@ namespace NProfiling { return TStringAtoms::Instance().GetTagsCount(); } - static ui32 SetThreadAllocTag_Default(ui32 tag) { - Y_UNUSED(tag); - return 0; - } - + static ui32 SetThreadAllocTag_Default(ui32 tag) { + Y_UNUSED(tag); + return 0; + } + #if defined(PROFILE_MEMORY_ALLOCATIONS) static ui32 SetThreadAllocTag_YT(ui32 tag) { auto prev = NYT::NYTAlloc::GetCurrentMemoryTag(); @@ -96,24 +96,24 @@ namespace NProfiling { return (TSetThreadAllocTag*)NAllocDbg::SetThreadAllocTag; } else if (name.StartsWith("yt")) { return SetThreadAllocTag_YT; - } else if (name.StartsWith("tc")) { - return SetTCMallocThreadAllocTag; + } else if (name.StartsWith("tc")) { + return SetTCMallocThreadAllocTag; + } else { + return SetThreadAllocTag_Default; + } + } +#else + static TSetThreadAllocTag* SetThreadAllocTagFn() { + const auto& info = NMalloc::MallocInfo(); + + TStringBuf name(info.Name); + if (name.StartsWith("tc")) { + return SetTCMallocThreadAllocTag; } else { return SetThreadAllocTag_Default; } } -#else - static TSetThreadAllocTag* SetThreadAllocTagFn() { - const auto& info = NMalloc::MallocInfo(); - - TStringBuf name(info.Name); - if (name.StartsWith("tc")) { - return SetTCMallocThreadAllocTag; - } else { - return SetThreadAllocTag_Default; - } - } -#endif - +#endif + TSetThreadAllocTag* SetThreadAllocTag = SetThreadAllocTagFn(); } diff --git a/library/cpp/actors/prof/tag.h b/library/cpp/actors/prof/tag.h index 81815b7289..357e264a22 100644 --- a/library/cpp/actors/prof/tag.h +++ b/library/cpp/actors/prof/tag.h @@ -5,7 +5,7 @@ /* Common registry for tagging memory profiler. Register a new tag with MakeTag using a unique string. - Use registered tags with SetThreadAllocTag function in allocator API. + Use registered tags with SetThreadAllocTag function in allocator API. */ namespace NProfiling { @@ -22,43 +22,43 @@ namespace NProfiling { class TMemoryTagScope { public: - explicit TMemoryTagScope(ui32 tag) + explicit TMemoryTagScope(ui32 tag) : RestoreTag(SetThreadAllocTag(tag)) { } - explicit TMemoryTagScope(const char* tagName) { + explicit TMemoryTagScope(const char* tagName) { ui32 newTag = MakeTag(tagName); RestoreTag = SetThreadAllocTag(newTag); } TMemoryTagScope(TMemoryTagScope&& move) : RestoreTag(move.RestoreTag) - , Released(move.Released) + , Released(move.Released) { - move.Released = true; + move.Released = true; } TMemoryTagScope& operator=(TMemoryTagScope&& move) { RestoreTag = move.RestoreTag; - Released = move.Released; - move.Released = true; + Released = move.Released; + move.Released = true; return *this; } - static void Reset(ui32 tag) { + static void Reset(ui32 tag) { SetThreadAllocTag(tag); } void Release() { - if (!Released) { + if (!Released) { SetThreadAllocTag(RestoreTag); - Released = true; + Released = true; } } ~TMemoryTagScope() { - if (!Released) { + if (!Released) { SetThreadAllocTag(RestoreTag); } } @@ -67,7 +67,7 @@ namespace NProfiling { TMemoryTagScope(const TMemoryTagScope&) = delete; void operator=(const TMemoryTagScope&) = delete; - ui32 RestoreTag = 0; - bool Released = false; + ui32 RestoreTag = 0; + bool Released = false; }; } diff --git a/library/cpp/actors/prof/tcmalloc.cpp b/library/cpp/actors/prof/tcmalloc.cpp index 331181e80b..3d4f203dbb 100644 --- a/library/cpp/actors/prof/tcmalloc.cpp +++ b/library/cpp/actors/prof/tcmalloc.cpp @@ -1,32 +1,32 @@ -#include "tcmalloc.h" - -#include <contrib/libs/tcmalloc/tcmalloc/malloc_extension.h> - -namespace NProfiling { - -static thread_local ui32 AllocationTag = 0; - -static struct TInitTCMallocCallbacks { - static void* CreateTag() { - return reinterpret_cast<void*>(AllocationTag); - } - static void* CopyTag(void* tag) { - return tag; - } - static void DestroyTag(void* tag) { - Y_UNUSED(tag); - } - - TInitTCMallocCallbacks() { - tcmalloc::MallocExtension::SetSampleUserDataCallbacks( - CreateTag, CopyTag, DestroyTag); - } -} InitTCMallocCallbacks; - -ui32 SetTCMallocThreadAllocTag(ui32 tag) { - ui32 prev = AllocationTag; - AllocationTag = tag; - return prev; -} - -} +#include "tcmalloc.h" + +#include <contrib/libs/tcmalloc/tcmalloc/malloc_extension.h> + +namespace NProfiling { + +static thread_local ui32 AllocationTag = 0; + +static struct TInitTCMallocCallbacks { + static void* CreateTag() { + return reinterpret_cast<void*>(AllocationTag); + } + static void* CopyTag(void* tag) { + return tag; + } + static void DestroyTag(void* tag) { + Y_UNUSED(tag); + } + + TInitTCMallocCallbacks() { + tcmalloc::MallocExtension::SetSampleUserDataCallbacks( + CreateTag, CopyTag, DestroyTag); + } +} InitTCMallocCallbacks; + +ui32 SetTCMallocThreadAllocTag(ui32 tag) { + ui32 prev = AllocationTag; + AllocationTag = tag; + return prev; +} + +} diff --git a/library/cpp/actors/prof/tcmalloc.h b/library/cpp/actors/prof/tcmalloc.h index 0da31a2024..659fb4eaf3 100644 --- a/library/cpp/actors/prof/tcmalloc.h +++ b/library/cpp/actors/prof/tcmalloc.h @@ -1,9 +1,9 @@ -#pragma once - -#include <util/generic/fwd.h> - -namespace NProfiling { - -ui32 SetTCMallocThreadAllocTag(ui32 tag); - -} +#pragma once + +#include <util/generic/fwd.h> + +namespace NProfiling { + +ui32 SetTCMallocThreadAllocTag(ui32 tag); + +} diff --git a/library/cpp/actors/prof/tcmalloc_null.cpp b/library/cpp/actors/prof/tcmalloc_null.cpp index 26e6f61bb9..75c0013154 100644 --- a/library/cpp/actors/prof/tcmalloc_null.cpp +++ b/library/cpp/actors/prof/tcmalloc_null.cpp @@ -1,10 +1,10 @@ -#include "tcmalloc.h" - -namespace NProfiling { - -ui32 SetTCMallocThreadAllocTag(ui32 tag) { - Y_UNUSED(tag); - return 0; -} - -} +#include "tcmalloc.h" + +namespace NProfiling { + +ui32 SetTCMallocThreadAllocTag(ui32 tag) { + Y_UNUSED(tag); + return 0; +} + +} diff --git a/library/cpp/actors/prof/ya.make b/library/cpp/actors/prof/ya.make index d20ee798c4..b5e2497563 100644 --- a/library/cpp/actors/prof/ya.make +++ b/library/cpp/actors/prof/ya.make @@ -23,11 +23,11 @@ IF (PROFILE_MEMORY_ALLOCATIONS) ) ENDIF() -IF(ALLOCATOR == "TCMALLOC_256K") - SRCS(tcmalloc.cpp) - PEERDIR(contrib/libs/tcmalloc) -ELSE() - SRCS(tcmalloc_null.cpp) -ENDIF() - +IF(ALLOCATOR == "TCMALLOC_256K") + SRCS(tcmalloc.cpp) + PEERDIR(contrib/libs/tcmalloc) +ELSE() + SRCS(tcmalloc_null.cpp) +ENDIF() + END() |