1 // Copyright (c) 2012 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.
6 // Author: Sainbayar Sukhbaatar
9 // This file contains a class DeepHeapProfile and its public function
10 // DeepHeapProfile::DumpOrderedProfile(). The function works like
11 // HeapProfileTable::FillOrderedProfile(), but dumps directory to files.
13 // DeepHeapProfile::DumpOrderedProfile() dumps more detailed information about
14 // heap usage, which includes OS-level information such as memory residency and
15 // type information if the type profiler is available.
17 // DeepHeapProfile::DumpOrderedProfile() uses data stored in HeapProfileTable.
18 // Any code in DeepHeapProfile runs only when DumpOrderedProfile() is called.
19 // It has overhead in dumping, but no overhead in logging.
21 // It currently works only on Linux including Android. It does nothing in
22 // non-Linux environments.
24 // Note that uint64 is used to represent addresses instead of uintptr_t, and
25 // int is used to represent buffer sizes instead of size_t.
26 // It's for consistency with other TCMalloc functions. ProcMapsIterator uses
27 // uint64 for addresses, and HeapProfileTable::DumpOrderedProfile uses int
30 #ifndef BASE_DEEP_HEAP_PROFILE_H_
31 #define BASE_DEEP_HEAP_PROFILE_H_
35 #if defined(TYPE_PROFILING)
39 #if defined(__linux__) || defined(_WIN32) || defined(_WIN64)
40 #define USE_DEEP_HEAP_PROFILE 1
43 #include "addressmap-inl.h"
44 #include "heap-profile-table.h"
45 #include "memory_region_map.h"
47 class DeepHeapProfile
{
50 DUMP_NO_PAGEFRAME
= 0, // Dumps nothing about pageframes
51 DUMP_PFN
= 1, // Dumps only pageframe numbers (PFNs)
52 DUMP_PAGECOUNT
= 2, // Dumps PFNs and pagecounts
55 // Constructs a DeepHeapProfile instance. It works as a wrapper of
58 // |heap_profile| is a pointer to HeapProfileTable. DeepHeapProfile reads
59 // data in |heap_profile| and forwards operations to |heap_profile| if
60 // DeepHeapProfile is not available (non-Linux).
61 // |prefix| is a prefix of dumped file names.
62 // |pageframe_type| means what information is dumped for pageframes.
63 DeepHeapProfile(HeapProfileTable
* heap_profile
,
65 enum PageFrameType pageframe_type
);
68 // Dumps a deep profile into |fd| with using |raw_buffer| of |buffer_size|.
70 // In addition, a list of buckets is dumped into a ".buckets" file in
71 // descending order of allocated bytes.
72 void DumpOrderedProfile(const char* reason
,
78 #ifdef USE_DEEP_HEAP_PROFILE
79 typedef HeapProfileTable::Stats Stats
;
80 typedef HeapProfileTable::Bucket Bucket
;
81 typedef HeapProfileTable::AllocValue AllocValue
;
82 typedef HeapProfileTable::AllocationMap AllocationMap
;
85 // Bytes of memory which were not recognized with /proc/<pid>/maps.
86 // This size should be 0.
89 // Bytes of memory which is mapped anonymously.
90 // Regions which contain nothing in the last column of /proc/<pid>/maps.
93 // Bytes of memory which is mapped to a executable/non-executable file.
94 // Regions which contain file paths in the last column of /proc/<pid>/maps.
98 // Bytes of memory which is labeled [stack] in /proc/<pid>/maps.
101 // Bytes of memory which is labeled, but not mapped to any file.
102 // Regions which contain non-path strings in the last column of
106 NUMBER_OF_MAPS_REGION_TYPES
109 static const char* kMapsRegionTypeDict
[NUMBER_OF_MAPS_REGION_TYPES
];
111 // Manages a buffer to keep a text to be dumped to a file.
114 TextBuffer(char *raw_buffer
, int size
, RawFD fd
)
115 : buffer_(raw_buffer
),
126 bool AppendChar(char value
);
127 bool AppendString(const char* value
, int width
);
128 bool AppendInt(int value
, int width
, bool leading_zero
);
129 bool AppendLong(long value
, int width
);
130 bool AppendUnsignedLong(unsigned long value
, int width
);
131 bool AppendInt64(int64 value
, int width
);
132 bool AppendBase64(uint64 value
, int width
);
133 bool AppendPtr(uint64 value
, int width
);
136 bool ForwardCursor(int appended
);
142 DISALLOW_COPY_AND_ASSIGN(TextBuffer
);
145 // Defines an interface for getting info about memory residence.
146 class MemoryResidenceInfoGetterInterface
{
148 virtual ~MemoryResidenceInfoGetterInterface();
150 // Initializes the instance.
151 virtual void Initialize() = 0;
153 // Returns the number of resident (including swapped) bytes of the given
154 // memory region from |first_address| to |last_address| inclusive.
155 virtual size_t CommittedSize(uint64 first_address
,
157 TextBuffer
* buffer
) const = 0;
159 // Creates a new platform specific MemoryResidenceInfoGetterInterface.
160 static MemoryResidenceInfoGetterInterface
* Create(
161 PageFrameType pageframe_type
);
163 virtual bool IsPageCountAvailable() const = 0;
166 MemoryResidenceInfoGetterInterface();
169 #if defined(_WIN32) || defined(_WIN64)
170 // TODO(peria): Implement this class.
171 class MemoryInfoGetterWindows
: public MemoryResidenceInfoGetterInterface
{
173 MemoryInfoGetterWindows(PageFrameType
) {}
174 virtual ~MemoryInfoGetterWindows() {}
176 virtual void Initialize();
178 virtual size_t CommittedSize(uint64 first_address
,
180 TextBuffer
* buffer
) const;
182 virtual bool IsPageCountAvailable() const;
184 #endif // defined(_WIN32) || defined(_WIN64)
186 #if defined(__linux__)
187 // Implements MemoryResidenceInfoGetterInterface for Linux.
188 class MemoryInfoGetterLinux
: public MemoryResidenceInfoGetterInterface
{
190 MemoryInfoGetterLinux(PageFrameType pageframe_type
)
191 : pageframe_type_(pageframe_type
),
192 pagemap_fd_(kIllegalRawFD
),
193 kpagecount_fd_(kIllegalRawFD
) {}
194 virtual ~MemoryInfoGetterLinux() {}
196 // Opens /proc/<pid>/pagemap and stores its file descriptor.
197 // It keeps open while the process is running.
199 // Note that file descriptors need to be refreshed after fork.
200 virtual void Initialize();
202 // Returns the number of resident (including swapped) bytes of the given
203 // memory region from |first_address| to |last_address| inclusive.
204 virtual size_t CommittedSize(uint64 first_address
,
206 TextBuffer
* buffer
) const;
208 virtual bool IsPageCountAvailable() const;
213 bool is_committed
; // Currently, we use only this
220 uint64
ReadPageCount(uint64 pfn
) const;
222 // Seeks to the offset of the open pagemap file.
223 // It returns true if succeeded.
224 bool Seek(uint64 address
) const;
226 // Reads a pagemap state from the current offset.
227 // It returns true if succeeded.
228 bool Read(State
* state
, bool get_pfn
) const;
230 PageFrameType pageframe_type_
;
232 RawFD kpagecount_fd_
;
234 #endif // defined(__linux__)
236 // Contains extended information for HeapProfileTable::Bucket. These objects
237 // are managed in a hash table (DeepBucketTable) whose key is an address of
238 // a Bucket and other additional information.
241 void UnparseForStats(TextBuffer
* buffer
);
242 void UnparseForBucketFile(TextBuffer
* buffer
);
245 #if defined(TYPE_PROFILING)
246 const std::type_info
* type
; // A type of the object
248 size_t committed_size
; // A resident size of this bucket
249 bool is_mmap
; // True if the bucket represents a mmap region
250 int id
; // A unique ID of the bucket
251 bool is_logged
; // True if the stracktrace is logged to a file
252 DeepBucket
* next
; // A reference to the next entry in the hash table
255 // Manages a hash table for DeepBucket.
256 class DeepBucketTable
{
258 DeepBucketTable(int size
,
259 HeapProfileTable::Allocator alloc
,
260 HeapProfileTable::DeAllocator dealloc
);
263 // Finds a DeepBucket instance corresponding to the given |bucket|, or
264 // creates a new DeepBucket object if it doesn't exist.
265 DeepBucket
* Lookup(Bucket
* bucket
,
266 #if defined(TYPE_PROFILING)
267 const std::type_info
* type
,
271 // Writes stats of the hash table to |buffer| for DumpOrderedProfile.
272 void UnparseForStats(TextBuffer
* buffer
);
274 // Writes all buckets for a bucket file with using |buffer|.
275 void WriteForBucketFile(const char* prefix
,
280 // Resets 'committed_size' members in DeepBucket objects.
281 void ResetCommittedSize();
283 // Resets all 'is_loggeed' flags in DeepBucket objects.
284 void ResetIsLogged();
287 // Adds |add| to a |hash_value| for Lookup.
288 inline static void AddToHashValue(uintptr_t add
, uintptr_t* hash_value
);
289 inline static void FinishHashValue(uintptr_t* hash_value
);
293 HeapProfileTable::Allocator alloc_
;
294 HeapProfileTable::DeAllocator dealloc_
;
300 RegionStats(): virtual_bytes_(0), committed_bytes_(0) {}
303 // Initializes 'virtual_bytes_' and 'committed_bytes_'.
306 // Updates itself to contain the tallies of 'virtual_bytes' and
307 // 'committed_bytes' in the region from |first_adress| to |last_address|
310 const MemoryResidenceInfoGetterInterface
* memory_residence_info_getter
,
311 uint64 first_address
,
315 // Writes stats of the region into |buffer| with |name|.
316 void Unparse(const char* name
, TextBuffer
* buffer
);
318 size_t virtual_bytes() const { return virtual_bytes_
; }
319 size_t committed_bytes() const { return committed_bytes_
; }
320 void AddToVirtualBytes(size_t additional_virtual_bytes
) {
321 virtual_bytes_
+= additional_virtual_bytes
;
323 void AddToCommittedBytes(size_t additional_committed_bytes
) {
324 committed_bytes_
+= additional_committed_bytes
;
326 void AddAnotherRegionStat(const RegionStats
& other
) {
327 virtual_bytes_
+= other
.virtual_bytes_
;
328 committed_bytes_
+= other
.committed_bytes_
;
332 size_t virtual_bytes_
;
333 size_t committed_bytes_
;
334 DISALLOW_COPY_AND_ASSIGN(RegionStats
);
339 // Snapshots and calculates global stats from /proc/<pid>/maps and pagemap.
341 const MemoryResidenceInfoGetterInterface
* memory_residence_info_getter
,
342 DeepHeapProfile
* deep_profile
,
343 TextBuffer
* mmap_dump_buffer
);
345 // Snapshots allocations by malloc and mmap.
346 void SnapshotAllocations(DeepHeapProfile
* deep_profile
);
348 // Writes global stats into |buffer|.
349 void Unparse(TextBuffer
* buffer
);
352 // Records both virtual and committed byte counts of malloc and mmap regions
353 // as callback functions for AllocationMap::Iterate().
354 static void RecordAlloc(const void* pointer
,
355 AllocValue
* alloc_value
,
356 DeepHeapProfile
* deep_profile
);
358 DeepBucket
* GetInformationOfMemoryRegion(
359 const MemoryRegionMap::RegionIterator
& mmap_iter
,
360 const MemoryResidenceInfoGetterInterface
* memory_residence_info_getter
,
361 DeepHeapProfile
* deep_profile
);
363 // All RegionStats members in this class contain the bytes of virtual
364 // memory and committed memory.
365 // TODO(dmikurube): These regions should be classified more precisely later
366 // for more detailed analysis.
367 RegionStats all_
[NUMBER_OF_MAPS_REGION_TYPES
];
369 RegionStats unhooked_
[NUMBER_OF_MAPS_REGION_TYPES
];
371 // Total bytes of malloc'ed regions.
372 RegionStats profiled_malloc_
;
374 // Total bytes of mmap'ed regions.
375 RegionStats profiled_mmap_
;
378 // Writes reformatted /proc/<pid>/maps into a file "|prefix|.<pid>.maps"
379 // with using |raw_buffer| of |buffer_size|.
380 static void WriteProcMaps(const char* prefix
,
384 // Appends the command line (/proc/pid/cmdline on Linux) into |buffer|.
385 bool AppendCommandLine(TextBuffer
* buffer
);
387 MemoryResidenceInfoGetterInterface
* memory_residence_info_getter_
;
389 // Process ID of the last dump. This can change by fork.
390 pid_t most_recent_pid_
;
392 GlobalStats stats_
; // Stats about total memory.
393 int dump_count_
; // The number of dumps.
394 char* filename_prefix_
; // Output file prefix.
397 DeepBucketTable deep_table_
;
399 enum PageFrameType pageframe_type_
;
400 #endif // USE_DEEP_HEAP_PROFILE
402 HeapProfileTable
* heap_profile_
;
404 DISALLOW_COPY_AND_ASSIGN(DeepHeapProfile
);
407 #endif // BASE_DEEP_HEAP_PROFILE_H_