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

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: Removed redundant DISALLOW_COPY_AND_ASSIGN from MallocLocker 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') | no next file with comments »
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 {
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_;
siva 2017/02/23 01:46:36 It might be cleaner to not declare this as static
bkonyi 2017/02/23 02:03:27 Done.
67
68 DISALLOW_ALLOCATION();
69 DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
70 }; 45 };
71 46
72 47
73 // Custom key/value trait specifically for address/size pairs. Unlike 48 // Custom key/value trait specifically for address/size pairs. Unlike
74 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. 49 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
75 class AddressKeyValueTrait { 50 class AddressKeyValueTrait {
76 public: 51 public:
77 typedef const void* Key; 52 typedef const void* Key;
78 typedef intptr_t Value; 53 typedef intptr_t Value;
79 54
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 static intptr_t original_pid_; 155 static intptr_t original_pid_;
181 static Mutex* malloc_hook_mutex_; 156 static Mutex* malloc_hook_mutex_;
182 static intptr_t allocation_count_; 157 static intptr_t allocation_count_;
183 static intptr_t heap_allocated_memory_in_bytes_; 158 static intptr_t heap_allocated_memory_in_bytes_;
184 static AddressMap* address_map_; 159 static AddressMap* address_map_;
185 160
186 static const intptr_t kInvalidPid = -1; 161 static const intptr_t kInvalidPid = -1;
187 }; 162 };
188 163
189 164
190 // MallocHookScope state.
191 Mutex* MallocHookScope::malloc_hook_scope_mutex_ = new Mutex();
192 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
193
194 // MallocHooks state / locks. 165 // MallocHooks state / locks.
195 bool MallocHooksState::active_ = false; 166 bool MallocHooksState::active_ = false;
196 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; 167 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
197 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); 168 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
169 ThreadId MallocLocker::owner_ = OSThread::kInvalidThreadId;
198 170
199 // Memory allocation state information. 171 // Memory allocation state information.
200 intptr_t MallocHooksState::allocation_count_ = 0; 172 intptr_t MallocHooksState::allocation_count_ = 0;
201 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; 173 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
202 AddressMap* MallocHooksState::address_map_ = NULL; 174 AddressMap* MallocHooksState::address_map_ = NULL;
203 175
204 176
205 void MallocHooks::InitOnce() { 177 void MallocHooks::InitOnce() {
206 if (!FLAG_enable_malloc_hooks) { 178 if (!FLAG_enable_malloc_hooks) {
207 return; 179 return;
208 } 180 }
209 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 181 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
210 ASSERT(!MallocHooksState::Active()); 182 ASSERT(!MallocHooksState::Active());
211 183
212 MallocHookScope::InitMallocHookFlag();
213 MallocHooksState::Init(); 184 MallocHooksState::Init();
214 185
215 // Register malloc hooks. 186 // Register malloc hooks.
216 bool success = false; 187 bool success = false;
217 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook); 188 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
218 ASSERT(success); 189 ASSERT(success);
219 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook); 190 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
220 ASSERT(success); 191 ASSERT(success);
221 } 192 }
222 193
223 194
224 void MallocHooks::TearDown() { 195 void MallocHooks::TearDown() {
225 if (!FLAG_enable_malloc_hooks) { 196 if (!FLAG_enable_malloc_hooks) {
226 return; 197 return;
227 } 198 }
228 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 199 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
229 ASSERT(MallocHooksState::Active()); 200 ASSERT(MallocHooksState::Active());
230 201
231 // Remove malloc hooks. 202 // Remove malloc hooks.
232 bool success = false; 203 bool success = false;
233 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook); 204 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
234 ASSERT(success); 205 ASSERT(success);
235 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook); 206 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
236 ASSERT(success); 207 ASSERT(success);
237 208
238 MallocHooksState::TearDown(); 209 MallocHooksState::TearDown();
239 MallocHookScope::DestroyMallocHookFlag();
240 } 210 }
241 211
242 212
243 void MallocHooks::ResetStats() { 213 void MallocHooks::ResetStats() {
244 if (!FLAG_enable_malloc_hooks) { 214 if (!FLAG_enable_malloc_hooks) {
245 return; 215 return;
246 } 216 }
247 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 217 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
248 if (MallocHooksState::Active()) { 218 if (MallocHooksState::Active()) {
249 MallocHooksState::ResetStats(); 219 MallocHooksState::ResetStats();
250 } 220 }
251 } 221 }
252 222
253 223
254 bool MallocHooks::Active() { 224 bool MallocHooks::Active() {
255 if (!FLAG_enable_malloc_hooks) { 225 if (!FLAG_enable_malloc_hooks) {
256 return false; 226 return false;
257 } 227 }
258 ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread()); 228 ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread());
259 return MallocHooksState::Active(); 229 return MallocHooksState::Active();
260 } 230 }
261 231
262 232
263 void MallocHooks::PrintToJSONObject(JSONObject* jsobj) { 233 void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
264 if (!FLAG_enable_malloc_hooks) { 234 if (!FLAG_enable_malloc_hooks) {
265 return; 235 return;
266 } 236 }
267 intptr_t allocated_memory = 0; 237 intptr_t allocated_memory = 0;
268 intptr_t allocation_count = 0; 238 intptr_t allocation_count = 0;
269 bool add_usage = false; 239 bool add_usage = false;
270 // AddProperty may call malloc which would result in an attempt 240 // AddProperty may call malloc which would result in an attempt
271 // to acquire the lock recursively so we extract the values first 241 // to acquire the lock recursively so we extract the values first
272 // and then add the JSON properties. 242 // and then add the JSON properties.
273 { 243 {
274 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 244 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
275 if (Active()) { 245 if (Active()) {
276 allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes(); 246 allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
277 allocation_count = MallocHooksState::allocation_count(); 247 allocation_count = MallocHooksState::allocation_count();
278 add_usage = true; 248 add_usage = true;
279 } 249 }
280 } 250 }
281 if (add_usage) { 251 if (add_usage) {
282 jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory); 252 jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory);
283 jsobj->AddProperty("_heapAllocationCount", allocation_count); 253 jsobj->AddProperty("_heapAllocationCount", allocation_count);
284 } 254 }
285 } 255 }
286 256
287 257
288 intptr_t MallocHooks::allocation_count() { 258 intptr_t MallocHooks::allocation_count() {
289 if (!FLAG_enable_malloc_hooks) { 259 if (!FLAG_enable_malloc_hooks) {
290 return 0; 260 return 0;
291 } 261 }
292 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 262 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
293 return MallocHooksState::allocation_count(); 263 return MallocHooksState::allocation_count();
294 } 264 }
295 265
296 266
297 intptr_t MallocHooks::heap_allocated_memory_in_bytes() { 267 intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
298 if (!FLAG_enable_malloc_hooks) { 268 if (!FLAG_enable_malloc_hooks) {
299 return 0; 269 return 0;
300 } 270 }
301 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 271 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
302 return MallocHooksState::heap_allocated_memory_in_bytes(); 272 return MallocHooksState::heap_allocated_memory_in_bytes();
303 } 273 }
304 274
305 275
306 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { 276 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
307 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 277 if (MallocLocker::IsOwnedByCurrentThread() ||
278 !MallocHooksState::IsOriginalProcess()) {
308 return; 279 return;
309 } 280 }
310 281
311 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 282 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
312 // Now that we hold the lock, check to make sure everything is still active. 283 // Now that we hold the lock, check to make sure everything is still active.
313 if ((ptr != NULL) && MallocHooksState::Active()) { 284 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); 285 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
318 MallocHooksState::address_map()->Insert(ptr, size); 286 MallocHooksState::address_map()->Insert(ptr, size);
319 } 287 }
320 } 288 }
321 289
322 290
323 void MallocHooksState::RecordFreeHook(const void* ptr) { 291 void MallocHooksState::RecordFreeHook(const void* ptr) {
324 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 292 if (MallocLocker::IsOwnedByCurrentThread() ||
293 !MallocHooksState::IsOriginalProcess()) {
325 return; 294 return;
326 } 295 }
327 296
328 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 297 MallocLocker ml(MallocHooksState::malloc_hook_mutex());
329 // Now that we hold the lock, check to make sure everything is still active. 298 // Now that we hold the lock, check to make sure everything is still active.
330 if ((ptr != NULL) && MallocHooksState::Active()) { 299 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; 300 intptr_t size = 0;
335 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { 301 if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
336 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); 302 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
337 MallocHooksState::address_map()->Remove(ptr); 303 MallocHooksState::address_map()->Remove(ptr);
338 } 304 }
339 } 305 }
340 } 306 }
341 307
342 } // namespace dart 308 } // namespace dart
343 309
344 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) 310 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/os_thread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698