OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015 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: Simon Que |
| 7 |
| 8 #ifndef _LEAK_DETECTOR_IMPL_H_ |
| 9 #define _LEAK_DETECTOR_IMPL_H_ |
| 10 |
| 11 #include "addressmap-inl.h" |
| 12 #include "base/basictypes.h" |
| 13 #include "heap-profile-stats.h" |
| 14 #include "leak_analyzer.h" |
| 15 |
| 16 namespace leak_detector { |
| 17 |
| 18 class CallStackTable; |
| 19 |
| 20 //---------------------------------------------------------------------- |
| 21 // Class that contains the actual leak detection mechanism. |
| 22 //---------------------------------------------------------------------- |
| 23 class LeakDetectorImpl { |
| 24 public: |
| 25 // Memory (de)allocator interface we'll use. |
| 26 typedef void* (*Allocator)(size_t size); |
| 27 typedef void (*DeAllocator)(void* ptr); |
| 28 |
| 29 // Used for tracking allocation stats. |
| 30 using Stats = HeapProfileStats; |
| 31 |
| 32 LeakDetectorImpl(Allocator alloc, DeAllocator dealloc, uint64 mapping_addr, |
| 33 uint64 mapping_size); |
| 34 ~LeakDetectorImpl(); |
| 35 |
| 36 // Indicates whether the given allocation size has an associated call stack |
| 37 // table, and thus requires a stack unwind. |
| 38 bool ShouldGetStackTraceForSize(size_t size) const; |
| 39 |
| 40 // Record allocs and frees. |
| 41 void RecordAlloc(const void* ptr, size_t size, |
| 42 int stack_depth, const void* const call_stack[]); |
| 43 void RecordFree(const void* ptr); |
| 44 |
| 45 const Stats& stats() const { |
| 46 return stats_; |
| 47 } |
| 48 |
| 49 // Run check for possible leaks based on the current profiling data. |
| 50 void TestForLeaks(); |
| 51 |
| 52 // Dump current profiling statistics to log. |
| 53 void DumpStats() const; |
| 54 |
| 55 private: |
| 56 // Used for tracking unique call stacks. |
| 57 using Bucket = HeapProfileBucket; |
| 58 |
| 59 // A record of allocations for a particular size. |
| 60 struct AllocSizeEntry { |
| 61 // Number of allocations and frees for this size. |
| 62 uint32 num_allocs; |
| 63 uint32 num_frees; |
| 64 |
| 65 // A stack table, if this size is being profiled for stack as well. |
| 66 CallStackTable* stack_table; |
| 67 }; |
| 68 |
| 69 // Info stored in the address map |
| 70 struct AllocInfo { |
| 71 AllocInfo() : bucket(NULL) {} |
| 72 |
| 73 // Number of bytes in this allocation. |
| 74 size_t bytes; |
| 75 |
| 76 // Points to a hash table bucket for a unique call stack. |
| 77 Bucket* bucket; |
| 78 }; |
| 79 |
| 80 // Used for recording size and call stack info for each allocation. |
| 81 using AllocationMap = AddressMap<AllocInfo>; |
| 82 |
| 83 // Number of entries in the alloc size table. As sizes are aligned to 32-bits |
| 84 // the max supported allocation size is (kNumSizeEntries * 4 - 1). Any larger |
| 85 // sizes are ignored. This value is chosen high enough that such large sizes |
| 86 // are rare if not nonexistent. |
| 87 static const int kNumSizeEntries = 2048; |
| 88 |
| 89 // The number of entries in the hash table for storing call stack buckets. |
| 90 // This does not represent the maximum number of unique call stacks that can |
| 91 // be supported. If there is a collision, multiple call stacks can be stored |
| 92 // in the same slot as a linked list. |
| 93 static const int kHashTableSize = 9973; |
| 94 |
| 95 // Converts an allocation size to/from the array index used for |entries_|. |
| 96 static int SizeToIndex(size_t size); |
| 97 static size_t IndexToSize(int index); |
| 98 |
| 99 // Accessor for the entry table. |
| 100 inline AllocSizeEntry* GetEntryForSize(size_t size) { |
| 101 return &entries_[SizeToIndex(size)]; |
| 102 } |
| 103 inline const AllocSizeEntry& GetConstEntryForSize(size_t size) const { |
| 104 return entries_[SizeToIndex(size)]; |
| 105 } |
| 106 |
| 107 // Returns a hash table bucket for a call stack. Each unique call stack has a |
| 108 // unique bucket. If the given call stack bucket has already been created by a |
| 109 // previous call to GetBucket(), return a pointer to that same call stack |
| 110 // bucket. |
| 111 Bucket* GetBucket(int depth, const void* const key[]); |
| 112 |
| 113 // Returns the offset of |ptr| within the current binary. If it is not in the |
| 114 // current binary, just return |ptr| as an integer. |
| 115 uint64 GetOffset(const void *ptr) const; |
| 116 |
| 117 // Functions for local allocations. |
| 118 Allocator alloc_; |
| 119 DeAllocator dealloc_; |
| 120 |
| 121 // Bucket hash table for tracking unique call stacks. |
| 122 Bucket* bucket_table_[kHashTableSize]; |
| 123 // Counter for the number of unique call stacks. |
| 124 int num_buckets_; |
| 125 |
| 126 // For tracking allocation stats. |
| 127 Stats stats_; |
| 128 Stats call_stack_stats_; |
| 129 int num_stack_tables_; |
| 130 |
| 131 // Stores all individual recorded allocations. |
| 132 AllocationMap address_map_; |
| 133 |
| 134 // Used to analyze potential leak patterns in the allocation sizes. |
| 135 LeakAnalyzer<uint32> size_leak_analyzer_; |
| 136 |
| 137 // Allocation stats for each size. |
| 138 AllocSizeEntry entries_[kNumSizeEntries]; |
| 139 |
| 140 // Address mapping info of the current binary. |
| 141 uint64 mapping_addr_; |
| 142 uint64 mapping_size_; |
| 143 |
| 144 DISALLOW_COPY_AND_ASSIGN(LeakDetectorImpl); |
| 145 }; |
| 146 |
| 147 } // namespace leak_detector |
| 148 |
| 149 #endif // _LEAK_DETECTOR_IMPL_H_ |
OLD | NEW |