1 //===-- asan_memory_profile.cc.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 // This file implements __sanitizer_print_memory_profile. 13 //===----------------------------------------------------------------------===// 14 15 #include "sanitizer_common/sanitizer_common.h" 16 #include "sanitizer_common/sanitizer_stackdepot.h" 17 #include "sanitizer_common/sanitizer_stacktrace.h" 18 #include "sanitizer_common/sanitizer_stoptheworld.h" 19 #include "lsan/lsan_common.h" 20 #include "asan/asan_allocator.h" 21 22 #if CAN_SANITIZE_LEAKS 23 24 namespace __asan { 25 26 struct AllocationSite { 27 u32 id; 28 uptr total_size; 29 uptr count; 30 }; 31 32 class HeapProfile { 33 public: 34 HeapProfile() { allocations_.reserve(1024); } 35 36 void ProcessChunk(const AsanChunkView &cv) { 37 if (cv.IsAllocated()) { 38 total_allocated_user_size_ += cv.UsedSize(); 39 total_allocated_count_++; 40 u32 id = cv.GetAllocStackId(); 41 if (id) 42 Insert(id, cv.UsedSize()); 43 } else if (cv.IsQuarantined()) { 44 total_quarantined_user_size_ += cv.UsedSize(); 45 total_quarantined_count_++; 46 } else { 47 total_other_count_++; 48 } 49 } 50 51 void Print(uptr top_percent, uptr max_number_of_contexts) { 52 Sort(allocations_.data(), allocations_.size(), 53 [](const AllocationSite &a, const AllocationSite &b) { 54 return a.total_size > b.total_size; 55 }); 56 CHECK(total_allocated_user_size_); 57 uptr total_shown = 0; 58 Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: " 59 "%zd bytes in %zd chunks; %zd other chunks; total chunks: %zd; " 60 "showing top %zd%% (at most %zd unique contexts)\n", 61 total_allocated_user_size_, total_allocated_count_, 62 total_quarantined_user_size_, total_quarantined_count_, 63 total_other_count_, total_allocated_count_ + 64 total_quarantined_count_ + total_other_count_, top_percent, 65 max_number_of_contexts); 66 for (uptr i = 0; i < Min(allocations_.size(), max_number_of_contexts); 67 i++) { 68 auto &a = allocations_[i]; 69 Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size, 70 a.total_size * 100 / total_allocated_user_size_, a.count); 71 StackDepotGet(a.id).Print(); 72 total_shown += a.total_size; 73 if (total_shown * 100 / total_allocated_user_size_ > top_percent) 74 break; 75 } 76 } 77 78 private: 79 uptr total_allocated_user_size_ = 0; 80 uptr total_allocated_count_ = 0; 81 uptr total_quarantined_user_size_ = 0; 82 uptr total_quarantined_count_ = 0; 83 uptr total_other_count_ = 0; 84 InternalMmapVector<AllocationSite> allocations_; 85 86 void Insert(u32 id, uptr size) { 87 // Linear lookup will be good enough for most cases (although not all). 88 for (uptr i = 0; i < allocations_.size(); i++) { 89 if (allocations_[i].id == id) { 90 allocations_[i].total_size += size; 91 allocations_[i].count++; 92 return; 93 } 94 } 95 allocations_.push_back({id, size, 1}); 96 } 97 }; 98 99 static void ChunkCallback(uptr chunk, void *arg) { 100 reinterpret_cast<HeapProfile*>(arg)->ProcessChunk( 101 FindHeapChunkByAllocBeg(chunk)); 102 } 103 104 static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, 105 void *argument) { 106 HeapProfile hp; 107 __lsan::ForEachChunk(ChunkCallback, &hp); 108 uptr *Arg = reinterpret_cast<uptr*>(argument); 109 hp.Print(Arg[0], Arg[1]); 110 111 if (Verbosity()) 112 __asan_print_accumulated_stats(); 113 } 114 115 } // namespace __asan 116 117 #endif // CAN_SANITIZE_LEAKS 118 119 extern "C" { 120 SANITIZER_INTERFACE_ATTRIBUTE 121 void __sanitizer_print_memory_profile(uptr top_percent, 122 uptr max_number_of_contexts) { 123 #if CAN_SANITIZE_LEAKS 124 uptr Arg[2]; 125 Arg[0] = top_percent; 126 Arg[1] = max_number_of_contexts; 127 __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg); 128 #endif // CAN_SANITIZE_LEAKS 129 } 130 } // extern "C" 131