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