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