OLD | NEW |
(Empty) | |
| 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 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| of |size|, and return the actual |
| 54 // size occupied by the dump in |buffer|. It works as an alternative |
| 55 // of 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 |buffer|. |
| 59 int FillOrderedProfile(char buffer[], int buffer_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 class RegionStats { |
| 81 public: |
| 82 RegionStats() {} |
| 83 ~RegionStats() {} |
| 84 |
| 85 // Initialize virtual_bytes and committed_bytes. |
| 86 void Initialize(); |
| 87 |
| 88 // Update the RegionStats to include the tallies of virtual_bytes and |
| 89 // committed_bytes in the region from |first_adress| to |last_address| |
| 90 // inclusive. |
| 91 void Record(int pagemap_fd, uint64 first_address, uint64 last_address); |
| 92 |
| 93 size_t virtual_bytes() const { return virtual_bytes_; } |
| 94 size_t committed_bytes() const { return committed_bytes_; } |
| 95 void set_virtual_bytes(size_t virtual_bytes) { |
| 96 virtual_bytes_ = virtual_bytes; |
| 97 } |
| 98 void set_committed_bytes(size_t committed_bytes) { |
| 99 committed_bytes_ = committed_bytes; |
| 100 } |
| 101 void AddToVirtualBytes(size_t additional_virtual_bytes) { |
| 102 virtual_bytes_ += additional_virtual_bytes; |
| 103 } |
| 104 void AddToCommittedBytes(size_t additional_committed_bytes) { |
| 105 committed_bytes_ += additional_committed_bytes; |
| 106 } |
| 107 |
| 108 private: |
| 109 size_t virtual_bytes_; |
| 110 size_t committed_bytes_; |
| 111 DISALLOW_COPY_AND_ASSIGN(RegionStats); |
| 112 }; |
| 113 |
| 114 struct GlobalStats { |
| 115 // All RegionStats members in this class contain the bytes of virtual |
| 116 // memory and committed memory. |
| 117 // TODO(dmikurube): These regions should be classified more precisely later |
| 118 // for more detailed analysis. |
| 119 |
| 120 // Total bytes of the process memory. |
| 121 RegionStats total; |
| 122 |
| 123 // Total bytes of memory which is mapped to a file. |
| 124 // Regions which contain file paths in the last column of /proc/<pid>/maps. |
| 125 RegionStats file_mapped; |
| 126 |
| 127 // Total bytes of memory which is mapped anonymously. |
| 128 // Regions which contain nothing in the last column of /proc/<pid>/maps. |
| 129 RegionStats anonymous; |
| 130 |
| 131 // Total bytes of memory which is labeled, but not mapped to any file. |
| 132 // Regions which contain non-path strings in the last column of |
| 133 // /proc/<pid>/maps. |
| 134 RegionStats other; |
| 135 |
| 136 // Total bytes of mmap'ed regions. |
| 137 RegionStats record_mmap; |
| 138 |
| 139 // Total bytes of malloc'ed regions. |
| 140 RegionStats record_malloc; |
| 141 }; |
| 142 |
| 143 // Checks if the length of |printed| characters by snprintf is valid. |
| 144 static bool IsPrintedStringValid(int printed, |
| 145 int buffer_size, |
| 146 int used_in_buffer); |
| 147 |
| 148 // Clear the is_logged flag in a DeepBucket object as a callback function |
| 149 // for DeepBucketMap::Iterate(). |
| 150 static void ClearIsLogged(const void* pointer, |
| 151 DeepBucket* db, |
| 152 DeepHeapProfile* deep_profile); |
| 153 |
| 154 // Open /proc/pid/pagemap and return its file descriptor. |
| 155 // File descriptors need to be refreshed after each fork. |
| 156 static int OpenProcPagemap(); |
| 157 |
| 158 // Seek to the offset of the open pagemap file pagemap_fd. |
| 159 // It returns true if succeeded. Otherwise, it returns false. |
| 160 static bool SeekProcPagemap(int pagemap_fd, uint64 address); |
| 161 |
| 162 // Read a pagemap state from the current pagemap_fd offset. |
| 163 // It returns true if succeeded. Otherwise, it returns false. |
| 164 static bool ReadProcPagemap(int pagemap_fd, PageState* state); |
| 165 |
| 166 // Returns the number of resident (including swapped) bytes of the memory |
| 167 // region starting at |first_address| and ending at |last_address| inclusive. |
| 168 static size_t GetCommittedSize(int pagemap_fd, |
| 169 uint64 first_address, |
| 170 uint64 last_address); |
| 171 |
| 172 // Write re-formatted /proc/self/maps into a file which has |filename_prefix| |
| 173 // with using |buffer| of size |buffer_size|. |
| 174 static void WriteMapsToFile(const char* filename_prefix, |
| 175 int buffer_size, |
| 176 char buffer[]); |
| 177 |
| 178 // Compute the global statistics from /proc/self/maps and |pagemap_fd|, and |
| 179 // store the statistics in |stats|. |
| 180 static void SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, |
| 181 GlobalStats* stats); |
| 182 |
| 183 // Get the DeepBucket object corresponding to the given |bucket|. |
| 184 // DeepBucket is an extension to Bucket which is declared above. |
| 185 DeepBucket* GetDeepBucket(Bucket* bucket); |
| 186 |
| 187 // Reset committed_size member variables in DeepBucket objects to 0. |
| 188 void ResetCommittedSize(Bucket** bucket_table); |
| 189 |
| 190 // Fill bucket data in |bucket_table| into buffer |buffer| of size |
| 191 // |buffer_size|, and return the size occupied by the bucket data in |
| 192 // |buffer|. |bucket_length| is the offset for |buffer| to start filling. |
| 193 int SnapshotBucketTableWithoutMalloc(Bucket** bucket_table, |
| 194 int used_in_buffer, |
| 195 int buffer_size, |
| 196 char buffer[]); |
| 197 |
| 198 // Record both virtual and committed byte counts of malloc and mmap regions |
| 199 // as callback functions for AllocationMap::Iterate(). |
| 200 static void RecordAlloc(const void* pointer, |
| 201 AllocValue* alloc_value, |
| 202 DeepHeapProfile* deep_profile); |
| 203 static void RecordMMap(const void* pointer, |
| 204 AllocValue* alloc_value, |
| 205 DeepHeapProfile* deep_profile); |
| 206 void SnapshotAllAllocsWithoutMalloc(); |
| 207 |
| 208 // Fill a bucket (a bucket id and its corresponding calling stack) into |
| 209 // |buffer| of size |buffer_size|. |
| 210 int FillBucketForBucketFile(const DeepBucket* deep_bucket, |
| 211 int buffer_size, |
| 212 char buffer[]); |
| 213 |
| 214 // Write a |bucket_table| into a file of |bucket_fd|. |
| 215 void WriteBucketsTableToBucketFile(Bucket** bucket_table, RawFD bucket_fd); |
| 216 |
| 217 // Write both malloc and mmap bucket tables into a "bucket file". |
| 218 void WriteBucketsToBucketFile(); |
| 219 |
| 220 // Fill a |deep_bucket| and its corresponding bucket into |buffer| from the |
| 221 // offset |used_in_buffer|. Add the sizes to |profile_stats| if it's not |
| 222 // NULL. |
| 223 static int UnparseBucket(const DeepBucket& deep_bucket, |
| 224 const char* extra, |
| 225 int used_in_buffer, |
| 226 int buffer_size, |
| 227 char* buffer, |
| 228 Stats* profile_stats); |
| 229 |
| 230 // Fill statistics of a region into |buffer|. |
| 231 static int UnparseRegionStats(const RegionStats* stats, |
| 232 const char* name, |
| 233 int used_in_buffer, |
| 234 int buffer_size, |
| 235 char* buffer); |
| 236 |
| 237 // Fill global statistics into |buffer|. |
| 238 int UnparseGlobalStats(int used_in_buffer, int buffer_size, char* buffer); |
| 239 |
| 240 int pagemap_fd_; // File descriptor of /proc/self/pagemap. |
| 241 |
| 242 // Process ID of the last dump. This could change by fork. |
| 243 pid_t most_recent_pid_; |
| 244 GlobalStats stats_; // Stats about total memory. |
| 245 int dump_count_; // The number of dumps. |
| 246 char* filename_prefix_; // Output file prefix. |
| 247 char* profiler_buffer_; // Buffer we use many times. |
| 248 |
| 249 int bucket_id_; |
| 250 DeepBucketMap* deep_bucket_map_; |
| 251 #endif // DEEP_HEAP_PROFILE |
| 252 |
| 253 HeapProfileTable* heap_profile_; |
| 254 |
| 255 DISALLOW_COPY_AND_ASSIGN(DeepHeapProfile); |
| 256 }; |
| 257 |
| 258 #endif // BASE_DEEP_HEAP_PROFILE_H_ |
OLD | NEW |