1 //===-- asan_memory_profile.cc.cc -----------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of AddressSanitizer, an address sanity checker.
10 // This file implements __sanitizer_print_memory_profile.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_common.h"
14 #include "sanitizer_common/sanitizer_stackdepot.h"
15 #include "sanitizer_common/sanitizer_stacktrace.h"
16 #include "sanitizer_common/sanitizer_stoptheworld.h"
17 #include "lsan/lsan_common.h"
18 #include "asan/asan_allocator.h"
20 #if CAN_SANITIZE_LEAKS
24 struct AllocationSite
{
32 HeapProfile() : allocations_(1024) {}
33 void Insert(u32 id
, uptr size
) {
34 total_allocated_
+= size
;
36 // Linear lookup will be good enough for most cases (although not all).
37 for (uptr i
= 0; i
< allocations_
.size(); i
++) {
38 if (allocations_
[i
].id
== id
) {
39 allocations_
[i
].total_size
+= size
;
40 allocations_
[i
].count
++;
44 allocations_
.push_back({id
, size
, 1});
47 void Print(uptr top_percent
) {
48 InternalSort(&allocations_
, allocations_
.size(),
49 [](const AllocationSite
&a
, const AllocationSite
&b
) {
50 return a
.total_size
> b
.total_size
;
52 CHECK(total_allocated_
);
54 Printf("Live Heap Allocations: %zd bytes from %zd allocations; "
55 "showing top %zd%%\n", total_allocated_
, total_count_
, top_percent
);
56 for (uptr i
= 0; i
< allocations_
.size(); i
++) {
57 auto &a
= allocations_
[i
];
58 Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a
.total_size
,
59 a
.total_size
* 100 / total_allocated_
, a
.count
);
60 StackDepotGet(a
.id
).Print();
61 total_shown
+= a
.total_size
;
62 if (total_shown
* 100 / total_allocated_
> top_percent
)
68 uptr total_allocated_
= 0;
69 uptr total_count_
= 0;
70 InternalMmapVector
<AllocationSite
> allocations_
;
73 static void ChunkCallback(uptr chunk
, void *arg
) {
74 HeapProfile
*hp
= reinterpret_cast<HeapProfile
*>(arg
);
75 AsanChunkView cv
= FindHeapChunkByAllocBeg(chunk
);
76 if (!cv
.IsAllocated()) return;
77 u32 id
= cv
.GetAllocStackId();
79 hp
->Insert(id
, cv
.UsedSize());
82 static void MemoryProfileCB(const SuspendedThreadsList
&suspended_threads_list
,
85 __lsan::ForEachChunk(ChunkCallback
, &hp
);
86 hp
.Print(reinterpret_cast<uptr
>(argument
));
92 SANITIZER_INTERFACE_ATTRIBUTE
93 void __sanitizer_print_memory_profile(uptr top_percent
) {
94 __sanitizer::StopTheWorld(__asan::MemoryProfileCB
, (void*)top_percent
);
98 #endif // CAN_SANITIZE_LEAKS