Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: runtime/vm/malloc_hooks.cc

Issue 2715493005: Removed MallocHookScope and replaced it with MallocLocker, which behaves like MutexLocker but also … (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | runtime/vm/os_thread.h » ('j') | runtime/vm/os_thread.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/json_stream.h"
16 #include "vm/lockers.h" 16 #include "vm/os_thread.h"
17 17
18 namespace dart { 18 namespace dart {
19 19
20 // A locker-type class to automatically grab and release the 20 // A locker-type class similar to MutexLocker which tracks which thread
21 // in_malloc_hook_flag_. 21 // currently holds the lock. We use this instead of MutexLocker and
22 class MallocHookScope { 22 // mutex->IsOwnedByCurrentThread() since IsOwnedByCurrentThread() is only
23 // enabled for debug mode.
24 class MallocLocker : public ValueObject {
zra 2017/02/22 22:54:54 This seems generally useful. Should it go in os_th
bkonyi 2017/02/22 23:04:26 In its current state, I don't think that would wor
siva 2017/02/22 23:53:04 Discussed offline with Zach, For this CL we leave
bkonyi 2017/02/23 00:28:46 That makes sense to me.
23 public: 25 public:
24 static void InitMallocHookFlag() { 26 explicit MallocLocker(Mutex* mutex) : mutex_(mutex) {
25 MutexLocker ml(malloc_hook_scope_mutex_); 27 mutex_->Lock();
26 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); 28 ASSERT(owner_ == OSThread::kInvalidThreadId);
27 in_malloc_hook_flag_ = OSThread::CreateThreadLocal(); 29 owner_ = OSThread::GetCurrentThreadId();
28 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
29 } 30 }
30 31
31 static void DestroyMallocHookFlag() { 32 virtual ~MallocLocker() {
32 MutexLocker ml(malloc_hook_scope_mutex_); 33 ASSERT(IsOwnedByCurrentThread());
33 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); 34 owner_ = OSThread::kInvalidThreadId;
34 OSThread::DeleteThreadLocal(in_malloc_hook_flag_); 35 mutex_->Unlock();
35 in_malloc_hook_flag_ = kUnsetThreadLocalKey;
36 } 36 }
37 37
38 MallocHookScope() { 38 static bool IsOwnedByCurrentThread() {
39 MutexLocker ml(malloc_hook_scope_mutex_); 39 return (owner_ == OSThread::GetCurrentThreadId());
40 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
41 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1);
42 }
43
44 ~MallocHookScope() {
45 MutexLocker ml(malloc_hook_scope_mutex_);
46 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
47 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
48 }
49
50 static bool IsInHook() {
51 MutexLocker ml(malloc_hook_scope_mutex_);
52 if (in_malloc_hook_flag_ == kUnsetThreadLocalKey) {
53 // Bail out if the malloc hook flag is invalid. This means that
54 // MallocHookState::TearDown() has been called and MallocHookScope is no
55 // longer intitialized. Don't worry if MallocHookState::TearDown() is
56 // called before the hooks grab the mutex, since
57 // MallocHooksState::Active() is checked after the lock is taken before
58 // proceeding to act on the allocation/free.
59 return false;
60 }
61 return OSThread::GetThreadLocal(in_malloc_hook_flag_);
62 } 40 }
63 41
64 private: 42 private:
65 static Mutex* malloc_hook_scope_mutex_; 43 Mutex* mutex_;
66 static ThreadLocalKey in_malloc_hook_flag_; 44 static ThreadId owner_;
67 45
68 DISALLOW_ALLOCATION(); 46 DISALLOW_COPY_AND_ASSIGN(MallocLocker);
zra 2017/02/22 22:54:54 Is this redundant if this is inheriting from Value
bkonyi 2017/02/22 23:04:26 Looks like it is. I had based MallocLocker on Mute
bkonyi 2017/02/23 00:28:46 Done.
69 DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
70 }; 47 };
71 48
72 49
73 // Custom key/value trait specifically for address/size pairs. Unlike 50 // Custom key/value trait specifically for address/size pairs. Unlike
74 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. 51 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
75 class AddressKeyValueTrait { 52 class AddressKeyValueTrait {
76 public: 53 public:
77 typedef const void* Key; 54 typedef const void* Key;
78 typedef intptr_t Value; 55 typedef intptr_t Value;
79 56
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 static intptr_t original_pid_; 157 static intptr_t original_pid_;
181 static Mutex* malloc_hook_mutex_; 158 static Mutex* malloc_hook_mutex_;
182 static intptr_t allocation_count_; 159 static intptr_t allocation_count_;
183 static intptr_t heap_allocated_memory_in_bytes_; 160 static intptr_t heap_allocated_memory_in_bytes_;
184 static AddressMap* address_map_; 161 static AddressMap* address_map_;
185 162
186 static const intptr_t kInvalidPid = -1; 163 static const intptr_t kInvalidPid = -1;
187 }; 164 };
188 165
189 166
190 // MallocHookScope state. 167 // MallocLocker state.
191 Mutex* MallocHookScope::malloc_hook_scope_mutex_ = new Mutex(); 168 ThreadId MallocLocker::owner_ = OSThread::kInvalidThreadId;
siva 2017/02/22 23:53:04 Shouldn't this be clubbed just below the line : Mu
bkonyi 2017/02/23 00:28:46 Done.
192 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
193 169
194 // MallocHooks state / locks. 170 // MallocHooks state / locks.
195 bool MallocHooksState::active_ = false; 171 bool MallocHooksState::active_ = false;
196 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; 172 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
197 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); 173 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
198 174
199 // Memory allocation state information. 175 // Memory allocation state information.
200 intptr_t MallocHooksState::allocation_count_ = 0; 176 intptr_t MallocHooksState::allocation_count_ = 0;
201 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; 177 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
202 AddressMap* MallocHooksState::address_map_ = NULL; 178 AddressMap* MallocHooksState::address_map_ = NULL;
203 179
204 180
205 void MallocHooks::InitOnce() { 181 void MallocHooks::InitOnce() {
206 if (!FLAG_enable_malloc_hooks) { 182 if (!FLAG_enable_malloc_hooks) {
207 return; 183 return;
208 } 184 }
209 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 185 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
210 ASSERT(!MallocHooksState::Active()); 186 ASSERT(!MallocHooksState::Active());
211 187
212 MallocHookScope::InitMallocHookFlag();
213 MallocHooksState::Init(); 188 MallocHooksState::Init();
214 189
215 // Register malloc hooks. 190 // Register malloc hooks.
216 bool success = false; 191 bool success = false;
217 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook); 192 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
218 ASSERT(success); 193 ASSERT(success);
219 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook); 194 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
220 ASSERT(success); 195 ASSERT(success);
221 } 196 }
222 197
223 198
224 void MallocHooks::TearDown() { 199 void MallocHooks::TearDown() {
225 if (!FLAG_enable_malloc_hooks) { 200 if (!FLAG_enable_malloc_hooks) {
226 return; 201 return;
227 } 202 }
228 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 203 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
229 ASSERT(MallocHooksState::Active()); 204 ASSERT(MallocHooksState::Active());
230 205
231 // Remove malloc hooks. 206 // Remove malloc hooks.
232 bool success = false; 207 bool success = false;
233 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook); 208 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
234 ASSERT(success); 209 ASSERT(success);
235 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook); 210 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
236 ASSERT(success); 211 ASSERT(success);
237 212
238 MallocHooksState::TearDown(); 213 MallocHooksState::TearDown();
239 MallocHookScope::DestroyMallocHookFlag();
240 } 214 }
241 215
242 216
243 void MallocHooks::ResetStats() { 217 void MallocHooks::ResetStats() {
244 if (!FLAG_enable_malloc_hooks) { 218 if (!FLAG_enable_malloc_hooks) {
245 return; 219 return;
246 } 220 }
247 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 221 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
248 if (MallocHooksState::Active()) { 222 if (MallocHooksState::Active()) {
249 MallocHooksState::ResetStats(); 223 MallocHooksState::ResetStats();
250 } 224 }
251 } 225 }
252 226
253 227
254 bool MallocHooks::Active() { 228 bool MallocHooks::Active() {
255 if (!FLAG_enable_malloc_hooks) { 229 if (!FLAG_enable_malloc_hooks) {
256 return false; 230 return false;
257 } 231 }
258 ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread()); 232 ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread());
259 return MallocHooksState::Active(); 233 return MallocHooksState::Active();
260 } 234 }
261 235
262 236
263 void MallocHooks::PrintToJSONObject(JSONObject* jsobj) { 237 void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
264 if (!FLAG_enable_malloc_hooks) { 238 if (!FLAG_enable_malloc_hooks) {
265 return; 239 return;
266 } 240 }
267 intptr_t allocated_memory = 0; 241 intptr_t allocated_memory = 0;
268 intptr_t allocation_count = 0; 242 intptr_t allocation_count = 0;
269 bool add_usage = false; 243 bool add_usage = false;
270 // AddProperty may call malloc which would result in an attempt 244 // AddProperty may call malloc which would result in an attempt
271 // to acquire the lock recursively so we extract the values first 245 // to acquire the lock recursively so we extract the values first
272 // and then add the JSON properties. 246 // and then add the JSON properties.
273 { 247 {
274 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 248 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
275 if (Active()) { 249 if (Active()) {
276 allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes(); 250 allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
277 allocation_count = MallocHooksState::allocation_count(); 251 allocation_count = MallocHooksState::allocation_count();
278 add_usage = true; 252 add_usage = true;
279 } 253 }
280 } 254 }
281 if (add_usage) { 255 if (add_usage) {
282 jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory); 256 jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory);
283 jsobj->AddProperty("_heapAllocationCount", allocation_count); 257 jsobj->AddProperty("_heapAllocationCount", allocation_count);
284 } 258 }
285 } 259 }
286 260
287 261
288 intptr_t MallocHooks::allocation_count() { 262 intptr_t MallocHooks::allocation_count() {
289 if (!FLAG_enable_malloc_hooks) { 263 if (!FLAG_enable_malloc_hooks) {
290 return 0; 264 return 0;
291 } 265 }
292 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 266 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
293 return MallocHooksState::allocation_count(); 267 return MallocHooksState::allocation_count();
294 } 268 }
295 269
296 270
297 intptr_t MallocHooks::heap_allocated_memory_in_bytes() { 271 intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
298 if (!FLAG_enable_malloc_hooks) { 272 if (!FLAG_enable_malloc_hooks) {
299 return 0; 273 return 0;
300 } 274 }
301 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 275 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
302 return MallocHooksState::heap_allocated_memory_in_bytes(); 276 return MallocHooksState::heap_allocated_memory_in_bytes();
303 } 277 }
304 278
305 279
306 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { 280 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
307 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 281 if (MallocLocker::IsOwnedByCurrentThread() ||
282 !MallocHooksState::IsOriginalProcess()) {
308 return; 283 return;
309 } 284 }
310 285
311 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 286 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
312 // Now that we hold the lock, check to make sure everything is still active. 287 // Now that we hold the lock, check to make sure everything is still active.
313 if ((ptr != NULL) && MallocHooksState::Active()) { 288 if ((ptr != NULL) && MallocHooksState::Active()) {
314 // Set the malloc hook flag to avoid calling hooks again if memory is
315 // allocated/freed below.
316 MallocHookScope mhs;
317 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); 289 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
318 MallocHooksState::address_map()->Insert(ptr, size); 290 MallocHooksState::address_map()->Insert(ptr, size);
319 } 291 }
320 } 292 }
321 293
322 294
323 void MallocHooksState::RecordFreeHook(const void* ptr) { 295 void MallocHooksState::RecordFreeHook(const void* ptr) {
324 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 296 if (MallocLocker::IsOwnedByCurrentThread() ||
297 !MallocHooksState::IsOriginalProcess()) {
325 return; 298 return;
326 } 299 }
327 300
328 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 301 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
329 // Now that we hold the lock, check to make sure everything is still active. 302 // Now that we hold the lock, check to make sure everything is still active.
330 if ((ptr != NULL) && MallocHooksState::Active()) { 303 if ((ptr != NULL) && MallocHooksState::Active()) {
331 // Set the malloc hook flag to avoid calling hooks again if memory is
332 // allocated/freed below.
333 MallocHookScope mhs;
334 intptr_t size = 0; 304 intptr_t size = 0;
335 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { 305 if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
336 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); 306 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
337 MallocHooksState::address_map()->Remove(ptr); 307 MallocHooksState::address_map()->Remove(ptr);
338 } 308 }
339 } 309 }
340 } 310 }
341 311
342 } // namespace dart 312 } // namespace dart
343 313
344 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) 314 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/os_thread.h » ('j') | runtime/vm/os_thread.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698