Revert of Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320) (patchset...
[chromium-blink-merge.git] / third_party / tcmalloc / chromium / src / deep-heap-profile.h
blob0544b31c7dd1de95a87f811ff87bf2f734c19855
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.
5 // ---
6 // Author: Sainbayar Sukhbaatar
7 // Dai Mikurube
8 //
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
28 // for buffer sizes.
30 #ifndef BASE_DEEP_HEAP_PROFILE_H_
31 #define BASE_DEEP_HEAP_PROFILE_H_
33 #include "config.h"
35 #if defined(TYPE_PROFILING)
36 #include <typeinfo>
37 #endif
39 #if defined(__linux__) || defined(_WIN32) || defined(_WIN64)
40 #define USE_DEEP_HEAP_PROFILE 1
41 #endif
43 #include "addressmap-inl.h"
44 #include "heap-profile-table.h"
45 #include "memory_region_map.h"
47 class DeepHeapProfile {
48 public:
49 enum PageFrameType {
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
56 // HeapProfileTable.
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,
64 const char* prefix,
65 enum PageFrameType pageframe_type);
66 ~DeepHeapProfile();
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,
73 char raw_buffer[],
74 int buffer_size,
75 RawFD fd);
77 private:
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;
84 enum MapsRegionType {
85 // Bytes of memory which were not recognized with /proc/<pid>/maps.
86 // This size should be 0.
87 ABSENT,
89 // Bytes of memory which is mapped anonymously.
90 // Regions which contain nothing in the last column of /proc/<pid>/maps.
91 ANONYMOUS,
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.
95 FILE_EXEC,
96 FILE_NONEXEC,
98 // Bytes of memory which is labeled [stack] in /proc/<pid>/maps.
99 STACK,
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
103 // /proc/<pid>/maps.
104 OTHER,
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.
112 class TextBuffer {
113 public:
114 TextBuffer(char *raw_buffer, int size, RawFD fd)
115 : buffer_(raw_buffer),
116 size_(size),
117 cursor_(0),
118 fd_(fd) {
121 int Size();
122 int FilledBytes();
123 void Clear();
124 void Flush();
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);
135 private:
136 bool ForwardCursor(int appended);
138 char *buffer_;
139 int size_;
140 int cursor_;
141 RawFD fd_;
142 DISALLOW_COPY_AND_ASSIGN(TextBuffer);
145 // Defines an interface for getting info about memory residence.
146 class MemoryResidenceInfoGetterInterface {
147 public:
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,
156 uint64 last_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;
165 protected:
166 MemoryResidenceInfoGetterInterface();
169 #if defined(_WIN32) || defined(_WIN64)
170 // TODO(peria): Implement this class.
171 class MemoryInfoGetterWindows : public MemoryResidenceInfoGetterInterface {
172 public:
173 MemoryInfoGetterWindows(PageFrameType) {}
174 virtual ~MemoryInfoGetterWindows() {}
176 virtual void Initialize();
178 virtual size_t CommittedSize(uint64 first_address,
179 uint64 last_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 {
189 public:
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,
205 uint64 last_address,
206 TextBuffer* buffer) const;
208 virtual bool IsPageCountAvailable() const;
210 private:
211 struct State {
212 uint64 pfn;
213 bool is_committed; // Currently, we use only this
214 bool is_present;
215 bool is_swapped;
216 bool is_shared;
217 bool is_mmap;
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_;
231 RawFD pagemap_fd_;
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.
239 struct DeepBucket {
240 public:
241 void UnparseForStats(TextBuffer* buffer);
242 void UnparseForBucketFile(TextBuffer* buffer);
244 Bucket* bucket;
245 #if defined(TYPE_PROFILING)
246 const std::type_info* type; // A type of the object
247 #endif
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 {
257 public:
258 DeepBucketTable(int size,
259 HeapProfileTable::Allocator alloc,
260 HeapProfileTable::DeAllocator dealloc);
261 ~DeepBucketTable();
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,
268 #endif
269 bool is_mmap);
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,
276 int dump_count,
277 char raw_buffer[],
278 int buffer_size);
280 // Resets 'committed_size' members in DeepBucket objects.
281 void ResetCommittedSize();
283 // Resets all 'is_loggeed' flags in DeepBucket objects.
284 void ResetIsLogged();
286 private:
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);
291 DeepBucket** table_;
292 size_t table_size_;
293 HeapProfileTable::Allocator alloc_;
294 HeapProfileTable::DeAllocator dealloc_;
295 int bucket_id_;
298 class RegionStats {
299 public:
300 RegionStats(): virtual_bytes_(0), committed_bytes_(0) {}
301 ~RegionStats() {}
303 // Initializes 'virtual_bytes_' and 'committed_bytes_'.
304 void Initialize();
306 // Updates itself to contain the tallies of 'virtual_bytes' and
307 // 'committed_bytes' in the region from |first_adress| to |last_address|
308 // inclusive.
309 uint64 Record(
310 const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
311 uint64 first_address,
312 uint64 last_address,
313 TextBuffer* buffer);
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_;
331 private:
332 size_t virtual_bytes_;
333 size_t committed_bytes_;
334 DISALLOW_COPY_AND_ASSIGN(RegionStats);
337 class GlobalStats {
338 public:
339 // Snapshots and calculates global stats from /proc/<pid>/maps and pagemap.
340 void SnapshotMaps(
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);
351 private:
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,
381 char raw_buffer[],
382 int buffer_size);
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.
395 char run_id_[128];
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_