Path: blob/main/contrib/llvm-project/compiler-rt/lib/asan/asan_memory_profile.cpp
35233 views
//===-- asan_memory_profile.cpp ----------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of AddressSanitizer, an address sanity checker.9//10// This file implements __sanitizer_print_memory_profile.11//===----------------------------------------------------------------------===//1213#include "asan/asan_allocator.h"14#include "lsan/lsan_common.h"15#include "sanitizer_common/sanitizer_common.h"16#include "sanitizer_common/sanitizer_stackdepot.h"17#include "sanitizer_common/sanitizer_stacktrace.h"1819#if CAN_SANITIZE_LEAKS2021namespace __asan {2223struct AllocationSite {24u32 id;25uptr total_size;26uptr count;27};2829class HeapProfile {30public:31HeapProfile() { allocations_.reserve(1024); }3233void ProcessChunk(const AsanChunkView &cv) {34if (cv.IsAllocated()) {35total_allocated_user_size_ += cv.UsedSize();36total_allocated_count_++;37u32 id = cv.GetAllocStackId();38if (id)39Insert(id, cv.UsedSize());40} else if (cv.IsQuarantined()) {41total_quarantined_user_size_ += cv.UsedSize();42total_quarantined_count_++;43} else {44total_other_count_++;45}46}4748void Print(uptr top_percent, uptr max_number_of_contexts) {49Sort(allocations_.data(), allocations_.size(),50[](const AllocationSite &a, const AllocationSite &b) {51return a.total_size > b.total_size;52});53CHECK(total_allocated_user_size_);54uptr total_shown = 0;55Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: "56"%zd bytes in %zd chunks; %zd other chunks; total chunks: %zd; "57"showing top %zd%% (at most %zd unique contexts)\n",58total_allocated_user_size_, total_allocated_count_,59total_quarantined_user_size_, total_quarantined_count_,60total_other_count_, total_allocated_count_ +61total_quarantined_count_ + total_other_count_, top_percent,62max_number_of_contexts);63for (uptr i = 0; i < Min(allocations_.size(), max_number_of_contexts);64i++) {65auto &a = allocations_[i];66Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size,67a.total_size * 100 / total_allocated_user_size_, a.count);68StackDepotGet(a.id).Print();69total_shown += a.total_size;70if (total_shown * 100 / total_allocated_user_size_ > top_percent)71break;72}73}7475private:76uptr total_allocated_user_size_ = 0;77uptr total_allocated_count_ = 0;78uptr total_quarantined_user_size_ = 0;79uptr total_quarantined_count_ = 0;80uptr total_other_count_ = 0;81InternalMmapVector<AllocationSite> allocations_;8283void Insert(u32 id, uptr size) {84// Linear lookup will be good enough for most cases (although not all).85for (uptr i = 0; i < allocations_.size(); i++) {86if (allocations_[i].id == id) {87allocations_[i].total_size += size;88allocations_[i].count++;89return;90}91}92allocations_.push_back({id, size, 1});93}94};9596static void ChunkCallback(uptr chunk, void *arg) {97reinterpret_cast<HeapProfile*>(arg)->ProcessChunk(98FindHeapChunkByAllocBeg(chunk));99}100101static void MemoryProfileCB(uptr top_percent, uptr max_number_of_contexts) {102HeapProfile hp;103__lsan::LockAllocator();104__lsan::ForEachChunk(ChunkCallback, &hp);105__lsan::UnlockAllocator();106hp.Print(top_percent, max_number_of_contexts);107108if (Verbosity())109__asan_print_accumulated_stats();110}111} // namespace __asan112113#endif // CAN_SANITIZE_LEAKS114115extern "C" {116SANITIZER_INTERFACE_ATTRIBUTE117void __sanitizer_print_memory_profile(uptr top_percent,118uptr max_number_of_contexts) {119#if CAN_SANITIZE_LEAKS120__asan::MemoryProfileCB(top_percent, max_number_of_contexts);121#endif // CAN_SANITIZE_LEAKS122}123} // extern "C"124125126