OLD | NEW |
1 // Copyright (c) 2006, Google Inc. | 1 // Copyright (c) 2006, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 int64 alloc_size; // Total size of all allocated objects so far | 64 int64 alloc_size; // Total size of all allocated objects so far |
65 int64 free_size; // Total size of all freed objects so far | 65 int64 free_size; // Total size of all freed objects so far |
66 | 66 |
67 // semantic equality | 67 // semantic equality |
68 bool Equivalent(const Stats& x) const { | 68 bool Equivalent(const Stats& x) const { |
69 return allocs - frees == x.allocs - x.frees && | 69 return allocs - frees == x.allocs - x.frees && |
70 alloc_size - free_size == x.alloc_size - x.free_size; | 70 alloc_size - free_size == x.alloc_size - x.free_size; |
71 } | 71 } |
72 }; | 72 }; |
73 | 73 |
| 74 // Possible marks for MarkCurrentAllocations and MarkUnmarkedAllocations. New |
| 75 // allocations are marked with UNMARKED by default. |
| 76 enum AllocationMark { |
| 77 UNMARKED = 0, |
| 78 MARK_ONE, |
| 79 MARK_TWO, |
| 80 MARK_THREE |
| 81 }; |
| 82 |
74 // Info we can return about an allocation. | 83 // Info we can return about an allocation. |
75 struct AllocInfo { | 84 struct AllocInfo { |
76 size_t object_size; // size of the allocation | 85 size_t object_size; // size of the allocation |
77 const void* const* call_stack; // call stack that made the allocation call | 86 const void* const* call_stack; // call stack that made the allocation call |
78 int stack_depth; // depth of call_stack | 87 int stack_depth; // depth of call_stack |
79 bool live; | 88 bool live; |
80 bool ignored; | 89 bool ignored; |
81 }; | 90 }; |
82 | 91 |
83 // Info we return about an allocation context. | 92 // Info we return about an allocation context. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 // If "ptr" points to a recorded allocation and it's not marked as live | 140 // If "ptr" points to a recorded allocation and it's not marked as live |
132 // mark it as live and return true. Else return false. | 141 // mark it as live and return true. Else return false. |
133 // All allocations start as non-live. | 142 // All allocations start as non-live. |
134 bool MarkAsLive(const void* ptr); | 143 bool MarkAsLive(const void* ptr); |
135 | 144 |
136 // If "ptr" points to a recorded allocation, mark it as "ignored". | 145 // If "ptr" points to a recorded allocation, mark it as "ignored". |
137 // Ignored objects are treated like other objects, except that they | 146 // Ignored objects are treated like other objects, except that they |
138 // are skipped in heap checking reports. | 147 // are skipped in heap checking reports. |
139 void MarkAsIgnored(const void* ptr); | 148 void MarkAsIgnored(const void* ptr); |
140 | 149 |
| 150 // Mark all currently known allocations with the given AllocationMark. |
| 151 void MarkCurrentAllocations(AllocationMark mark); |
| 152 |
| 153 // Mark all unmarked (i.e. marked with AllocationMark::UNMARKED) with the |
| 154 // given mark. |
| 155 void MarkUnmarkedAllocations(AllocationMark mark); |
| 156 |
141 // Return current total (de)allocation statistics. It doesn't contain | 157 // Return current total (de)allocation statistics. It doesn't contain |
142 // mmap'ed regions. | 158 // mmap'ed regions. |
143 const Stats& total() const { return total_; } | 159 const Stats& total() const { return total_; } |
144 | 160 |
145 // Allocation data iteration callback: gets passed object pointer and | 161 // Allocation data iteration callback: gets passed object pointer and |
146 // fully-filled AllocInfo. | 162 // fully-filled AllocInfo. |
147 typedef void (*AllocIterator)(const void* ptr, const AllocInfo& info); | 163 typedef void (*AllocIterator)(const void* ptr, const AllocInfo& info); |
148 | 164 |
149 // Iterate over the allocation profile data calling "callback" | 165 // Iterate over the allocation profile data calling "callback" |
150 // for every allocation. | 166 // for every allocation. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 // They are introduced to avoid expected memory fragmentation and bloat in | 212 // They are introduced to avoid expected memory fragmentation and bloat in |
197 // an arena. A dedicated arena for this function allows disposing whole the | 213 // an arena. A dedicated arena for this function allows disposing whole the |
198 // arena after ClearMMapData. | 214 // arena after ClearMMapData. |
199 void RefreshMMapData(Allocator mmap_alloc, DeAllocator mmap_dealloc); | 215 void RefreshMMapData(Allocator mmap_alloc, DeAllocator mmap_dealloc); |
200 | 216 |
201 // Clear the internal mmap information. Results of FillOrderedProfile and | 217 // Clear the internal mmap information. Results of FillOrderedProfile and |
202 // IterateOrderedAllocContexts won't contain mmap'ed memory regions after | 218 // IterateOrderedAllocContexts won't contain mmap'ed memory regions after |
203 // calling ClearMMapData. | 219 // calling ClearMMapData. |
204 void ClearMMapData(); | 220 void ClearMMapData(); |
205 | 221 |
| 222 // Dump a list of allocations marked as "live" along with their creation |
| 223 // stack traces and sizes to a file named |file_name|. Together with |
| 224 // MarkCurrentAllocatiosn and MarkUnmarkedAllocations this can be used |
| 225 // to find objects that are created in a certain time span: |
| 226 // 1. Invoke MarkCurrentAllocations(MARK_ONE) to mark the start of the |
| 227 // timespan. |
| 228 // 2. Perform whatever action you suspect allocates memory that is not |
| 229 // correctly freed. |
| 230 // 3. Invoke MarkUnmarkedAllocations(MARK_TWO). |
| 231 // 4. Perform whatever action is supposed to free the memory again. New |
| 232 // allocations are not marked. So all allocations that are marked as |
| 233 // "live" where created during step 2. |
| 234 // 5. Invoke DumpMarkedObjects(MARK_TWO) to get the list of allocations that |
| 235 // were created during step 2, but survived step 4. |
| 236 // |
| 237 // Note that this functionality cannot be used if the HeapProfileTable is |
| 238 // used for leak checking (using HeapLeakChecker). |
| 239 void DumpMarkedObjects(AllocationMark mark, const char* file_name); |
| 240 |
206 private: | 241 private: |
207 friend class DeepHeapProfile; | 242 friend class DeepHeapProfile; |
208 | 243 |
209 // data types ---------------------------- | 244 // data types ---------------------------- |
210 | 245 |
211 // Hash table bucket to hold (de)allocation stats | 246 // Hash table bucket to hold (de)allocation stats |
212 // for a given allocation call stack trace. | 247 // for a given allocation call stack trace. |
213 struct Bucket : public Stats { | 248 struct Bucket : public Stats { |
214 uintptr_t hash; // Hash value of the stack trace | 249 uintptr_t hash; // Hash value of the stack trace |
215 int depth; // Depth of stack trace | 250 int depth; // Depth of stack trace |
(...skipping 15 matching lines...) Expand all Loading... |
231 bool live() const { return bucket_rep & kLive; } | 266 bool live() const { return bucket_rep & kLive; } |
232 void set_live(bool l) { | 267 void set_live(bool l) { |
233 bucket_rep = (bucket_rep & ~uintptr_t(kLive)) | (l ? kLive : 0); | 268 bucket_rep = (bucket_rep & ~uintptr_t(kLive)) | (l ? kLive : 0); |
234 } | 269 } |
235 | 270 |
236 // Should this allocation be ignored if it looks like a leak? | 271 // Should this allocation be ignored if it looks like a leak? |
237 bool ignore() const { return bucket_rep & kIgnore; } | 272 bool ignore() const { return bucket_rep & kIgnore; } |
238 void set_ignore(bool r) { | 273 void set_ignore(bool r) { |
239 bucket_rep = (bucket_rep & ~uintptr_t(kIgnore)) | (r ? kIgnore : 0); | 274 bucket_rep = (bucket_rep & ~uintptr_t(kIgnore)) | (r ? kIgnore : 0); |
240 } | 275 } |
| 276 AllocationMark mark() const { |
| 277 return static_cast<AllocationMark>(bucket_rep & uintptr_t(kMask)); |
| 278 } |
| 279 void set_mark(AllocationMark mark) { |
| 280 bucket_rep = (bucket_rep & ~uintptr_t(kMask)) | uintptr_t(mark); |
| 281 } |
241 | 282 |
242 private: | 283 private: |
243 // We store a few bits in the bottom bits of bucket_rep. | 284 // We store a few bits in the bottom bits of bucket_rep. |
244 // (Alignment is at least four, so we have at least two bits.) | 285 // (Alignment is at least four, so we have at least two bits.) |
245 static const int kLive = 1; | 286 static const int kLive = 1; |
246 static const int kIgnore = 2; | 287 static const int kIgnore = 2; |
247 static const int kMask = kLive | kIgnore; | 288 static const int kMask = kLive | kIgnore; |
248 | 289 |
249 uintptr_t bucket_rep; | 290 uintptr_t bucket_rep; |
250 }; | 291 }; |
251 | 292 |
252 // helper for FindInsideAlloc | 293 // helper for FindInsideAlloc |
253 static size_t AllocValueSize(const AllocValue& v) { return v.bytes; } | 294 static size_t AllocValueSize(const AllocValue& v) { return v.bytes; } |
254 | 295 |
255 typedef AddressMap<AllocValue> AllocationMap; | 296 typedef AddressMap<AllocValue> AllocationMap; |
256 | 297 |
257 // Arguments that need to be passed DumpNonLiveIterator callback below. | 298 // Arguments that need to be passed DumpNonLiveIterator callback below. |
258 struct DumpArgs { | 299 struct DumpArgs { |
259 RawFD fd; // file to write to | 300 RawFD fd; // file to write to |
260 Stats* profile_stats; // stats to update (may be NULL) | 301 Stats* profile_stats; // stats to update (may be NULL) |
261 | 302 |
262 DumpArgs(RawFD a, Stats* d) | 303 DumpArgs(RawFD a, Stats* d) |
263 : fd(a), profile_stats(d) { } | 304 : fd(a), profile_stats(d) { } |
264 }; | 305 }; |
265 | 306 |
| 307 // Arguments that need to be passed DumpMarkedIterator callback below. |
| 308 struct DumpMarkedArgs { |
| 309 RawFD fd; // file to write to. |
| 310 AllocationMark mark; // The mark of the allocations to process. |
| 311 |
| 312 DumpMarkedArgs(RawFD a, AllocationMark m) : fd(a), mark(m) { } |
| 313 }; |
| 314 |
| 315 // Arguments that need to be passed MarkIterator callback below. |
| 316 struct MarkArgs { |
| 317 AllocationMark mark; // The mark to put on allocations. |
| 318 bool mark_all; // True if all allocations should be marked. Otherwise just |
| 319 // mark unmarked allocations. |
| 320 |
| 321 MarkArgs(AllocationMark m, bool a) : mark(m), mark_all(a) { } |
| 322 }; |
| 323 |
266 // helpers ---------------------------- | 324 // helpers ---------------------------- |
267 | 325 |
268 // Unparse bucket b and print its portion of profile dump into buf. | 326 // Unparse bucket b and print its portion of profile dump into buf. |
269 // We return the amount of space in buf that we use. We start printing | 327 // We return the amount of space in buf that we use. We start printing |
270 // at buf + buflen, and promise not to go beyond buf + bufsize. | 328 // at buf + buflen, and promise not to go beyond buf + bufsize. |
271 // We do not provision for 0-terminating 'buf'. | 329 // We do not provision for 0-terminating 'buf'. |
272 // | 330 // |
273 // If profile_stats is non-NULL, we update *profile_stats by | 331 // If profile_stats is non-NULL, we update *profile_stats by |
274 // counting bucket b. | 332 // counting bucket b. |
275 // | 333 // |
(...skipping 24 matching lines...) Expand all Loading... |
300 AllocIterator callback) { | 358 AllocIterator callback) { |
301 AllocInfo info; | 359 AllocInfo info; |
302 info.object_size = v->bytes; | 360 info.object_size = v->bytes; |
303 info.call_stack = v->bucket()->stack; | 361 info.call_stack = v->bucket()->stack; |
304 info.stack_depth = v->bucket()->depth; | 362 info.stack_depth = v->bucket()->depth; |
305 info.live = v->live(); | 363 info.live = v->live(); |
306 info.ignored = v->ignore(); | 364 info.ignored = v->ignore(); |
307 callback(ptr, info); | 365 callback(ptr, info); |
308 } | 366 } |
309 | 367 |
| 368 // Helper for MarkCurrentAllocations and MarkUnmarkedAllocations. |
| 369 inline static void MarkIterator(const void* ptr, AllocValue* v, |
| 370 const MarkArgs& args); |
| 371 |
310 // Helper for DumpNonLiveProfile to do object-granularity | 372 // Helper for DumpNonLiveProfile to do object-granularity |
311 // heap profile dumping. It gets passed to AllocationMap::Iterate. | 373 // heap profile dumping. It gets passed to AllocationMap::Iterate. |
312 inline static void DumpNonLiveIterator(const void* ptr, AllocValue* v, | 374 inline static void DumpNonLiveIterator(const void* ptr, AllocValue* v, |
313 const DumpArgs& args); | 375 const DumpArgs& args); |
314 | 376 |
| 377 // Helper for DumpMarkedObjects to dump all allocations with a given mark. It |
| 378 // gets passed to AllocationMap::Iterate. |
| 379 inline static void DumpMarkedIterator(const void* ptr, AllocValue* v, |
| 380 const DumpMarkedArgs& args); |
| 381 |
315 // Helper for filling size variables in buckets by zero. | 382 // Helper for filling size variables in buckets by zero. |
316 inline static void ZeroBucketCountsIterator( | 383 inline static void ZeroBucketCountsIterator( |
317 const void* ptr, AllocValue* v, HeapProfileTable* heap_profile); | 384 const void* ptr, AllocValue* v, HeapProfileTable* heap_profile); |
318 | 385 |
319 // Helper for IterateOrderedAllocContexts and FillOrderedProfile. | 386 // Helper for IterateOrderedAllocContexts and FillOrderedProfile. |
320 // Creates a sorted list of Buckets whose length is num_alloc_buckets_ + | 387 // Creates a sorted list of Buckets whose length is num_alloc_buckets_ + |
321 // num_avaliable_mmap_buckets_. | 388 // num_avaliable_mmap_buckets_. |
322 // The caller is responsible for deallocating the returned list. | 389 // The caller is responsible for deallocating the returned list. |
323 Bucket** MakeSortedBucketList() const; | 390 Bucket** MakeSortedBucketList() const; |
324 | 391 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 // Helpers for sorting and generating leak reports | 487 // Helpers for sorting and generating leak reports |
421 struct Entry; | 488 struct Entry; |
422 struct ReportState; | 489 struct ReportState; |
423 static void ReportCallback(const void* ptr, AllocValue* v, ReportState*); | 490 static void ReportCallback(const void* ptr, AllocValue* v, ReportState*); |
424 static void ReportObject(const void* ptr, AllocValue* v, char*); | 491 static void ReportObject(const void* ptr, AllocValue* v, char*); |
425 | 492 |
426 DISALLOW_COPY_AND_ASSIGN(Snapshot); | 493 DISALLOW_COPY_AND_ASSIGN(Snapshot); |
427 }; | 494 }; |
428 | 495 |
429 #endif // BASE_HEAP_PROFILE_TABLE_H_ | 496 #endif // BASE_HEAP_PROFILE_TABLE_H_ |
OLD | NEW |