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