OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 | 6 |
7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) | 7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) |
8 | 8 |
9 #include "vm/malloc_hooks.h" | 9 #include "vm/malloc_hooks.h" |
10 | 10 |
11 #include "gperftools/malloc_hook.h" | 11 #include "gperftools/malloc_hook.h" |
12 | 12 |
13 #include "platform/assert.h" | 13 #include "platform/assert.h" |
14 #include "vm/hash_map.h" | 14 #include "vm/hash_map.h" |
| 15 #include "vm/json_stream.h" |
15 #include "vm/lockers.h" | 16 #include "vm/lockers.h" |
16 | 17 |
17 namespace dart { | 18 namespace dart { |
18 | 19 |
19 // A locker-type class to automatically grab and release the | 20 // A locker-type class to automatically grab and release the |
20 // in_malloc_hook_flag_. | 21 // in_malloc_hook_flag_. |
21 class MallocHookScope { | 22 class MallocHookScope { |
22 public: | 23 public: |
23 static void InitMallocHookFlag() { | 24 static void InitMallocHookFlag() { |
24 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); | 25 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 if (pair == NULL) { | 96 if (pair == NULL) { |
96 return false; | 97 return false; |
97 } else { | 98 } else { |
98 *value = pair->value; | 99 *value = pair->value; |
99 return true; | 100 return true; |
100 } | 101 } |
101 } | 102 } |
102 }; | 103 }; |
103 | 104 |
104 | 105 |
105 class MallocHooksState { | 106 class MallocHooksState : public AllStatic { |
106 public: | 107 public: |
107 static void RecordAllocHook(const void* ptr, size_t size); | 108 static void RecordAllocHook(const void* ptr, size_t size); |
108 static void RecordFreeHook(const void* ptr); | 109 static void RecordFreeHook(const void* ptr); |
109 | 110 |
110 static bool initialized() { return initialized_; } | 111 static bool Active() { return active_; } |
111 static void Init() { | 112 static void Init() { |
112 address_map_ = new AddressMap(); | 113 address_map_ = new AddressMap(); |
113 initialized_ = true; | 114 active_ = true; |
114 original_pid_ = OS::ProcessId(); | 115 original_pid_ = OS::ProcessId(); |
115 } | 116 } |
116 | 117 |
117 static bool IsOriginalProcess() { | 118 static bool IsOriginalProcess() { |
118 ASSERT(original_pid_ != kInvalidPid); | 119 ASSERT(original_pid_ != kInvalidPid); |
119 return original_pid_ == OS::ProcessId(); | 120 return original_pid_ == OS::ProcessId(); |
120 } | 121 } |
121 | 122 |
122 static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; } | 123 static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; } |
123 | 124 |
124 static intptr_t allocation_count() { return allocation_count_; } | 125 static intptr_t allocation_count() { return allocation_count_; } |
125 | 126 |
126 static intptr_t heap_allocated_memory_in_bytes() { | 127 static intptr_t heap_allocated_memory_in_bytes() { |
127 return heap_allocated_memory_in_bytes_; | 128 return heap_allocated_memory_in_bytes_; |
128 } | 129 } |
129 | 130 |
130 static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) { | 131 static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) { |
| 132 ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread()); |
131 ASSERT(size >= 0); | 133 ASSERT(size >= 0); |
132 heap_allocated_memory_in_bytes_ += size; | 134 heap_allocated_memory_in_bytes_ += size; |
133 ++allocation_count_; | 135 ++allocation_count_; |
134 } | 136 } |
135 | 137 |
136 static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) { | 138 static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) { |
| 139 ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread()); |
137 ASSERT(size >= 0); | 140 ASSERT(size >= 0); |
138 ASSERT(heap_allocated_memory_in_bytes_ >= size); | 141 ASSERT(heap_allocated_memory_in_bytes_ >= size); |
139 heap_allocated_memory_in_bytes_ -= size; | 142 heap_allocated_memory_in_bytes_ -= size; |
140 --allocation_count_; | 143 --allocation_count_; |
141 ASSERT(allocation_count_ >= 0); | 144 ASSERT(allocation_count_ >= 0); |
142 } | 145 } |
143 | 146 |
144 static AddressMap* address_map() { return address_map_; } | 147 static AddressMap* address_map() { return address_map_; } |
145 | 148 |
146 static void ResetStats() { | 149 static void ResetStats() { |
| 150 ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread()); |
147 allocation_count_ = 0; | 151 allocation_count_ = 0; |
148 heap_allocated_memory_in_bytes_ = 0; | 152 heap_allocated_memory_in_bytes_ = 0; |
149 address_map_->Clear(); | 153 address_map_->Clear(); |
150 } | 154 } |
151 | 155 |
152 static void TearDown() { | 156 static void TearDown() { |
153 initialized_ = false; | 157 ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread()); |
| 158 active_ = false; |
154 original_pid_ = kInvalidPid; | 159 original_pid_ = kInvalidPid; |
155 ResetStats(); | 160 ResetStats(); |
156 delete address_map_; | 161 delete address_map_; |
157 } | 162 } |
158 | 163 |
159 private: | 164 private: |
160 static bool initialized_; | 165 static bool active_; |
161 static intptr_t original_pid_; | 166 static intptr_t original_pid_; |
162 static Mutex* malloc_hook_mutex_; | 167 static Mutex* malloc_hook_mutex_; |
163 static intptr_t allocation_count_; | 168 static intptr_t allocation_count_; |
164 static intptr_t heap_allocated_memory_in_bytes_; | 169 static intptr_t heap_allocated_memory_in_bytes_; |
165 static AddressMap* address_map_; | 170 static AddressMap* address_map_; |
166 | 171 |
167 static const intptr_t kInvalidPid = -1; | 172 static const intptr_t kInvalidPid = -1; |
168 | |
169 DISALLOW_ALLOCATION(); | |
170 DISALLOW_COPY_AND_ASSIGN(MallocHooksState); | |
171 }; | 173 }; |
172 | 174 |
173 | 175 |
174 // MallocHooks state / locks. | 176 // MallocHooks state / locks. |
175 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey; | 177 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey; |
176 bool MallocHooksState::initialized_ = false; | 178 bool MallocHooksState::active_ = false; |
177 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; | 179 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; |
178 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); | 180 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); |
179 | 181 |
180 // Memory allocation state information. | 182 // Memory allocation state information. |
181 intptr_t MallocHooksState::allocation_count_ = 0; | 183 intptr_t MallocHooksState::allocation_count_ = 0; |
182 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; | 184 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; |
183 AddressMap* MallocHooksState::address_map_ = NULL; | 185 AddressMap* MallocHooksState::address_map_ = NULL; |
184 | 186 |
185 | 187 |
186 void MallocHooks::InitOnce() { | 188 void MallocHooks::InitOnce() { |
187 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 189 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
188 ASSERT(!MallocHooksState::initialized()); | 190 ASSERT(!MallocHooksState::Active()); |
189 | 191 |
190 MallocHookScope::InitMallocHookFlag(); | 192 MallocHookScope::InitMallocHookFlag(); |
191 MallocHooksState::Init(); | 193 MallocHooksState::Init(); |
192 | 194 |
193 // Register malloc hooks. | 195 // Register malloc hooks. |
194 bool success = false; | 196 bool success = false; |
195 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook); | 197 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook); |
196 ASSERT(success); | 198 ASSERT(success); |
197 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook); | 199 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook); |
198 ASSERT(success); | 200 ASSERT(success); |
199 } | 201 } |
200 | 202 |
201 | 203 |
202 void MallocHooks::TearDown() { | 204 void MallocHooks::TearDown() { |
203 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 205 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
204 ASSERT(MallocHooksState::initialized()); | 206 ASSERT(MallocHooksState::Active()); |
205 | 207 |
206 // Remove malloc hooks. | 208 // Remove malloc hooks. |
207 bool success = false; | 209 bool success = false; |
208 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook); | 210 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook); |
209 ASSERT(success); | 211 ASSERT(success); |
210 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook); | 212 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook); |
211 ASSERT(success); | 213 ASSERT(success); |
212 | 214 |
213 MallocHooksState::TearDown(); | 215 MallocHooksState::TearDown(); |
214 MallocHookScope::DestroyMallocHookFlag(); | 216 MallocHookScope::DestroyMallocHookFlag(); |
215 } | 217 } |
216 | 218 |
217 | 219 |
218 void MallocHooks::ResetStats() { | 220 void MallocHooks::ResetStats() { |
219 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 221 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
220 ASSERT(MallocHooksState::initialized()); | 222 if (MallocHooksState::Active()) { |
221 | 223 MallocHooksState::ResetStats(); |
222 MallocHooksState::ResetStats(); | 224 } |
223 } | 225 } |
224 | 226 |
225 | 227 |
226 bool MallocHooks::Initialized() { | 228 bool MallocHooks::Active() { |
227 return MallocHooksState::initialized(); | 229 ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread()); |
| 230 return MallocHooksState::Active(); |
228 } | 231 } |
229 | 232 |
230 | 233 |
| 234 void MallocHooks::PrintToJSONObject(JSONObject* jsobj) { |
| 235 intptr_t allocated_memory = 0; |
| 236 intptr_t allocation_count = 0; |
| 237 bool add_usage = false; |
| 238 // AddProperty may call malloc which would result in an attempt |
| 239 // to acquire the lock recursively so we extract the values first |
| 240 // and then add the JSON properties. |
| 241 { |
| 242 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
| 243 if (Active()) { |
| 244 allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes(); |
| 245 allocation_count = MallocHooksState::allocation_count(); |
| 246 add_usage = true; |
| 247 } |
| 248 } |
| 249 if (add_usage) { |
| 250 jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory); |
| 251 jsobj->AddProperty("_heapAllocationCount", allocation_count); |
| 252 } |
| 253 } |
| 254 |
| 255 |
231 intptr_t MallocHooks::allocation_count() { | 256 intptr_t MallocHooks::allocation_count() { |
232 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 257 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
233 return MallocHooksState::allocation_count(); | 258 return MallocHooksState::allocation_count(); |
234 } | 259 } |
235 | 260 |
236 | 261 |
237 intptr_t MallocHooks::heap_allocated_memory_in_bytes() { | 262 intptr_t MallocHooks::heap_allocated_memory_in_bytes() { |
238 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 263 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
239 return MallocHooksState::heap_allocated_memory_in_bytes(); | 264 return MallocHooksState::heap_allocated_memory_in_bytes(); |
240 } | 265 } |
241 | 266 |
242 | 267 |
243 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { | 268 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { |
244 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { | 269 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { |
245 return; | 270 return; |
246 } | 271 } |
247 | 272 |
248 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks | 273 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks |
249 // again. | 274 // again. |
250 MallocHookScope mhs; | 275 MallocHookScope mhs; |
251 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 276 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
252 ASSERT(MallocHooksState::initialized()); | 277 if ((ptr != NULL) && MallocHooksState::Active()) { |
253 | |
254 if (ptr != NULL) { | |
255 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); | 278 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); |
256 MallocHooksState::address_map()->Insert(ptr, size); | 279 MallocHooksState::address_map()->Insert(ptr, size); |
257 } | 280 } |
258 } | 281 } |
259 | 282 |
260 | 283 |
261 void MallocHooksState::RecordFreeHook(const void* ptr) { | 284 void MallocHooksState::RecordFreeHook(const void* ptr) { |
262 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { | 285 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { |
263 return; | 286 return; |
264 } | 287 } |
265 | 288 |
266 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks | 289 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks |
267 // again. | 290 // again. |
268 MallocHookScope mhs; | 291 MallocHookScope mhs; |
269 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 292 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
270 ASSERT(MallocHooksState::initialized()); | 293 if ((ptr != NULL) && MallocHooksState::Active()) { |
271 | |
272 if (ptr != NULL) { | |
273 intptr_t size = 0; | 294 intptr_t size = 0; |
274 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { | 295 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { |
275 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); | 296 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); |
276 MallocHooksState::address_map()->Remove(ptr); | 297 MallocHooksState::address_map()->Remove(ptr); |
277 } | 298 } |
278 } | 299 } |
279 } | 300 } |
280 | 301 |
281 } // namespace dart | 302 } // namespace dart |
282 | 303 |
283 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) | 304 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) |
OLD | NEW |