diff options
author | vskipin <vskipin@yandex-team.ru> | 2022-02-10 16:46:00 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:46:00 +0300 |
commit | 4e4b78bd7b67e2533da4dbb9696374a6d6068e32 (patch) | |
tree | a7a5543d815c451256ece74081d960b4e1d70ec2 /library/cpp/lfalloc/alloc_profiler/stackcollect.cpp | |
parent | 5b00ed04a5137a452fa6d3423cb0c9b54ac27408 (diff) | |
download | ydb-4e4b78bd7b67e2533da4dbb9696374a6d6068e32.tar.gz |
Restoring authorship annotation for <vskipin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/lfalloc/alloc_profiler/stackcollect.cpp')
-rw-r--r-- | library/cpp/lfalloc/alloc_profiler/stackcollect.cpp | 504 |
1 files changed, 252 insertions, 252 deletions
diff --git a/library/cpp/lfalloc/alloc_profiler/stackcollect.cpp b/library/cpp/lfalloc/alloc_profiler/stackcollect.cpp index fded4e2fd1..5a0c920451 100644 --- a/library/cpp/lfalloc/alloc_profiler/stackcollect.cpp +++ b/library/cpp/lfalloc/alloc_profiler/stackcollect.cpp @@ -1,278 +1,278 @@ -#include "stackcollect.h" +#include "stackcollect.h" -#include "profiler.h" - -#include <util/generic/algorithm.h> -#include <util/generic/vector.h> -#include <util/stream/format.h> +#include "profiler.h" + +#include <util/generic/algorithm.h> +#include <util/generic/vector.h> +#include <util/stream/format.h> #include <util/stream/str.h> #include <util/string/cast.h> #include <util/string/printf.h> -#include <util/system/backtrace.h> -#include <util/system/spinlock.h> -#include <util/system/yassert.h> - - +#include <util/system/backtrace.h> +#include <util/system/spinlock.h> +#include <util/system/yassert.h> + + namespace NAllocProfiler { -//////////////////////////////////////////////////////////////////////////////// - -template <typename T> -class TStackCollector: private TNonCopyable { -public: - struct TFrameInfo { - int PrevInd; - void* Addr; - int Tag; - T Stats; - - void Clear() - { - PrevInd = 0; - Addr = nullptr; - Tag = 0; - Stats.Clear(); - } - }; - -private: - static const size_t STACKS_HASH_MAP_SIZE = 256 * 1024; - TFrameInfo Frames[STACKS_HASH_MAP_SIZE]; - - ui64 Samples; // Saved samples count - ui64 UniqueSamples; // Number of unique addresses - ui64 UsedSlots; // Number of occupied slots in the hashtable - ui64 DroppedSamples; // Number of unsaved addresses - ui64 SearchSkipCount; // Total number of linear hash table probes due to collisions - - TAdaptiveLock Lock; - -public: - TStackCollector() - { - Clear(); - } - - int AddStack(void** stack, size_t frameCount, int tag) - { - Y_ASSERT(frameCount > 0); - - int prevInd = -1; - with_lock (Lock) { - for (int i = frameCount - 1; i >= 0; --i) { - prevInd = AddFrame(stack[i], prevInd, ((i == 0) ? tag : 0), (i == 0)); - if (prevInd == -1) { - break; - } - } - } - return prevInd; - } - - T& GetStats(int stackId) - { - Y_ASSERT(stackId >= 0 && (size_t)stackId < Y_ARRAY_SIZE(Frames)); - Y_ASSERT(!IsSlotEmpty(stackId)); - - return Frames[stackId].Stats; - } - - const TFrameInfo* GetFrames() const - { - return Frames; - } - - size_t GetFramesCount() const - { - return Y_ARRAY_SIZE(Frames); - } - +//////////////////////////////////////////////////////////////////////////////// + +template <typename T> +class TStackCollector: private TNonCopyable { +public: + struct TFrameInfo { + int PrevInd; + void* Addr; + int Tag; + T Stats; + + void Clear() + { + PrevInd = 0; + Addr = nullptr; + Tag = 0; + Stats.Clear(); + } + }; + +private: + static const size_t STACKS_HASH_MAP_SIZE = 256 * 1024; + TFrameInfo Frames[STACKS_HASH_MAP_SIZE]; + + ui64 Samples; // Saved samples count + ui64 UniqueSamples; // Number of unique addresses + ui64 UsedSlots; // Number of occupied slots in the hashtable + ui64 DroppedSamples; // Number of unsaved addresses + ui64 SearchSkipCount; // Total number of linear hash table probes due to collisions + + TAdaptiveLock Lock; + +public: + TStackCollector() + { + Clear(); + } + + int AddStack(void** stack, size_t frameCount, int tag) + { + Y_ASSERT(frameCount > 0); + + int prevInd = -1; + with_lock (Lock) { + for (int i = frameCount - 1; i >= 0; --i) { + prevInd = AddFrame(stack[i], prevInd, ((i == 0) ? tag : 0), (i == 0)); + if (prevInd == -1) { + break; + } + } + } + return prevInd; + } + + T& GetStats(int stackId) + { + Y_ASSERT(stackId >= 0 && (size_t)stackId < Y_ARRAY_SIZE(Frames)); + Y_ASSERT(!IsSlotEmpty(stackId)); + + return Frames[stackId].Stats; + } + + const TFrameInfo* GetFrames() const + { + return Frames; + } + + size_t GetFramesCount() const + { + return Y_ARRAY_SIZE(Frames); + } + void BackTrace(const TFrameInfo* stack, TStackVec<void*, 64>& frames) const - { + { frames.clear(); - for (size_t i = 0; i < 100; ++i) { + for (size_t i = 0; i < 100; ++i) { frames.push_back(stack->Addr); - int prevInd = stack->PrevInd; - if (prevInd == -1) { - break; - } - stack = &Frames[prevInd]; - } - } - - void Clear() - { - for (auto& frame: Frames) { - frame.Clear(); - } - - Samples = 0; - DroppedSamples = 0; - UniqueSamples = 0; - UsedSlots = 0; - SearchSkipCount = 0; - } - -private: - // Hash function applied to the addresses - static ui32 Hash(void* addr, int prevInd, int tag) - { - return (((size_t)addr + ((size_t)addr / STACKS_HASH_MAP_SIZE)) + prevInd + tag) % STACKS_HASH_MAP_SIZE; - } - - static bool EqualFrame(const TFrameInfo& frame, void* addr, int prevInd, int tag) - { - return (frame.Addr == addr && frame.PrevInd == prevInd && frame.Tag == tag); - } - - bool IsSlotEmpty(ui32 slot) const - { - return Frames[slot].Addr == 0; - } - - bool InsertsAllowed() const - { - return UsedSlots < STACKS_HASH_MAP_SIZE / 2; - } - - // returns the index in the hashmap - int AddFrame(void* addr, int prevFrameIndex, int tag, bool last) - { - ui32 slot = Hash(addr, prevFrameIndex, tag); - ui32 prevSlot = (slot - 1) % STACKS_HASH_MAP_SIZE; - - while (!EqualFrame(Frames[slot], addr, prevFrameIndex, tag) && !IsSlotEmpty(slot) && slot != prevSlot) { - slot = (slot + 1) % STACKS_HASH_MAP_SIZE; - SearchSkipCount++; - } - - if (EqualFrame(Frames[slot], addr, prevFrameIndex, tag)) { - if (last) { - ++Samples; - } - } else if (InsertsAllowed() && IsSlotEmpty(slot)) { - // add new sample - Frames[slot].Clear(); - Frames[slot].Addr = addr; - Frames[slot].PrevInd = prevFrameIndex; - Frames[slot].Tag = tag; - ++UsedSlots; - if (last) { - ++UniqueSamples; - ++Samples; - } - } else { - // don't insert new sample if the search is becoming too slow - ++DroppedSamples; - return -1; - } - - return slot; - } -}; - - -//////////////////////////////////////////////////////////////////////////////// - + int prevInd = stack->PrevInd; + if (prevInd == -1) { + break; + } + stack = &Frames[prevInd]; + } + } + + void Clear() + { + for (auto& frame: Frames) { + frame.Clear(); + } + + Samples = 0; + DroppedSamples = 0; + UniqueSamples = 0; + UsedSlots = 0; + SearchSkipCount = 0; + } + +private: + // Hash function applied to the addresses + static ui32 Hash(void* addr, int prevInd, int tag) + { + return (((size_t)addr + ((size_t)addr / STACKS_HASH_MAP_SIZE)) + prevInd + tag) % STACKS_HASH_MAP_SIZE; + } + + static bool EqualFrame(const TFrameInfo& frame, void* addr, int prevInd, int tag) + { + return (frame.Addr == addr && frame.PrevInd == prevInd && frame.Tag == tag); + } + + bool IsSlotEmpty(ui32 slot) const + { + return Frames[slot].Addr == 0; + } + + bool InsertsAllowed() const + { + return UsedSlots < STACKS_HASH_MAP_SIZE / 2; + } + + // returns the index in the hashmap + int AddFrame(void* addr, int prevFrameIndex, int tag, bool last) + { + ui32 slot = Hash(addr, prevFrameIndex, tag); + ui32 prevSlot = (slot - 1) % STACKS_HASH_MAP_SIZE; + + while (!EqualFrame(Frames[slot], addr, prevFrameIndex, tag) && !IsSlotEmpty(slot) && slot != prevSlot) { + slot = (slot + 1) % STACKS_HASH_MAP_SIZE; + SearchSkipCount++; + } + + if (EqualFrame(Frames[slot], addr, prevFrameIndex, tag)) { + if (last) { + ++Samples; + } + } else if (InsertsAllowed() && IsSlotEmpty(slot)) { + // add new sample + Frames[slot].Clear(); + Frames[slot].Addr = addr; + Frames[slot].PrevInd = prevFrameIndex; + Frames[slot].Tag = tag; + ++UsedSlots; + if (last) { + ++UniqueSamples; + ++Samples; + } + } else { + // don't insert new sample if the search is becoming too slow + ++DroppedSamples; + return -1; + } + + return slot; + } +}; + + +//////////////////////////////////////////////////////////////////////////////// + class TAllocationStackCollector::TImpl: public TStackCollector<TStats> { using TBase = TStackCollector<TStats>; - -private: + +private: TStats Total; - -public: - int Alloc(void** stack, size_t frameCount, int tag, size_t size) - { - int stackId = TBase::AddStack(stack, frameCount, tag); - if (stackId >= 0) { - TBase::GetStats(stackId).Alloc(size); - Total.Alloc(size); - } - return stackId; - } - - void Free(int stackId, size_t size) - { - TBase::GetStats(stackId).Free(size); - Total.Free(size); - } - - void Clear() - { - TBase::Clear(); - Total.Clear(); - } - + +public: + int Alloc(void** stack, size_t frameCount, int tag, size_t size) + { + int stackId = TBase::AddStack(stack, frameCount, tag); + if (stackId >= 0) { + TBase::GetStats(stackId).Alloc(size); + Total.Alloc(size); + } + return stackId; + } + + void Free(int stackId, size_t size) + { + TBase::GetStats(stackId).Free(size); + Total.Free(size); + } + + void Clear() + { + TBase::Clear(); + Total.Clear(); + } + void Dump(int count, IAllocationStatsDumper& out) const - { - const TFrameInfo* frames = TBase::GetFrames(); - size_t framesCount = TBase::GetFramesCount(); - + { + const TFrameInfo* frames = TBase::GetFrames(); + size_t framesCount = TBase::GetFramesCount(); + TVector<const TFrameInfo*> stacks; - for (size_t i = 0; i < framesCount; ++i) { - if (frames[i].Stats.Allocs) { - stacks.push_back(&frames[i]); - } - } - - Sort(stacks, [] (const TFrameInfo* l, const TFrameInfo* r) { - const auto& ls = l->Stats; - const auto& rs = r->Stats; - return ls.CurrentSize != rs.CurrentSize - ? ls.CurrentSize > rs.CurrentSize - : ls.Allocs != rs.Allocs - ? ls.Allocs > rs.Allocs - : ls.Frees > rs.Frees; - }); - + for (size_t i = 0; i < framesCount; ++i) { + if (frames[i].Stats.Allocs) { + stacks.push_back(&frames[i]); + } + } + + Sort(stacks, [] (const TFrameInfo* l, const TFrameInfo* r) { + const auto& ls = l->Stats; + const auto& rs = r->Stats; + return ls.CurrentSize != rs.CurrentSize + ? ls.CurrentSize > rs.CurrentSize + : ls.Allocs != rs.Allocs + ? ls.Allocs > rs.Allocs + : ls.Frees > rs.Frees; + }); + out.DumpTotal(Total); - + TAllocationInfo allocInfo; - int printedCount = 0; - for (const TFrameInfo* stack: stacks) { + int printedCount = 0; + for (const TFrameInfo* stack: stacks) { allocInfo.Clear(); allocInfo.Tag = stack->Tag; allocInfo.Stats = stack->Stats; TBase::BackTrace(stack, allocInfo.Stack); - + out.DumpEntry(allocInfo); - if (++printedCount >= count) { - break; - } - } - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -TAllocationStackCollector::TAllocationStackCollector() - : Impl(new TImpl()) -{} - -TAllocationStackCollector::~TAllocationStackCollector() -{} - -int TAllocationStackCollector::Alloc(void** stack, size_t frameCount, int tag, size_t size) -{ - return Impl->Alloc(stack, frameCount, tag, size); -} - -void TAllocationStackCollector::Free(int stackId, size_t size) -{ - Impl->Free(stackId, size); -} - -void TAllocationStackCollector::Clear() -{ - Impl->Clear(); -} - + if (++printedCount >= count) { + break; + } + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// + +TAllocationStackCollector::TAllocationStackCollector() + : Impl(new TImpl()) +{} + +TAllocationStackCollector::~TAllocationStackCollector() +{} + +int TAllocationStackCollector::Alloc(void** stack, size_t frameCount, int tag, size_t size) +{ + return Impl->Alloc(stack, frameCount, tag, size); +} + +void TAllocationStackCollector::Free(int stackId, size_t size) +{ + Impl->Free(stackId, size); +} + +void TAllocationStackCollector::Clear() +{ + Impl->Clear(); +} + void TAllocationStackCollector::Dump(int count, IAllocationStatsDumper &out) const -{ - Impl->Dump(count, out); -} - +{ + Impl->Dump(count, out); +} + TString IAllocationStatsDumper::FormatTag(int tag) { return ToString(tag); |