OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 whether the memory |
| 15 // block is actually in memory, or not. DeepHeapProfile::FillOrderedProfile() |
| 16 // uses logged data in HeapProfileTable as one of its data sources. |
| 17 // DeepHeapProfile works only when its FillOrderedProfile() is called. It has |
| 18 // overhead when dumping, but no overhead when logging. |
| 19 // |
| 20 // It currently works only on Linux. It just delegates to HeapProfileTable in |
| 21 // non-Linux environments. |
| 22 |
| 23 |
| 24 #ifndef BASE_DEEP_HEAP_PROFILE_H_ |
| 25 #define BASE_DEEP_HEAP_PROFILE_H_ |
| 26 |
| 27 #include "config.h" |
| 28 |
| 29 #if defined(__linux__) |
| 30 #define DEEP_HEAP_PROFILE 1 |
| 31 #endif |
| 32 |
| 33 #include "addressmap-inl.h" |
| 34 #include "heap-profile-table.h" |
| 35 |
| 36 class DeepHeapProfile { |
| 37 public: |
| 38 typedef HeapProfileTable::Bucket Bucket; |
| 39 typedef HeapProfileTable::AllocationMap AllocationMap; |
| 40 typedef HeapProfileTable::AllocValue AllocValue; |
| 41 typedef HeapProfileTable::Stats Stats; |
| 42 |
| 43 // Construct a DeepHeapProfile instance. It works as a wrapper of |
| 44 // HeapProfileTable. |
| 45 // |
| 46 // 'heap_profile' is a pointer to HeapProfileTable. DeepHeapProfile reads |
| 47 // data in 'heap_profile' and forwards operations to 'heap_profile' if |
| 48 // DeepHeapProfile is not available (non-Linux). |
| 49 // 'prefix' is a prefix of dumped file names. |
| 50 DeepHeapProfile(HeapProfileTable* heap_profile, const char* prefix); |
| 51 ~DeepHeapProfile(); |
| 52 |
| 53 // Fill deep profile data into buffer 'buf' of size 'size', and return the |
| 54 // actual size occupied by the dump in 'buf'. It works as an alternative of |
| 55 // HeapProfileTable::FillOrderedProfile. |
| 56 // |
| 57 // The profile buckets are dumped in the decreasing order of currently |
| 58 // allocated bytes. We do not provision for 0-terminating 'buf'. |
| 59 int FillOrderedProfile(char buf[], int size); |
| 60 |
| 61 private: |
| 62 #ifdef DEEP_HEAP_PROFILE |
| 63 struct DeepBucket { |
| 64 Bucket* bucket; |
| 65 size_t committed_size; |
| 66 int id; // Unique ID of the bucket. |
| 67 bool is_logged; // True if the stracktrace is logged to a file. |
| 68 }; |
| 69 |
| 70 typedef AddressMap<DeepBucket> DeepBucketMap; |
| 71 |
| 72 struct PageState { |
| 73 bool is_committed; // Currently, we use only this |
| 74 bool is_present; |
| 75 bool is_swapped; |
| 76 bool is_shared; |
| 77 bool is_mmap; |
| 78 }; |
| 79 |
| 80 struct RegionStats { |
| 81 size_t virtual_bytes; |
| 82 size_t committed_bytes; |
| 83 }; |
| 84 |
| 85 struct GlobalStats { |
| 86 RegionStats total; |
| 87 RegionStats file_mapped; |
| 88 RegionStats anonymous; |
| 89 RegionStats other; |
| 90 RegionStats record_mmap; |
| 91 RegionStats record_tcmalloc; |
| 92 }; |
| 93 |
| 94 struct BufferArgs { |
| 95 char* buf; |
| 96 int size; |
| 97 int len; |
| 98 }; |
| 99 |
| 100 // Get the DeepBucket object corresponding to the given 'bucket'. |
| 101 // DeepBucket is an extension to Bucket which is declared above. |
| 102 DeepBucket* GetDeepBucket(Bucket* bucket); |
| 103 |
| 104 // Reset committed_size member variables in DeepBucket objects to 0. |
| 105 void ResetCommittedSize(Bucket** table); |
| 106 |
| 107 // Fill bucket data in 'table' into buffer 'buf' of size 'size', and return |
| 108 // the size occupied by the bucket data in 'buf'. 'bucket_length' is the |
| 109 // offset for 'buf' to start filling. Statistics in 'stats' is updated if |
| 110 // it's not NULL. |
| 111 int FillBucketTable(Bucket** table, char buf[], int size, int bucket_length, |
| 112 HeapProfileTable::Stats* stats); |
| 113 |
| 114 // Open /proc/pid/pagemap and store its file descriptor in pagemap_fd_. |
| 115 void OpenProcPagemap(); |
| 116 |
| 117 // Seek the offset of the open pagemap file pagemap_fd_. |
| 118 bool SeekProcPagemap(uint64 addr); |
| 119 |
| 120 // Read a pagemap state from the current pagemap_fd_ offset. |
| 121 bool ReadProcPagemap(PageState* state); |
| 122 |
| 123 // Get a committed (resident + swapped) size in the memory region |
| 124 // from 'addr' to 'addr + size'. |
| 125 size_t GetCommittedSize(uint64 addr, size_t size); |
| 126 |
| 127 // Initialize 'virtual_bytes' and 'committed_bytes' in RegionStats. |
| 128 void InitRegionStats(RegionStats* stats); |
| 129 |
| 130 // Add the virtual size (end - start) and the committed size in the region |
| 131 // to 'stats'. |
| 132 void RecordRegionStats(uint64 start, uint64 end, RegionStats* stats); |
| 133 |
| 134 // Compute the global statistics from /proc/self/maps and pagemap, and |
| 135 // store them in stats_. |
| 136 void GetGlobalStats(); |
| 137 |
| 138 // Record the committed memory size of each allocation and mmap. |
| 139 static void RecordAlloc(const void* ptr, AllocValue* v, |
| 140 DeepHeapProfile* deep_profile); |
| 141 static void RecordMMap(const void* ptr, AllocValue* v, |
| 142 DeepHeapProfile* deep_profile); |
| 143 void RecordAllAllocs(); |
| 144 |
| 145 // Fill re-formatted /proc/self/maps into 'buf' of size 'size'. |
| 146 void WriteMapsToFile(char buf[], int size); |
| 147 |
| 148 // Fill a bucket (a bucket id and its corresponding calling stack) into 'buf' |
| 149 // of size 'bufsize'. |
| 150 int FillBucketForBucketFile(const DeepBucket* db, char buf[], int bufsize); |
| 151 |
| 152 // Write a bucket table 'table' into a file of 'bucket_fd'. |
| 153 void WriteBucketsTableToBucketFile(Bucket** table, RawFD bucket_fd); |
| 154 |
| 155 // Write both malloc and mmap bucket tables into "a bucket file". |
| 156 void WriteBucketsToBucketFile(); |
| 157 |
| 158 // Fill a (deep) bucket into 'buf' from the offset 'buflen'. Add the sizes |
| 159 // to 'profile_stats' if it's not NULL. |
| 160 static int UnparseBucket(const DeepBucket& b, |
| 161 char* buf, int buflen, int bufsize, |
| 162 const char* extra, |
| 163 Stats* profile_stats); |
| 164 |
| 165 // Fill statistics of a region into 'buf'. |
| 166 static int UnparseRegionStats(const RegionStats* stats, const char* name, |
| 167 char* buf, int buflen, int bufsize); |
| 168 |
| 169 // Fill global statistics into 'buf'. |
| 170 int UnparseGlobalStats(char* buf, int buflen, int bufsize); |
| 171 |
| 172 #endif // DEEP_HEAP_PROFILE |
| 173 HeapProfileTable* heap_profile_; |
| 174 #ifdef DEEP_HEAP_PROFILE |
| 175 |
| 176 int pagemap_fd_; // File descriptor of /proc/self/pagemap. |
| 177 pid_t most_recent_pid_; // Process ID of the last dump. This could change. |
| 178 GlobalStats stats_; // Stats about total memory. |
| 179 int dump_count_; // The number of dumps. |
| 180 char* filename_prefix_; // Output file prefix. |
| 181 char* profiler_buffer_; // Buffer we use many times. |
| 182 |
| 183 int bucket_id_; |
| 184 DeepBucketMap* deep_bucket_map_; |
| 185 #endif // DEEP_HEAP_PROFILE |
| 186 |
| 187 DISALLOW_COPY_AND_ASSIGN(DeepHeapProfile); |
| 188 }; |
| 189 |
| 190 #endif // BASE_DEEP_HEAP_PROFILE_H_ |
OLD | NEW |