asan_stats.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
1765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//===-- asan_stats.cc -----------------------------------------------------===// 2765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// 3765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// The LLVM Compiler Infrastructure 4765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// 5765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// This file is distributed under the University of Illinois Open Source 6765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// License. See LICENSE.TXT for details. 7765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// 8765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//===----------------------------------------------------------------------===// 9765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// 10765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// This file is a part of AddressSanitizer, an address sanity checker. 11765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// 12765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// Code related to statistics collected by AddressSanitizer. 13765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//===----------------------------------------------------------------------===// 14765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_interceptors.h" 15765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_internal.h" 16765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_stats.h" 17765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_thread.h" 18765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "sanitizer_common/sanitizer_allocator_interface.h" 19765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "sanitizer_common/sanitizer_mutex.h" 20765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "sanitizer_common/sanitizer_stackdepot.h" 21765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 22765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyenamespace __asan { 23765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 24765e52e2d30d0754625b8c7af6c36e93612f15beTor NorbyeAsanStats::AsanStats() { 25765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Clear(); 26765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye} 27765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 28765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyevoid AsanStats::Clear() { 29765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye CHECK(REAL(memset)); 30765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye REAL(memset)(this, 0, sizeof(AsanStats)); 31765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye} 32765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 33765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic void PrintMallocStatsArray(const char *prefix, 34765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye uptr (&array)[kNumberOfSizeClasses]) { 35765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("%s", prefix); 36765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye for (uptr i = 0; i < kNumberOfSizeClasses; i++) { 37765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye if (!array[i]) continue; 38765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("%zu:%zu; ", i, array[i]); 39765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye } 40765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("\n"); 41765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye} 42765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 43765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyevoid AsanStats::Print() { 44765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n", 45765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye malloced>>20, malloced_redzones>>20, mallocs); 46765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs); 47765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees); 48765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("Stats: %zuM really freed by %zu calls\n", 49765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye really_freed>>20, real_frees); 50765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n", 51765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20, 52765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye mmaps, munmaps); 53765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 54765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size); 55765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size); 56765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye PrintMallocStatsArray(" frees by size class: ", freed_by_size); 57765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size); 58765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye Printf("Stats: malloc large: %zu small slow: %zu\n", 59765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye malloc_large, malloc_small_slow); 60765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye} 61765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 62765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyevoid AsanStats::MergeFrom(const AsanStats *stats) { 63765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye uptr *dst_ptr = reinterpret_cast<uptr*>(this); 64765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye const uptr *src_ptr = reinterpret_cast<const uptr*>(stats); 65765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye uptr num_fields = sizeof(*this) / sizeof(uptr); 66765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye for (uptr i = 0; i < num_fields; i++) 67765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye dst_ptr[i] += src_ptr[i]; 68765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye} 69765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 70765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic BlockingMutex print_lock(LINKER_INITIALIZED); 71765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 72765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic AsanStats unknown_thread_stats(LINKER_INITIALIZED); 73765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic AsanStats dead_threads_stats(LINKER_INITIALIZED); 74765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED); 75765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// Required for malloc_zone_statistics() on OS X. This can't be stored in 76765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// per-thread AsanStats. 77765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic uptr max_malloced_memory; 78765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye 79765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) { 80765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg); 81 AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base); 82 if (AsanThread *t = tctx->thread) 83 accumulated_stats->MergeFrom(&t->stats()); 84} 85 86static void GetAccumulatedStats(AsanStats *stats) { 87 stats->Clear(); 88 { 89 ThreadRegistryLock l(&asanThreadRegistry()); 90 asanThreadRegistry() 91 .RunCallbackForEachThreadLocked(MergeThreadStats, stats); 92 } 93 stats->MergeFrom(&unknown_thread_stats); 94 { 95 BlockingMutexLock lock(&dead_threads_stats_lock); 96 stats->MergeFrom(&dead_threads_stats); 97 } 98 // This is not very accurate: we may miss allocation peaks that happen 99 // between two updates of accumulated_stats_. For more accurate bookkeeping 100 // the maximum should be updated on every malloc(), which is unacceptable. 101 if (max_malloced_memory < stats->malloced) { 102 max_malloced_memory = stats->malloced; 103 } 104} 105 106void FlushToDeadThreadStats(AsanStats *stats) { 107 BlockingMutexLock lock(&dead_threads_stats_lock); 108 dead_threads_stats.MergeFrom(stats); 109 stats->Clear(); 110} 111 112void FillMallocStatistics(AsanMallocStats *malloc_stats) { 113 AsanStats stats; 114 GetAccumulatedStats(&stats); 115 malloc_stats->blocks_in_use = stats.mallocs; 116 malloc_stats->size_in_use = stats.malloced; 117 malloc_stats->max_size_in_use = max_malloced_memory; 118 malloc_stats->size_allocated = stats.mmaped; 119} 120 121AsanStats &GetCurrentThreadStats() { 122 AsanThread *t = GetCurrentThread(); 123 return (t) ? t->stats() : unknown_thread_stats; 124} 125 126static void PrintAccumulatedStats() { 127 AsanStats stats; 128 GetAccumulatedStats(&stats); 129 // Use lock to keep reports from mixing up. 130 BlockingMutexLock lock(&print_lock); 131 stats.Print(); 132 StackDepotStats *stack_depot_stats = StackDepotGetStats(); 133 Printf("Stats: StackDepot: %zd ids; %zdM allocated\n", 134 stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20); 135 PrintInternalAllocatorStats(); 136} 137 138} // namespace __asan 139 140// ---------------------- Interface ---------------- {{{1 141using namespace __asan; // NOLINT 142 143uptr __sanitizer_get_current_allocated_bytes() { 144 AsanStats stats; 145 GetAccumulatedStats(&stats); 146 uptr malloced = stats.malloced; 147 uptr freed = stats.freed; 148 // Return sane value if malloced < freed due to racy 149 // way we update accumulated stats. 150 return (malloced > freed) ? malloced - freed : 1; 151} 152uptr __asan_get_current_allocated_bytes() { 153 return __sanitizer_get_current_allocated_bytes(); 154} 155 156uptr __sanitizer_get_heap_size() { 157 AsanStats stats; 158 GetAccumulatedStats(&stats); 159 return stats.mmaped - stats.munmaped; 160} 161uptr __asan_get_heap_size() { 162 return __sanitizer_get_heap_size(); 163} 164 165uptr __sanitizer_get_free_bytes() { 166 AsanStats stats; 167 GetAccumulatedStats(&stats); 168 uptr total_free = stats.mmaped 169 - stats.munmaped 170 + stats.really_freed 171 + stats.really_freed_redzones; 172 uptr total_used = stats.malloced 173 + stats.malloced_redzones; 174 // Return sane value if total_free < total_used due to racy 175 // way we update accumulated stats. 176 return (total_free > total_used) ? total_free - total_used : 1; 177} 178uptr __asan_get_free_bytes() { 179 return __sanitizer_get_free_bytes(); 180} 181 182uptr __sanitizer_get_unmapped_bytes() { 183 return 0; 184} 185uptr __asan_get_unmapped_bytes() { 186 return __sanitizer_get_unmapped_bytes(); 187} 188 189void __asan_print_accumulated_stats() { 190 PrintAccumulatedStats(); 191} 192