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