OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/thread_heap_usage_tracker.h" | 5 #include "base/debug/thread_heap_usage_tracker.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 #include <limits> | 9 #include <limits> |
10 #include <new> | 10 #include <new> |
(...skipping 25 matching lines...) Expand all Loading... |
36 reinterpret_cast<ThreadHeapUsage*>(kSentinelMask); | 36 reinterpret_cast<ThreadHeapUsage*>(kSentinelMask); |
37 ThreadHeapUsage* const kTeardownSentinel = | 37 ThreadHeapUsage* const kTeardownSentinel = |
38 reinterpret_cast<ThreadHeapUsage*>(kSentinelMask | 1); | 38 reinterpret_cast<ThreadHeapUsage*>(kSentinelMask | 1); |
39 | 39 |
40 bool g_heap_tracking_enabled = false; | 40 bool g_heap_tracking_enabled = false; |
41 | 41 |
42 // Forward declared as it needs to delegate memory allocation to the next | 42 // Forward declared as it needs to delegate memory allocation to the next |
43 // lower shim. | 43 // lower shim. |
44 ThreadHeapUsage* GetOrCreateThreadUsage(); | 44 ThreadHeapUsage* GetOrCreateThreadUsage(); |
45 | 45 |
46 size_t GetAllocSizeEstimate(const AllocatorDispatch* next, void* ptr) { | 46 size_t GetAllocSizeEstimate(const AllocatorDispatch* next, |
| 47 void* ptr, |
| 48 void* context) { |
47 if (ptr == nullptr) | 49 if (ptr == nullptr) |
48 return 0U; | 50 return 0U; |
49 | 51 |
50 return next->get_size_estimate_function(next, ptr); | 52 return next->get_size_estimate_function(next, ptr, context); |
51 } | 53 } |
52 | 54 |
53 void RecordAlloc(const AllocatorDispatch* next, void* ptr, size_t size) { | 55 void RecordAlloc(const AllocatorDispatch* next, |
| 56 void* ptr, |
| 57 size_t size, |
| 58 void* context) { |
54 ThreadHeapUsage* usage = GetOrCreateThreadUsage(); | 59 ThreadHeapUsage* usage = GetOrCreateThreadUsage(); |
55 if (usage == nullptr) | 60 if (usage == nullptr) |
56 return; | 61 return; |
57 | 62 |
58 usage->alloc_ops++; | 63 usage->alloc_ops++; |
59 size_t estimate = GetAllocSizeEstimate(next, ptr); | 64 size_t estimate = GetAllocSizeEstimate(next, ptr, context); |
60 if (size && estimate) { | 65 if (size && estimate) { |
61 // Only keep track of the net number of bytes allocated in the scope if the | 66 // Only keep track of the net number of bytes allocated in the scope if the |
62 // size estimate function returns sane values, e.g. non-zero. | 67 // size estimate function returns sane values, e.g. non-zero. |
63 usage->alloc_bytes += estimate; | 68 usage->alloc_bytes += estimate; |
64 usage->alloc_overhead_bytes += estimate - size; | 69 usage->alloc_overhead_bytes += estimate - size; |
65 | 70 |
66 // Record the max outstanding number of bytes, but only if the difference | 71 // Record the max outstanding number of bytes, but only if the difference |
67 // is net positive (e.g. more bytes allocated than freed in the scope). | 72 // is net positive (e.g. more bytes allocated than freed in the scope). |
68 if (usage->alloc_bytes > usage->free_bytes) { | 73 if (usage->alloc_bytes > usage->free_bytes) { |
69 uint64_t allocated_bytes = usage->alloc_bytes - usage->free_bytes; | 74 uint64_t allocated_bytes = usage->alloc_bytes - usage->free_bytes; |
70 if (allocated_bytes > usage->max_allocated_bytes) | 75 if (allocated_bytes > usage->max_allocated_bytes) |
71 usage->max_allocated_bytes = allocated_bytes; | 76 usage->max_allocated_bytes = allocated_bytes; |
72 } | 77 } |
73 } else { | 78 } else { |
74 usage->alloc_bytes += size; | 79 usage->alloc_bytes += size; |
75 } | 80 } |
76 } | 81 } |
77 | 82 |
78 void RecordFree(const AllocatorDispatch* next, void* ptr) { | 83 void RecordFree(const AllocatorDispatch* next, void* ptr, void* context) { |
79 ThreadHeapUsage* usage = GetOrCreateThreadUsage(); | 84 ThreadHeapUsage* usage = GetOrCreateThreadUsage(); |
80 if (usage == nullptr) | 85 if (usage == nullptr) |
81 return; | 86 return; |
82 | 87 |
83 size_t estimate = GetAllocSizeEstimate(next, ptr); | 88 size_t estimate = GetAllocSizeEstimate(next, ptr, context); |
84 usage->free_ops++; | 89 usage->free_ops++; |
85 usage->free_bytes += estimate; | 90 usage->free_bytes += estimate; |
86 } | 91 } |
87 | 92 |
88 void* AllocFn(const AllocatorDispatch* self, size_t size) { | 93 void* AllocFn(const AllocatorDispatch* self, size_t size, void* context) { |
89 void* ret = self->next->alloc_function(self->next, size); | 94 void* ret = self->next->alloc_function(self->next, size, context); |
90 if (ret != nullptr) | 95 if (ret != nullptr) |
91 RecordAlloc(self->next, ret, size); | 96 RecordAlloc(self->next, ret, size, context); |
92 | 97 |
93 return ret; | 98 return ret; |
94 } | 99 } |
95 | 100 |
96 void* AllocZeroInitializedFn(const AllocatorDispatch* self, | 101 void* AllocZeroInitializedFn(const AllocatorDispatch* self, |
97 size_t n, | 102 size_t n, |
98 size_t size) { | 103 size_t size, |
99 void* ret = self->next->alloc_zero_initialized_function(self->next, n, size); | 104 void* context) { |
| 105 void* ret = |
| 106 self->next->alloc_zero_initialized_function(self->next, n, size, context); |
100 if (ret != nullptr) | 107 if (ret != nullptr) |
101 RecordAlloc(self->next, ret, size); | 108 RecordAlloc(self->next, ret, size, context); |
102 | 109 |
103 return ret; | 110 return ret; |
104 } | 111 } |
105 | 112 |
106 void* AllocAlignedFn(const AllocatorDispatch* self, | 113 void* AllocAlignedFn(const AllocatorDispatch* self, |
107 size_t alignment, | 114 size_t alignment, |
108 size_t size) { | 115 size_t size, |
109 void* ret = self->next->alloc_aligned_function(self->next, alignment, size); | 116 void* context) { |
| 117 void* ret = |
| 118 self->next->alloc_aligned_function(self->next, alignment, size, context); |
110 if (ret != nullptr) | 119 if (ret != nullptr) |
111 RecordAlloc(self->next, ret, size); | 120 RecordAlloc(self->next, ret, size, context); |
112 | 121 |
113 return ret; | 122 return ret; |
114 } | 123 } |
115 | 124 |
116 void* ReallocFn(const AllocatorDispatch* self, void* address, size_t size) { | 125 void* ReallocFn(const AllocatorDispatch* self, |
| 126 void* address, |
| 127 size_t size, |
| 128 void* context) { |
117 if (address != nullptr) | 129 if (address != nullptr) |
118 RecordFree(self->next, address); | 130 RecordFree(self->next, address, context); |
119 | 131 |
120 void* ret = self->next->realloc_function(self->next, address, size); | 132 void* ret = self->next->realloc_function(self->next, address, size, context); |
121 if (ret != nullptr && size != 0) | 133 if (ret != nullptr && size != 0) |
122 RecordAlloc(self->next, ret, size); | 134 RecordAlloc(self->next, ret, size, context); |
123 | 135 |
124 return ret; | 136 return ret; |
125 } | 137 } |
126 | 138 |
127 void FreeFn(const AllocatorDispatch* self, void* address) { | 139 void FreeFn(const AllocatorDispatch* self, void* address, void* context) { |
128 if (address != nullptr) | 140 if (address != nullptr) |
129 RecordFree(self->next, address); | 141 RecordFree(self->next, address, context); |
130 self->next->free_function(self->next, address); | 142 self->next->free_function(self->next, address, context); |
131 } | 143 } |
132 | 144 |
133 size_t GetSizeEstimateFn(const AllocatorDispatch* self, void* address) { | 145 size_t GetSizeEstimateFn(const AllocatorDispatch* self, |
134 return self->next->get_size_estimate_function(self->next, address); | 146 void* address, |
| 147 void* context) { |
| 148 return self->next->get_size_estimate_function(self->next, address, context); |
135 } | 149 } |
136 | 150 |
137 unsigned BatchMallocFn(const AllocatorDispatch* self, | 151 unsigned BatchMallocFn(const AllocatorDispatch* self, |
138 size_t size, | 152 size_t size, |
139 void** results, | 153 void** results, |
140 unsigned num_requested) { | 154 unsigned num_requested, |
| 155 void* context) { |
141 unsigned count = self->next->batch_malloc_function(self->next, size, results, | 156 unsigned count = self->next->batch_malloc_function(self->next, size, results, |
142 num_requested); | 157 num_requested, context); |
143 for (unsigned i = 0; i < count; ++i) { | 158 for (unsigned i = 0; i < count; ++i) { |
144 RecordAlloc(self->next, results[i], size); | 159 RecordAlloc(self->next, results[i], size, context); |
145 } | 160 } |
146 return count; | 161 return count; |
147 } | 162 } |
148 | 163 |
149 void BatchFreeFn(const AllocatorDispatch* self, | 164 void BatchFreeFn(const AllocatorDispatch* self, |
150 void** to_be_freed, | 165 void** to_be_freed, |
151 unsigned num_to_be_freed) { | 166 unsigned num_to_be_freed, |
| 167 void* context) { |
152 for (unsigned i = 0; i < num_to_be_freed; ++i) { | 168 for (unsigned i = 0; i < num_to_be_freed; ++i) { |
153 if (to_be_freed[i] != nullptr) { | 169 if (to_be_freed[i] != nullptr) { |
154 RecordFree(self->next, to_be_freed[i]); | 170 RecordFree(self->next, to_be_freed[i], context); |
155 } | 171 } |
156 } | 172 } |
157 self->next->batch_free_function(self->next, to_be_freed, num_to_be_freed); | 173 self->next->batch_free_function(self->next, to_be_freed, num_to_be_freed, |
| 174 context); |
158 } | 175 } |
159 | 176 |
160 void FreeDefiniteSizeFn(const AllocatorDispatch* self, void* ptr, size_t size) { | 177 void FreeDefiniteSizeFn(const AllocatorDispatch* self, |
| 178 void* ptr, |
| 179 size_t size, |
| 180 void* context) { |
161 if (ptr != nullptr) | 181 if (ptr != nullptr) |
162 RecordFree(self->next, ptr); | 182 RecordFree(self->next, ptr, context); |
163 self->next->free_definite_size_function(self->next, ptr, size); | 183 self->next->free_definite_size_function(self->next, ptr, size, context); |
164 } | 184 } |
165 | 185 |
166 // The allocator dispatch used to intercept heap operations. | 186 // The allocator dispatch used to intercept heap operations. |
167 AllocatorDispatch allocator_dispatch = {&AllocFn, | 187 AllocatorDispatch allocator_dispatch = {&AllocFn, |
168 &AllocZeroInitializedFn, | 188 &AllocZeroInitializedFn, |
169 &AllocAlignedFn, | 189 &AllocAlignedFn, |
170 &ReallocFn, | 190 &ReallocFn, |
171 &FreeFn, | 191 &FreeFn, |
172 &GetSizeEstimateFn, | 192 &GetSizeEstimateFn, |
173 &BatchMallocFn, | 193 &BatchMallocFn, |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 // RecordFree() above. The sentinel prevents RecordFree() from re-creating | 331 // RecordFree() above. The sentinel prevents RecordFree() from re-creating |
312 // another ThreadHeapUsage object. | 332 // another ThreadHeapUsage object. |
313 g_thread_allocator_usage.Set(kTeardownSentinel); | 333 g_thread_allocator_usage.Set(kTeardownSentinel); |
314 delete static_cast<ThreadHeapUsage*>(thread_heap_usage); | 334 delete static_cast<ThreadHeapUsage*>(thread_heap_usage); |
315 }); | 335 }); |
316 } | 336 } |
317 } | 337 } |
318 | 338 |
319 } // namespace debug | 339 } // namespace debug |
320 } // namespace base | 340 } // namespace base |
OLD | NEW |