deep-heap-profile.h revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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.
4
5// ---
6// Author: Sainbayar Sukhbaatar
7//         Dai Mikurube
8//
9// This file contains a class DeepHeapProfile and its public function
10// DeepHeapProfile::FillOrderedProfile() which works as an alternative of
11// HeapProfileTable::FillOrderedProfile().
12//
13// DeepHeapProfile::FillOrderedProfile() 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.
16//
17// DeepHeapProfile::FillOrderedProfile() uses data stored in HeapProfileTable.
18// Any code in DeepHeapProfile runs only when FillOrderedProfile() is called.
19// It has overhead in dumping, but no overhead in logging.
20//
21// It currently works only on Linux.  It just delegates to HeapProfileTable in
22// non-Linux environments.
23
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::FillOrderedProfile uses int
28// for buffer sizes.
29
30#ifndef BASE_DEEP_HEAP_PROFILE_H_
31#define BASE_DEEP_HEAP_PROFILE_H_
32
33#include "config.h"
34
35#if defined(TYPE_PROFILING)
36#include <typeinfo>
37#endif
38
39#if defined(__linux__)
40#define USE_DEEP_HEAP_PROFILE 1
41#endif
42
43#include "addressmap-inl.h"
44#include "heap-profile-table.h"
45#include "memory_region_map.h"
46
47class DeepHeapProfile {
48 public:
49  // Defines an interface for getting info about memory residence.
50  class MemoryResidenceInfoGetterInterface {
51   public:
52    virtual ~MemoryResidenceInfoGetterInterface();
53
54    // Initializes the instance.
55    virtual void Initialize() = 0;
56
57    // Returns the number of resident (including swapped) bytes of the given
58    // memory region from |first_address| to |last_address| inclusive.
59    virtual size_t CommittedSize(
60        uint64 first_address, uint64 last_address) const = 0;
61
62    // Creates a new platform specific MemoryResidenceInfoGetterInterface.
63    static MemoryResidenceInfoGetterInterface* Create();
64
65   protected:
66    MemoryResidenceInfoGetterInterface();
67  };
68
69  // Constructs a DeepHeapProfile instance.  It works as a wrapper of
70  // HeapProfileTable.
71  //
72  // |heap_profile| is a pointer to HeapProfileTable.  DeepHeapProfile reads
73  // data in |heap_profile| and forwards operations to |heap_profile| if
74  // DeepHeapProfile is not available (non-Linux).
75  // |prefix| is a prefix of dumped file names.
76  DeepHeapProfile(HeapProfileTable* heap_profile, const char* prefix);
77  ~DeepHeapProfile();
78
79  // Fills deep profile dump into |raw_buffer| of |buffer_size|, and return the
80  // actual size occupied by the dump in |raw_buffer|.  It works as an
81  // alternative of HeapProfileTable::FillOrderedProfile.  |raw_buffer| is not
82  // terminated by zero.
83  //
84  // In addition, a list of buckets is dumped into a ".buckets" file in
85  // descending order of allocated bytes.
86  int FillOrderedProfile(char raw_buffer[], int buffer_size);
87
88 private:
89#ifdef USE_DEEP_HEAP_PROFILE
90  typedef HeapProfileTable::Stats Stats;
91  typedef HeapProfileTable::Bucket Bucket;
92  typedef HeapProfileTable::AllocValue AllocValue;
93  typedef HeapProfileTable::AllocationMap AllocationMap;
94
95  enum MapsRegionType {
96    // Bytes of memory which were not recognized with /proc/<pid>/maps.
97    // This size should be 0.
98    ABSENT,
99
100    // Bytes of memory which is mapped anonymously.
101    // Regions which contain nothing in the last column of /proc/<pid>/maps.
102    ANONYMOUS,
103
104    // Bytes of memory which is mapped to a executable/non-executable file.
105    // Regions which contain file paths in the last column of /proc/<pid>/maps.
106    FILE_EXEC,
107    FILE_NONEXEC,
108
109    // Bytes of memory which is labeled [stack] in /proc/<pid>/maps.
110    STACK,
111
112    // Bytes of memory which is labeled, but not mapped to any file.
113    // Regions which contain non-path strings in the last column of
114    // /proc/<pid>/maps.
115    OTHER,
116
117    NUMBER_OF_MAPS_REGION_TYPES
118  };
119
120  static const char* kMapsRegionTypeDict[NUMBER_OF_MAPS_REGION_TYPES];
121
122  // Manages a buffer to keep a dumped text for FillOrderedProfile and other
123  // functions.
124  class TextBuffer {
125   public:
126    TextBuffer(char *raw_buffer, int size)
127        : buffer_(raw_buffer),
128          size_(size),
129          cursor_(0) {
130    }
131
132    int Size();
133    int FilledBytes();
134    void Clear();
135    void Write(RawFD fd);
136
137    bool AppendChar(char v);
138    bool AppendString(const char* v, int d);
139    bool AppendInt(int v, int d, bool leading_zero);
140    bool AppendLong(long v, int d);
141    bool AppendUnsignedLong(unsigned long v, int d);
142    bool AppendInt64(int64 v, int d);
143    bool AppendPtr(uint64 v, int d);
144
145   private:
146    bool ForwardCursor(int appended);
147
148    char *buffer_;
149    int size_;
150    int cursor_;
151    DISALLOW_COPY_AND_ASSIGN(TextBuffer);
152  };
153
154  // Contains extended information for HeapProfileTable::Bucket.  These objects
155  // are managed in a hash table (DeepBucketTable) whose key is an address of
156  // a Bucket and other additional information.
157  struct DeepBucket {
158   public:
159    void UnparseForStats(TextBuffer* buffer);
160    void UnparseForBucketFile(TextBuffer* buffer);
161
162    Bucket* bucket;
163#if defined(TYPE_PROFILING)
164    const std::type_info* type;  // A type of the object
165#endif
166    size_t committed_size;  // A resident size of this bucket
167    bool is_mmap;  // True if the bucket represents a mmap region
168    int id;  // A unique ID of the bucket
169    bool is_logged;  // True if the stracktrace is logged to a file
170    DeepBucket* next;  // A reference to the next entry in the hash table
171  };
172
173  // Manages a hash table for DeepBucket.
174  class DeepBucketTable {
175   public:
176    DeepBucketTable(int size,
177                    HeapProfileTable::Allocator alloc,
178                    HeapProfileTable::DeAllocator dealloc);
179    ~DeepBucketTable();
180
181    // Finds a DeepBucket instance corresponding to the given |bucket|, or
182    // creates a new DeepBucket object if it doesn't exist.
183    DeepBucket* Lookup(Bucket* bucket,
184#if defined(TYPE_PROFILING)
185                       const std::type_info* type,
186#endif
187                       bool is_mmap);
188
189    // Writes stats of the hash table to |buffer| for FillOrderedProfile.
190    void UnparseForStats(TextBuffer* buffer);
191
192    // Writes all buckets for a bucket file with using |buffer|.
193    void WriteForBucketFile(const char* prefix,
194                            int dump_count,
195                            TextBuffer* buffer);
196
197    // Resets 'committed_size' members in DeepBucket objects.
198    void ResetCommittedSize();
199
200    // Resets all 'is_loggeed' flags in DeepBucket objects.
201    void ResetIsLogged();
202
203   private:
204    // Adds |add| to a |hash_value| for Lookup.
205    inline static void AddToHashValue(uintptr_t add, uintptr_t* hash_value);
206    inline static void FinishHashValue(uintptr_t* hash_value);
207
208    DeepBucket** table_;
209    size_t table_size_;
210    HeapProfileTable::Allocator alloc_;
211    HeapProfileTable::DeAllocator dealloc_;
212    int bucket_id_;
213  };
214
215  class RegionStats {
216   public:
217    RegionStats(): virtual_bytes_(0), committed_bytes_(0) {}
218    ~RegionStats() {}
219
220    // Initializes 'virtual_bytes_' and 'committed_bytes_'.
221    void Initialize();
222
223    // Updates itself to contain the tallies of 'virtual_bytes' and
224    // 'committed_bytes' in the region from |first_adress| to |last_address|
225    // inclusive.
226    uint64 Record(
227        const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
228        uint64 first_address,
229        uint64 last_address);
230
231    // Writes stats of the region into |buffer| with |name|.
232    void Unparse(const char* name, TextBuffer* buffer);
233
234    size_t virtual_bytes() const { return virtual_bytes_; }
235    size_t committed_bytes() const { return committed_bytes_; }
236    void AddToVirtualBytes(size_t additional_virtual_bytes) {
237      virtual_bytes_ += additional_virtual_bytes;
238    }
239    void AddToCommittedBytes(size_t additional_committed_bytes) {
240      committed_bytes_ += additional_committed_bytes;
241    }
242    void AddAnotherRegionStat(const RegionStats& other) {
243      virtual_bytes_ += other.virtual_bytes_;
244      committed_bytes_ += other.committed_bytes_;
245    }
246
247   private:
248    size_t virtual_bytes_;
249    size_t committed_bytes_;
250    DISALLOW_COPY_AND_ASSIGN(RegionStats);
251  };
252
253  class GlobalStats {
254   public:
255    // Snapshots and calculates global stats from /proc/<pid>/maps and pagemap.
256    void SnapshotMaps(
257        const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
258        DeepHeapProfile* deep_profile,
259        TextBuffer* mmap_dump_buffer);
260
261    // Snapshots allocations by malloc and mmap.
262    void SnapshotAllocations(DeepHeapProfile* deep_profile);
263
264    // Writes global stats into |buffer|.
265    void Unparse(TextBuffer* buffer);
266
267  private:
268    // Records both virtual and committed byte counts of malloc and mmap regions
269    // as callback functions for AllocationMap::Iterate().
270    static void RecordAlloc(const void* pointer,
271                            AllocValue* alloc_value,
272                            DeepHeapProfile* deep_profile);
273
274    DeepBucket* GetInformationOfMemoryRegion(
275        const MemoryRegionMap::RegionIterator& mmap_iter,
276        const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
277        DeepHeapProfile* deep_profile);
278
279    // All RegionStats members in this class contain the bytes of virtual
280    // memory and committed memory.
281    // TODO(dmikurube): These regions should be classified more precisely later
282    // for more detailed analysis.
283    RegionStats all_[NUMBER_OF_MAPS_REGION_TYPES];
284
285    RegionStats unhooked_[NUMBER_OF_MAPS_REGION_TYPES];
286
287    // Total bytes of malloc'ed regions.
288    RegionStats profiled_malloc_;
289
290    // Total bytes of mmap'ed regions.
291    RegionStats profiled_mmap_;
292  };
293
294  // Writes reformatted /proc/<pid>/maps into a file "|prefix|.<pid>.maps"
295  // with using |raw_buffer| of |buffer_size|.
296  static void WriteProcMaps(const char* prefix,
297                            int buffer_size,
298                            char raw_buffer[]);
299
300  MemoryResidenceInfoGetterInterface* memory_residence_info_getter_;
301
302  // Process ID of the last dump.  This can change by fork.
303  pid_t most_recent_pid_;
304
305  GlobalStats stats_;      // Stats about total memory.
306  int dump_count_;         // The number of dumps.
307  char* filename_prefix_;  // Output file prefix.
308  char* profiler_buffer_;  // Buffer we use many times.
309
310  DeepBucketTable deep_table_;
311#endif  // USE_DEEP_HEAP_PROFILE
312
313  HeapProfileTable* heap_profile_;
314
315  DISALLOW_COPY_AND_ASSIGN(DeepHeapProfile);
316};
317
318#endif  // BASE_DEEP_HEAP_PROFILE_H_
319