1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/trace_event/malloc_dump_provider.h"
6
7 #include <stddef.h>
8
9 #include "base/allocator/allocator_extension.h"
10 #include "base/trace_event/process_memory_dump.h"
11 #include "build/build_config.h"
12
13 #if defined(OS_MACOSX)
14 #include <malloc/malloc.h>
15 #else
16 #include <malloc.h>
17 #endif
18
19 namespace base {
20 namespace trace_event {
21
22 // static
23 const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects";
24
25 // static
GetInstance()26 MallocDumpProvider* MallocDumpProvider::GetInstance() {
27 return Singleton<MallocDumpProvider,
28 LeakySingletonTraits<MallocDumpProvider>>::get();
29 }
30
MallocDumpProvider()31 MallocDumpProvider::MallocDumpProvider() {}
32
~MallocDumpProvider()33 MallocDumpProvider::~MallocDumpProvider() {}
34
35 // Called at trace dump point time. Creates a snapshot the memory counters for
36 // the current process.
OnMemoryDump(const MemoryDumpArgs &,ProcessMemoryDump * pmd)37 bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& /* args */,
38 ProcessMemoryDump* pmd) {
39 size_t total_virtual_size = 0;
40 size_t resident_size = 0;
41 size_t allocated_objects_size = 0;
42 #if defined(USE_TCMALLOC)
43 bool res =
44 allocator::GetNumericProperty("generic.heap_size", &total_virtual_size);
45 DCHECK(res);
46 res = allocator::GetNumericProperty("generic.total_physical_bytes",
47 &resident_size);
48 DCHECK(res);
49 res = allocator::GetNumericProperty("generic.current_allocated_bytes",
50 &allocated_objects_size);
51 DCHECK(res);
52 #elif defined(OS_MACOSX) || defined(OS_IOS)
53 malloc_statistics_t stats;
54 memset(&stats, 0, sizeof(stats));
55 malloc_zone_statistics(nullptr, &stats);
56 total_virtual_size = stats.size_allocated;
57 allocated_objects_size = stats.size_in_use;
58
59 // The resident size is approximated to the max size in use, which would count
60 // the total size of all regions other than the free bytes at the end of each
61 // region. In each allocation region the allocations are rounded off to a
62 // fixed quantum, so the excess region will not be resident.
63 // See crrev.com/1531463004 for detailed explanation.
64 resident_size = stats.max_size_in_use;
65 #else
66 struct mallinfo info = mallinfo();
67 DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
68
69 // In case of Android's jemalloc |arena| is 0 and the outer pages size is
70 // reported by |hblkhd|. In case of dlmalloc the total is given by
71 // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF.
72 total_virtual_size = info.arena + info.hblkhd;
73 resident_size = info.uordblks;
74 allocated_objects_size = info.uordblks;
75 #endif
76
77 MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
78 outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes,
79 total_virtual_size);
80 outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
81 MemoryAllocatorDump::kUnitsBytes, resident_size);
82
83 // Total allocated space is given by |uordblks|.
84 MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects);
85 inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
86 MemoryAllocatorDump::kUnitsBytes,
87 allocated_objects_size);
88
89 if (resident_size - allocated_objects_size > 0) {
90 // Explicitly specify why is extra memory resident. In tcmalloc it accounts
91 // for free lists and caches. In mac and ios it accounts for the
92 // fragmentation and metadata.
93 MemoryAllocatorDump* other_dump =
94 pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches");
95 other_dump->AddScalar(MemoryAllocatorDump::kNameSize,
96 MemoryAllocatorDump::kUnitsBytes,
97 resident_size - allocated_objects_size);
98 }
99
100 return true;
101 }
102
103 } // namespace trace_event
104 } // namespace base
105