asan_stats.cc revision 717ece58e18190c4aef50bd16254db1d74036395
1//===-- asan_stats.cc -----------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of AddressSanitizer, an address sanity checker. 11// 12// Code related to statistics collected by AddressSanitizer. 13//===----------------------------------------------------------------------===// 14#include "asan_interceptors.h" 15#include "asan_internal.h" 16#include "asan_stats.h" 17#include "asan_thread.h" 18#include "sanitizer_common/sanitizer_mutex.h" 19#include "sanitizer_common/sanitizer_stackdepot.h" 20 21namespace __asan { 22 23AsanStats::AsanStats() { 24 Clear(); 25} 26 27void AsanStats::Clear() { 28 CHECK(REAL(memset)); 29 REAL(memset)(this, 0, sizeof(AsanStats)); 30} 31 32static void PrintMallocStatsArray(const char *prefix, 33 uptr (&array)[kNumberOfSizeClasses]) { 34 Printf("%s", prefix); 35 for (uptr i = 0; i < kNumberOfSizeClasses; i++) { 36 if (!array[i]) continue; 37 Printf("%zu:%zu; ", i, array[i]); 38 } 39 Printf("\n"); 40} 41 42void AsanStats::Print() { 43 Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n", 44 malloced>>20, malloced_redzones>>20, mallocs); 45 Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs); 46 Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees); 47 Printf("Stats: %zuM really freed by %zu calls\n", 48 really_freed>>20, real_frees); 49 Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n", 50 (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20, 51 mmaps, munmaps); 52 53 PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size); 54 PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size); 55 PrintMallocStatsArray(" frees by size class: ", freed_by_size); 56 PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size); 57 Printf("Stats: malloc large: %zu small slow: %zu\n", 58 malloc_large, malloc_small_slow); 59} 60 61void AsanStats::MergeFrom(const AsanStats *stats) { 62 uptr *dst_ptr = reinterpret_cast<uptr*>(this); 63 const uptr *src_ptr = reinterpret_cast<const uptr*>(stats); 64 uptr num_fields = sizeof(*this) / sizeof(uptr); 65 for (uptr i = 0; i < num_fields; i++) 66 dst_ptr[i] += src_ptr[i]; 67} 68 69static BlockingMutex print_lock(LINKER_INITIALIZED); 70 71static AsanStats unknown_thread_stats(LINKER_INITIALIZED); 72static AsanStats dead_threads_stats(LINKER_INITIALIZED); 73static BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED); 74// Required for malloc_zone_statistics() on OS X. This can't be stored in 75// per-thread AsanStats. 76static uptr max_malloced_memory; 77 78static void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) { 79 AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg); 80 AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base); 81 if (AsanThread *t = tctx->thread) 82 accumulated_stats->MergeFrom(&t->stats()); 83} 84 85static void GetAccumulatedStats(AsanStats *stats) { 86 stats->Clear(); 87 { 88 ThreadRegistryLock l(&asanThreadRegistry()); 89 asanThreadRegistry() 90 .RunCallbackForEachThreadLocked(MergeThreadStats, stats); 91 } 92 stats->MergeFrom(&unknown_thread_stats); 93 { 94 BlockingMutexLock lock(&dead_threads_stats_lock); 95 stats->MergeFrom(&dead_threads_stats); 96 } 97 // This is not very accurate: we may miss allocation peaks that happen 98 // between two updates of accumulated_stats_. For more accurate bookkeeping 99 // the maximum should be updated on every malloc(), which is unacceptable. 100 if (max_malloced_memory < stats->malloced) { 101 max_malloced_memory = stats->malloced; 102 } 103} 104 105void FlushToDeadThreadStats(AsanStats *stats) { 106 BlockingMutexLock lock(&dead_threads_stats_lock); 107 dead_threads_stats.MergeFrom(stats); 108 stats->Clear(); 109} 110 111void FillMallocStatistics(AsanMallocStats *malloc_stats) { 112 AsanStats stats; 113 GetAccumulatedStats(&stats); 114 malloc_stats->blocks_in_use = stats.mallocs; 115 malloc_stats->size_in_use = stats.malloced; 116 malloc_stats->max_size_in_use = max_malloced_memory; 117 malloc_stats->size_allocated = stats.mmaped; 118} 119 120AsanStats &GetCurrentThreadStats() { 121 AsanThread *t = GetCurrentThread(); 122 return (t) ? t->stats() : unknown_thread_stats; 123} 124 125static void PrintAccumulatedStats() { 126 AsanStats stats; 127 GetAccumulatedStats(&stats); 128 // Use lock to keep reports from mixing up. 129 BlockingMutexLock lock(&print_lock); 130 stats.Print(); 131 StackDepotStats *stack_depot_stats = StackDepotGetStats(); 132 Printf("Stats: StackDepot: %zd ids; %zdM mapped\n", 133 stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20); 134 PrintInternalAllocatorStats(); 135} 136 137} // namespace __asan 138 139// ---------------------- Interface ---------------- {{{1 140using namespace __asan; // NOLINT 141 142uptr __asan_get_current_allocated_bytes() { 143 AsanStats stats; 144 GetAccumulatedStats(&stats); 145 uptr malloced = stats.malloced; 146 uptr freed = stats.freed; 147 // Return sane value if malloced < freed due to racy 148 // way we update accumulated stats. 149 return (malloced > freed) ? malloced - freed : 1; 150} 151 152uptr __asan_get_heap_size() { 153 AsanStats stats; 154 GetAccumulatedStats(&stats); 155 return stats.mmaped - stats.munmaped; 156} 157 158uptr __asan_get_free_bytes() { 159 AsanStats stats; 160 GetAccumulatedStats(&stats); 161 uptr total_free = stats.mmaped 162 - stats.munmaped 163 + stats.really_freed 164 + stats.really_freed_redzones; 165 uptr total_used = stats.malloced 166 + stats.malloced_redzones; 167 // Return sane value if total_free < total_used due to racy 168 // way we update accumulated stats. 169 return (total_free > total_used) ? total_free - total_used : 1; 170} 171 172uptr __asan_get_unmapped_bytes() { 173 return 0; 174} 175 176void __asan_print_accumulated_stats() { 177 PrintAccumulatedStats(); 178} 179