From c25e62b0cdbca855e7611583b0ff7013c31db21d Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Wed, 20 Mar 2013 10:11:24 +0000 Subject: [ASan] Move malloc stats collection away from AsanThreadRegistry class. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@177508 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 10 ++--- lib/asan/asan_allocator2.cc | 12 +++--- lib/asan/asan_mac.cc | 10 ++--- lib/asan/asan_malloc_mac.cc | 2 +- lib/asan/asan_stats.cc | 82 ++++++++++++++++++++++++++++++++++++-- lib/asan/asan_stats.h | 13 ++++++ lib/asan/asan_thread_registry.cc | 86 ++++------------------------------------ lib/asan/asan_thread_registry.h | 21 +--------- 8 files changed, 117 insertions(+), 119 deletions(-) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 9df741fb..49c1f73e 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -427,7 +427,7 @@ class MallocInfo { free_lists_[size_class] = m; // Statistics. - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.real_frees++; thread_stats.really_freed += m->used_size; thread_stats.really_freed_redzones += m->Size() - m->used_size; @@ -454,7 +454,7 @@ class MallocInfo { u8 *mem = MmapNewPagesAndPoisonShadow(mmap_size); // Statistics. - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.mmaps++; thread_stats.mmaped += mmap_size; thread_stats.mmaped_by_size[size_class] += n_chunks; @@ -530,7 +530,7 @@ static u8 *Allocate(uptr alignment, uptr size, StackTrace *stack, } AsanThread *t = GetCurrentThread(); - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); // Statistics thread_stats.mallocs++; thread_stats.malloced += size; @@ -627,7 +627,7 @@ static void Deallocate(u8 *ptr, StackTrace *stack, AllocType alloc_type) { PoisonShadow((uptr)ptr, rounded_size, kAsanHeapFreeMagic); // Statistics. - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.frees++; thread_stats.freed += m->used_size; thread_stats.freed_by_size[m->SizeClass()]++; @@ -651,7 +651,7 @@ static u8 *Reallocate(u8 *old_ptr, uptr new_size, CHECK(old_ptr && new_size); // Statistics. - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.reallocs++; thread_stats.realloced += new_size; diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc index 77cc87bc..63076c72 100644 --- a/lib/asan/asan_allocator2.cc +++ b/lib/asan/asan_allocator2.cc @@ -34,7 +34,7 @@ struct AsanMapUnmapCallback { void OnMap(uptr p, uptr size) const { PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic); // Statistics. - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.mmaps++; thread_stats.mmaped += size; } @@ -49,7 +49,7 @@ struct AsanMapUnmapCallback { uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size); FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg); // Statistics. - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.munmaps++; thread_stats.munmaped += size; } @@ -274,7 +274,7 @@ struct QuarantineCallback { } // Statistics. - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.real_frees++; thread_stats.really_freed += m->UsedSize(); @@ -401,7 +401,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, *shadow = size & (SHADOW_GRANULARITY - 1); } - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.mallocs++; thread_stats.malloced += size; thread_stats.malloced_redzones += needed_size - size; @@ -452,7 +452,7 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) { RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), kAsanHeapFreeMagic); - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.frees++; thread_stats.freed += m->UsedSize(); @@ -476,7 +476,7 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) { uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); - AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats(); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.reallocs++; thread_stats.realloced += new_size; diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index 80dc0f6b..e88aa6a7 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -237,7 +237,7 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) { if ((max_s) > 1) { stack->max_size = max_s; if (!asan_inited) return; - if (AsanThread *t = asanThreadRegistry().GetCurrent()) + if (AsanThread *t = GetCurrentThread()) stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom()); } } @@ -291,12 +291,12 @@ typedef struct { static ALWAYS_INLINE void asan_register_worker_thread(int parent_tid, StackTrace *stack) { - AsanThread *t = asanThreadRegistry().GetCurrent(); + AsanThread *t = GetCurrentThread(); if (!t) { t = AsanThread::Create(parent_tid, 0, 0, stack); asanThreadRegistry().RegisterThread(t); t->Init(); - asanThreadRegistry().SetCurrent(t); + SetCurrentThread(t); } } @@ -330,7 +330,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); asan_ctxt->block = ctxt; asan_ctxt->func = func; - asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); + asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); return asan_ctxt; } @@ -396,7 +396,7 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); #define GET_ASAN_BLOCK(work) \ void (^asan_block)(void); \ - int parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); \ + int parent_tid = GetCurrentTidOrInvalid(); \ asan_block = ^(void) { \ GET_STACK_TRACE_THREAD; \ asan_register_worker_thread(parent_tid, &stack); \ diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc index 618dd258..eb66ddab 100644 --- a/lib/asan/asan_malloc_mac.cc +++ b/lib/asan/asan_malloc_mac.cc @@ -285,7 +285,7 @@ void mi_force_unlock(malloc_zone_t *zone) { void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) { AsanMallocStats malloc_stats; - asanThreadRegistry().FillMallocStatistics(&malloc_stats); + FillMallocStatistics(&malloc_stats); CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t)); } diff --git a/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc index ba67c820..b1fe7bc4 100644 --- a/lib/asan/asan_stats.cc +++ b/lib/asan/asan_stats.cc @@ -15,6 +15,7 @@ #include "asan_internal.h" #include "asan_stats.h" #include "asan_thread_registry.h" +#include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_stackdepot.h" namespace __asan { @@ -57,7 +58,7 @@ static BlockingMutex print_lock(LINKER_INITIALIZED); static void PrintAccumulatedStats() { AsanStats stats; - asanThreadRegistry().GetAccumulatedStats(&stats); + GetAccumulatedStats(&stats); // Use lock to keep reports from mixing up. BlockingMutexLock lock(&print_lock); stats.Print(); @@ -67,21 +68,94 @@ static void PrintAccumulatedStats() { PrintInternalAllocatorStats(); } +static AsanStats unknown_thread_stats(LINKER_INITIALIZED); +static AsanStats accumulated_stats(LINKER_INITIALIZED); +// Required for malloc_zone_statistics() on OS X. This can't be stored in +// per-thread AsanStats. +static uptr max_malloced_memory; +static BlockingMutex acc_stats_lock(LINKER_INITIALIZED); + +void FlushToAccumulatedStatsUnlocked(AsanStats *stats) { + acc_stats_lock.CheckLocked(); + uptr *dst = (uptr*)&accumulated_stats; + uptr *src = (uptr*)stats; + uptr num_fields = sizeof(*stats) / sizeof(uptr); + for (uptr i = 0; i < num_fields; i++) { + dst[i] += src[i]; + src[i] = 0; + } +} + +static void UpdateAccumulatedStatsUnlocked() { + acc_stats_lock.CheckLocked(); + asanThreadRegistry().FlushAllStats(); + FlushToAccumulatedStatsUnlocked(&unknown_thread_stats); + // This is not very accurate: we may miss allocation peaks that happen + // between two updates of accumulated_stats_. For more accurate bookkeeping + // the maximum should be updated on every malloc(), which is unacceptable. + if (max_malloced_memory < accumulated_stats.malloced) { + max_malloced_memory = accumulated_stats.malloced; + } +} + +void FlushToAccumulatedStats(AsanStats *stats) { + BlockingMutexLock lock(&acc_stats_lock); + FlushToAccumulatedStatsUnlocked(stats); +} + +void GetAccumulatedStats(AsanStats *stats) { + BlockingMutexLock lock(&acc_stats_lock); + UpdateAccumulatedStatsUnlocked(); + internal_memcpy(stats, &accumulated_stats, sizeof(accumulated_stats)); +} + +void FillMallocStatistics(AsanMallocStats *malloc_stats) { + BlockingMutexLock lock(&acc_stats_lock); + UpdateAccumulatedStatsUnlocked(); + malloc_stats->blocks_in_use = accumulated_stats.mallocs; + malloc_stats->size_in_use = accumulated_stats.malloced; + malloc_stats->max_size_in_use = max_malloced_memory; + malloc_stats->size_allocated = accumulated_stats.mmaped; +} + +AsanStats &GetCurrentThreadStats() { + AsanThread *t = GetCurrentThread(); + return (t) ? t->stats() : unknown_thread_stats; +} + } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT uptr __asan_get_current_allocated_bytes() { - return asanThreadRegistry().GetCurrentAllocatedBytes(); + BlockingMutexLock lock(&acc_stats_lock); + UpdateAccumulatedStatsUnlocked(); + uptr malloced = accumulated_stats.malloced; + uptr freed = accumulated_stats.freed; + // Return sane value if malloced < freed due to racy + // way we update accumulated stats. + return (malloced > freed) ? malloced - freed : 1; } uptr __asan_get_heap_size() { - return asanThreadRegistry().GetHeapSize(); + BlockingMutexLock lock(&acc_stats_lock); + UpdateAccumulatedStatsUnlocked(); + return accumulated_stats.mmaped - accumulated_stats.munmaped; } uptr __asan_get_free_bytes() { - return asanThreadRegistry().GetFreeBytes(); + BlockingMutexLock lock(&acc_stats_lock); + UpdateAccumulatedStatsUnlocked(); + uptr total_free = accumulated_stats.mmaped + - accumulated_stats.munmaped + + accumulated_stats.really_freed + + accumulated_stats.really_freed_redzones; + uptr total_used = accumulated_stats.malloced + + accumulated_stats.malloced_redzones; + // Return sane value if total_free < total_used due to racy + // way we update accumulated stats. + return (total_free > total_used) ? total_free - total_used : 1; } uptr __asan_get_unmapped_bytes() { diff --git a/lib/asan/asan_stats.h b/lib/asan/asan_stats.h index 37846bc9..920ac050 100644 --- a/lib/asan/asan_stats.h +++ b/lib/asan/asan_stats.h @@ -56,6 +56,17 @@ struct AsanStats { void Print(); }; +// Returns stats for GetCurrentThread(), or stats for fake "unknown thread" +// if GetCurrentThread() returns 0. +AsanStats &GetCurrentThreadStats(); +// Flushes all thread-local stats to accumulated stats, and makes +// a copy of accumulated stats. +void GetAccumulatedStats(AsanStats *stats); +// Flushes a given stats into accumulated stats. +void FlushToAccumulatedStats(AsanStats *stats); +// FIXME: Hide this method when AsanThreadRegistry is removed. +void FlushToAccumulatedStatsUnlocked(AsanStats *stats); + // A cross-platform equivalent of malloc_statistics_t on Mac OS. struct AsanMallocStats { uptr blocks_in_use; @@ -64,6 +75,8 @@ struct AsanMallocStats { uptr size_allocated; }; +void FillMallocStatistics(AsanMallocStats *malloc_stats); + } // namespace __asan #endif // ASAN_STATS_H diff --git a/lib/asan/asan_thread_registry.cc b/lib/asan/asan_thread_registry.cc index 5e875a44..82ee34dc 100644 --- a/lib/asan/asan_thread_registry.cc +++ b/lib/asan/asan_thread_registry.cc @@ -29,8 +29,6 @@ AsanThreadRegistry &asanThreadRegistry() { AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) : main_thread_(x), main_thread_summary_(x), - accumulated_stats_(x), - max_malloced_memory_(x), mu_(x) { } void AsanThreadRegistry::Init() { @@ -57,7 +55,7 @@ void AsanThreadRegistry::RegisterThread(AsanThread *thread) { void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { BlockingMutexLock lock(&mu_); - FlushToAccumulatedStatsUnlocked(&thread->stats()); + FlushToAccumulatedStats(&thread->stats()); AsanThreadSummary *summary = thread->summary(); CHECK(summary); summary->set_thread(0); @@ -67,56 +65,14 @@ AsanThread *AsanThreadRegistry::GetMain() { return &main_thread_; } -AsanStats &AsanThreadRegistry::GetCurrentThreadStats() { - AsanThread *t = GetCurrentThread(); - return (t) ? t->stats() : main_thread_.stats(); -} - -void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) { - BlockingMutexLock lock(&mu_); - UpdateAccumulatedStatsUnlocked(); - internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_)); -} - -uptr AsanThreadRegistry::GetCurrentAllocatedBytes() { - BlockingMutexLock lock(&mu_); - UpdateAccumulatedStatsUnlocked(); - uptr malloced = accumulated_stats_.malloced; - uptr freed = accumulated_stats_.freed; - // Return sane value if malloced < freed due to racy - // way we update accumulated stats. - return (malloced > freed) ? malloced - freed : 1; -} - -uptr AsanThreadRegistry::GetHeapSize() { +void AsanThreadRegistry::FlushAllStats() { BlockingMutexLock lock(&mu_); - UpdateAccumulatedStatsUnlocked(); - return accumulated_stats_.mmaped - accumulated_stats_.munmaped; -} - -uptr AsanThreadRegistry::GetFreeBytes() { - BlockingMutexLock lock(&mu_); - UpdateAccumulatedStatsUnlocked(); - uptr total_free = accumulated_stats_.mmaped - - accumulated_stats_.munmaped - + accumulated_stats_.really_freed - + accumulated_stats_.really_freed_redzones; - uptr total_used = accumulated_stats_.malloced - + accumulated_stats_.malloced_redzones; - // Return sane value if total_free < total_used due to racy - // way we update accumulated stats. - return (total_free > total_used) ? total_free - total_used : 1; -} - -// Return several stats counters with a single call to -// UpdateAccumulatedStatsUnlocked(). -void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) { - BlockingMutexLock lock(&mu_); - UpdateAccumulatedStatsUnlocked(); - malloc_stats->blocks_in_use = accumulated_stats_.mallocs; - malloc_stats->size_in_use = accumulated_stats_.malloced; - malloc_stats->max_size_in_use = max_malloced_memory_; - malloc_stats->size_allocated = accumulated_stats_.mmaped; + for (u32 tid = 0; tid < n_threads_; tid++) { + AsanThread *t = thread_summaries_[tid]->thread(); + if (t != 0) { + FlushToAccumulatedStatsUnlocked(&t->stats()); + } + } } AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) { @@ -137,30 +93,4 @@ AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) { return 0; } -void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() { - for (u32 tid = 0; tid < n_threads_; tid++) { - AsanThread *t = thread_summaries_[tid]->thread(); - if (t != 0) { - FlushToAccumulatedStatsUnlocked(&t->stats()); - } - } - // This is not very accurate: we may miss allocation peaks that happen - // between two updates of accumulated_stats_. For more accurate bookkeeping - // the maximum should be updated on every malloc(), which is unacceptable. - if (max_malloced_memory_ < accumulated_stats_.malloced) { - max_malloced_memory_ = accumulated_stats_.malloced; - } -} - -void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) { - // AsanStats consists of variables of type uptr only. - uptr *dst = (uptr*)&accumulated_stats_; - uptr *src = (uptr*)stats; - uptr num_fields = sizeof(AsanStats) / sizeof(uptr); - for (uptr i = 0; i < num_fields; i++) { - dst[i] += src[i]; - src[i] = 0; - } -} - } // namespace __asan diff --git a/lib/asan/asan_thread_registry.h b/lib/asan/asan_thread_registry.h index 112f412d..cfa8b668 100644 --- a/lib/asan/asan_thread_registry.h +++ b/lib/asan/asan_thread_registry.h @@ -34,35 +34,16 @@ class AsanThreadRegistry { void UnregisterThread(AsanThread *thread); AsanThread *GetMain(); - - // Returns stats for GetCurrentThread(), or stats for - // T0 if GetCurrentThread() returns 0. - AsanStats &GetCurrentThreadStats(); - // Flushes all thread-local stats to accumulated stats, and makes - // a copy of accumulated stats. - void GetAccumulatedStats(AsanStats *stats); - uptr GetCurrentAllocatedBytes(); - uptr GetHeapSize(); - uptr GetFreeBytes(); - void FillMallocStatistics(AsanMallocStats *malloc_stats); + void FlushAllStats(); AsanThreadSummary *FindByTid(u32 tid); AsanThread *FindThreadByStackAddress(uptr addr); private: - void UpdateAccumulatedStatsUnlocked(); - // Adds values of all counters in "stats" to accumulated stats, - // and fills "stats" with zeroes. - void FlushToAccumulatedStatsUnlocked(AsanStats *stats); - static const u32 kMaxNumberOfThreads = (1 << 22); // 4M AsanThreadSummary *thread_summaries_[kMaxNumberOfThreads]; AsanThread main_thread_; AsanThreadSummary main_thread_summary_; - AsanStats accumulated_stats_; - // Required for malloc_zone_statistics() on OS X. This can't be stored in - // per-thread AsanStats. - uptr max_malloced_memory_; u32 n_threads_; BlockingMutex mu_; bool inited_; -- cgit v1.2.3