OLD | NEW |
1 // Copyright (c) 2005, Google Inc. | 1 // Copyright (c) 2005, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 15 matching lines...) Expand all Loading... |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 // --- | 30 // --- |
31 // Author: Sanjay Ghemawat | 31 // Author: Sanjay Ghemawat |
32 // | 32 // |
33 // TODO: Log large allocations | 33 // TODO: Log large allocations |
34 | 34 |
35 #include <config.h> | 35 #include <config.h> |
36 | 36 #include <stddef.h> |
37 #include <stdio.h> | 37 #include <stdio.h> |
38 #include <stdlib.h> | 38 #include <stdlib.h> |
39 #ifdef HAVE_UNISTD_H | 39 #ifdef HAVE_UNISTD_H |
40 #include <unistd.h> | 40 #include <unistd.h> |
41 #endif | 41 #endif |
42 #ifdef HAVE_INTTYPES_H | 42 #ifdef HAVE_INTTYPES_H |
43 #include <inttypes.h> | 43 #include <inttypes.h> |
44 #endif | 44 #endif |
45 #ifdef HAVE_FCNTL_H | 45 #ifdef HAVE_FCNTL_H |
46 #include <fcntl.h> // for open() | 46 #include <fcntl.h> // for open() |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 // Profile generation | 175 // Profile generation |
176 //---------------------------------------------------------------------- | 176 //---------------------------------------------------------------------- |
177 | 177 |
178 enum AddOrRemove { ADD, REMOVE }; | 178 enum AddOrRemove { ADD, REMOVE }; |
179 | 179 |
180 // Add or remove all MMap-allocated regions to/from *heap_profile. | 180 // Add or remove all MMap-allocated regions to/from *heap_profile. |
181 // Assumes heap_lock is held. | 181 // Assumes heap_lock is held. |
182 static void AddRemoveMMapDataLocked(AddOrRemove mode) { | 182 static void AddRemoveMMapDataLocked(AddOrRemove mode) { |
183 RAW_DCHECK(heap_lock.IsHeld(), ""); | 183 RAW_DCHECK(heap_lock.IsHeld(), ""); |
184 if (!FLAGS_mmap_profile || !is_on) return; | 184 if (!FLAGS_mmap_profile || !is_on) return; |
185 if (!FLAGS_mmap_log) MemoryRegionMap::CheckMallocHooks(); | |
186 // MemoryRegionMap maintained all the data we need for all | 185 // MemoryRegionMap maintained all the data we need for all |
187 // mmap-like allocations, so we just use it here: | 186 // mmap-like allocations, so we just use it here: |
188 MemoryRegionMap::LockHolder l; | 187 MemoryRegionMap::LockHolder l; |
189 for (MemoryRegionMap::RegionIterator r = MemoryRegionMap::BeginRegionLocked(); | 188 for (MemoryRegionMap::RegionIterator r = MemoryRegionMap::BeginRegionLocked(); |
190 r != MemoryRegionMap::EndRegionLocked(); ++r) { | 189 r != MemoryRegionMap::EndRegionLocked(); ++r) { |
191 if (mode == ADD) { | 190 if (mode == ADD) { |
192 heap_profile->RecordAllocWithStack( | 191 heap_profile->RecordAllocWithStack( |
193 reinterpret_cast<const void*>(r->start_addr), | 192 reinterpret_cast<const void*>(r->start_addr), |
194 r->end_addr - r->start_addr, | 193 r->end_addr - r->start_addr, |
195 r->call_stack_depth, r->call_stack); | 194 r->call_stack_depth, r->call_stack); |
196 } else { | 195 } else { |
197 heap_profile->RecordFree(reinterpret_cast<void*>(r->start_addr)); | 196 heap_profile->RecordFree(reinterpret_cast<void*>(r->start_addr)); |
198 } | 197 } |
199 } | 198 } |
200 } | 199 } |
201 | 200 |
202 // Input must be a buffer of size at least 1MB. | 201 // Input must be a buffer of size at least 1MB. |
203 static char* DoGetHeapProfileLocked(char* buf, int buflen) { | 202 static char* DoGetHeapProfileLocked(char* buf, int buflen) { |
204 // We used to be smarter about estimating the required memory and | 203 // We used to be smarter about estimating the required memory and |
205 // then capping it to 1MB and generating the profile into that. | 204 // then capping it to 1MB and generating the profile into that. |
206 if (buf == NULL || buflen < 1) | 205 if (buf == NULL || buflen < 1) |
207 return NULL; | 206 return NULL; |
208 | 207 |
209 RAW_DCHECK(heap_lock.IsHeld(), ""); | 208 RAW_DCHECK(heap_lock.IsHeld(), ""); |
210 int bytes_written = 0; | 209 int bytes_written = 0; |
211 if (is_on) { | 210 if (is_on) { |
212 HeapProfileTable::Stats const stats = heap_profile->total(); | 211 HeapProfileTable::Stats const stats = heap_profile->total(); |
| 212 (void)stats; // avoid an unused-variable warning in non-debug mode. |
213 AddRemoveMMapDataLocked(ADD); | 213 AddRemoveMMapDataLocked(ADD); |
214 bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); | 214 bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); |
215 // FillOrderedProfile should not reduce the set of active mmap-ed regions, | 215 // FillOrderedProfile should not reduce the set of active mmap-ed regions, |
216 // hence MemoryRegionMap will let us remove everything we've added above: | 216 // hence MemoryRegionMap will let us remove everything we've added above: |
217 AddRemoveMMapDataLocked(REMOVE); | 217 AddRemoveMMapDataLocked(REMOVE); |
218 RAW_DCHECK(stats.Equivalent(heap_profile->total()), ""); | 218 RAW_DCHECK(stats.Equivalent(heap_profile->total()), ""); |
219 // if this fails, we somehow removed by AddRemoveMMapDataLocked | 219 // if this fails, we somehow removed by AddRemoveMMapDataLocked |
220 // more than we have added. | 220 // more than we have added. |
221 } | 221 } |
222 buf[bytes_written] = '\0'; | 222 buf[bytes_written] = '\0'; |
(...skipping 14 matching lines...) Expand all Loading... |
237 static void DeleteHook(const void* ptr); | 237 static void DeleteHook(const void* ptr); |
238 | 238 |
239 // Helper for HeapProfilerDump. | 239 // Helper for HeapProfilerDump. |
240 static void DumpProfileLocked(const char* reason) { | 240 static void DumpProfileLocked(const char* reason) { |
241 RAW_DCHECK(heap_lock.IsHeld(), ""); | 241 RAW_DCHECK(heap_lock.IsHeld(), ""); |
242 RAW_DCHECK(is_on, ""); | 242 RAW_DCHECK(is_on, ""); |
243 RAW_DCHECK(!dumping, ""); | 243 RAW_DCHECK(!dumping, ""); |
244 | 244 |
245 if (filename_prefix == NULL) return; // we do not yet need dumping | 245 if (filename_prefix == NULL) return; // we do not yet need dumping |
246 | 246 |
247 if (FLAGS_only_mmap_profile == false) { | |
248 if (MallocHook::GetNewHook() != NewHook || | |
249 MallocHook::GetDeleteHook() != DeleteHook) { | |
250 RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. " | |
251 "Are you using another MallocHook client? " | |
252 "Do not use --heap_profile=... to avoid this conflict."); | |
253 } | |
254 } | |
255 | |
256 dumping = true; | 247 dumping = true; |
257 | 248 |
258 // Make file name | 249 // Make file name |
259 char file_name[1000]; | 250 char file_name[1000]; |
260 dump_count++; | 251 dump_count++; |
261 snprintf(file_name, sizeof(file_name), "%s.%05d.%04d%s", | 252 snprintf(file_name, sizeof(file_name), "%s.%05d.%04d%s", |
262 filename_prefix, getpid(), dump_count, HeapProfileTable::kFileExt); | 253 filename_prefix, getpid(), dump_count, HeapProfileTable::kFileExt); |
263 | 254 |
264 // Dump the profile | 255 // Dump the profile |
265 RAW_VLOG(0, "Dumping heap profile to %s (%s)", file_name, reason); | 256 RAW_VLOG(0, "Dumping heap profile to %s (%s)", file_name, reason); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 } | 355 } |
365 | 356 |
366 // TODO(jandrews): Re-enable stack tracing | 357 // TODO(jandrews): Re-enable stack tracing |
367 #ifdef TODO_REENABLE_STACK_TRACING | 358 #ifdef TODO_REENABLE_STACK_TRACING |
368 static void RawInfoStackDumper(const char* message, void*) { | 359 static void RawInfoStackDumper(const char* message, void*) { |
369 RAW_LOG(INFO, "%.*s", static_cast<int>(strlen(message) - 1), message); | 360 RAW_LOG(INFO, "%.*s", static_cast<int>(strlen(message) - 1), message); |
370 // -1 is to chop the \n which will be added by RAW_LOG | 361 // -1 is to chop the \n which will be added by RAW_LOG |
371 } | 362 } |
372 #endif | 363 #endif |
373 | 364 |
374 // Saved MemoryRegionMap's hooks to daisy-chain calls to. | |
375 MallocHook::MmapHook saved_mmap_hook = NULL; | |
376 MallocHook::MremapHook saved_mremap_hook = NULL; | |
377 MallocHook::MunmapHook saved_munmap_hook = NULL; | |
378 MallocHook::SbrkHook saved_sbrk_hook = NULL; | |
379 | |
380 static void MmapHook(const void* result, const void* start, size_t size, | 365 static void MmapHook(const void* result, const void* start, size_t size, |
381 int prot, int flags, int fd, off_t offset) { | 366 int prot, int flags, int fd, off_t offset) { |
382 if (FLAGS_mmap_log) { // log it | 367 if (FLAGS_mmap_log) { // log it |
383 // We use PRIxS not just '%p' to avoid deadlocks | 368 // We use PRIxS not just '%p' to avoid deadlocks |
384 // in pretty-printing of NULL as "nil". | 369 // in pretty-printing of NULL as "nil". |
385 // TODO(maxim): instead should use a safe snprintf reimplementation | 370 // TODO(maxim): instead should use a safe snprintf reimplementation |
386 RAW_LOG(INFO, | 371 RAW_LOG(INFO, |
387 "mmap(start=0x%"PRIxPTR", len=%"PRIuS", prot=0x%x, flags=0x%x, " | 372 "mmap(start=0x%"PRIxPTR", len=%"PRIuS", prot=0x%x, flags=0x%x, " |
388 "fd=%d, offset=0x%x) = 0x%"PRIxPTR"", | 373 "fd=%d, offset=0x%x) = 0x%"PRIxPTR"", |
389 (uintptr_t) start, size, prot, flags, fd, (unsigned int) offset, | 374 (uintptr_t) start, size, prot, flags, fd, (unsigned int) offset, |
390 (uintptr_t) result); | 375 (uintptr_t) result); |
391 #ifdef TODO_REENABLE_STACK_TRACING | 376 #ifdef TODO_REENABLE_STACK_TRACING |
392 DumpStackTrace(1, RawInfoStackDumper, NULL); | 377 DumpStackTrace(1, RawInfoStackDumper, NULL); |
393 #endif | 378 #endif |
394 } | 379 } |
395 if (saved_mmap_hook) { | |
396 // Call MemoryRegionMap's hook: it will record needed info about the mmap | |
397 // for us w/o deadlocks: | |
398 (*saved_mmap_hook)(result, start, size, prot, flags, fd, offset); | |
399 } | |
400 } | 380 } |
401 | 381 |
402 static void MremapHook(const void* result, const void* old_addr, | 382 static void MremapHook(const void* result, const void* old_addr, |
403 size_t old_size, size_t new_size, | 383 size_t old_size, size_t new_size, |
404 int flags, const void* new_addr) { | 384 int flags, const void* new_addr) { |
405 if (FLAGS_mmap_log) { // log it | 385 if (FLAGS_mmap_log) { // log it |
406 // We use PRIxS not just '%p' to avoid deadlocks | 386 // We use PRIxS not just '%p' to avoid deadlocks |
407 // in pretty-printing of NULL as "nil". | 387 // in pretty-printing of NULL as "nil". |
408 // TODO(maxim): instead should use a safe snprintf reimplementation | 388 // TODO(maxim): instead should use a safe snprintf reimplementation |
409 RAW_LOG(INFO, | 389 RAW_LOG(INFO, |
410 "mremap(old_addr=0x%"PRIxPTR", old_size=%"PRIuS", " | 390 "mremap(old_addr=0x%"PRIxPTR", old_size=%"PRIuS", " |
411 "new_size=%"PRIuS", flags=0x%x, new_addr=0x%"PRIxPTR") = " | 391 "new_size=%"PRIuS", flags=0x%x, new_addr=0x%"PRIxPTR") = " |
412 "0x%"PRIxPTR"", | 392 "0x%"PRIxPTR"", |
413 (uintptr_t) old_addr, old_size, new_size, flags, | 393 (uintptr_t) old_addr, old_size, new_size, flags, |
414 (uintptr_t) new_addr, (uintptr_t) result); | 394 (uintptr_t) new_addr, (uintptr_t) result); |
415 #ifdef TODO_REENABLE_STACK_TRACING | 395 #ifdef TODO_REENABLE_STACK_TRACING |
416 DumpStackTrace(1, RawInfoStackDumper, NULL); | 396 DumpStackTrace(1, RawInfoStackDumper, NULL); |
417 #endif | 397 #endif |
418 } | 398 } |
419 if (saved_mremap_hook) { // call MemoryRegionMap's hook | |
420 (*saved_mremap_hook)(result, old_addr, old_size, new_size, flags, new_addr); | |
421 } | |
422 } | 399 } |
423 | 400 |
424 static void MunmapHook(const void* ptr, size_t size) { | 401 static void MunmapHook(const void* ptr, size_t size) { |
425 if (FLAGS_mmap_log) { // log it | 402 if (FLAGS_mmap_log) { // log it |
426 // We use PRIxS not just '%p' to avoid deadlocks | 403 // We use PRIxS not just '%p' to avoid deadlocks |
427 // in pretty-printing of NULL as "nil". | 404 // in pretty-printing of NULL as "nil". |
428 // TODO(maxim): instead should use a safe snprintf reimplementation | 405 // TODO(maxim): instead should use a safe snprintf reimplementation |
429 RAW_LOG(INFO, "munmap(start=0x%"PRIxPTR", len=%"PRIuS")", | 406 RAW_LOG(INFO, "munmap(start=0x%"PRIxPTR", len=%"PRIuS")", |
430 (uintptr_t) ptr, size); | 407 (uintptr_t) ptr, size); |
431 #ifdef TODO_REENABLE_STACK_TRACING | 408 #ifdef TODO_REENABLE_STACK_TRACING |
432 DumpStackTrace(1, RawInfoStackDumper, NULL); | 409 DumpStackTrace(1, RawInfoStackDumper, NULL); |
433 #endif | 410 #endif |
434 } | 411 } |
435 if (saved_munmap_hook) { // call MemoryRegionMap's hook | |
436 (*saved_munmap_hook)(ptr, size); | |
437 } | |
438 } | 412 } |
439 | 413 |
440 static void SbrkHook(const void* result, std::ptrdiff_t increment) { | 414 static void SbrkHook(const void* result, std::ptrdiff_t increment) { |
441 if (FLAGS_mmap_log) { // log it | 415 if (FLAGS_mmap_log) { // log it |
442 RAW_LOG(INFO, "sbrk(inc=%"PRIdS") = 0x%"PRIxPTR"", | 416 RAW_LOG(INFO, "sbrk(inc=%"PRIdS") = 0x%"PRIxPTR"", |
443 increment, (uintptr_t) result); | 417 increment, (uintptr_t) result); |
444 #ifdef TODO_REENABLE_STACK_TRACING | 418 #ifdef TODO_REENABLE_STACK_TRACING |
445 DumpStackTrace(1, RawInfoStackDumper, NULL); | 419 DumpStackTrace(1, RawInfoStackDumper, NULL); |
446 #endif | 420 #endif |
447 } | 421 } |
448 if (saved_sbrk_hook) { // call MemoryRegionMap's hook | |
449 (*saved_sbrk_hook)(result, increment); | |
450 } | |
451 } | 422 } |
452 | 423 |
453 //---------------------------------------------------------------------- | 424 //---------------------------------------------------------------------- |
454 // Starting/stopping/dumping | 425 // Starting/stopping/dumping |
455 //---------------------------------------------------------------------- | 426 //---------------------------------------------------------------------- |
456 | 427 |
457 extern "C" void HeapProfilerStart(const char* prefix) { | 428 extern "C" void HeapProfilerStart(const char* prefix) { |
458 SpinLockHolder l(&heap_lock); | 429 SpinLockHolder l(&heap_lock); |
459 | 430 |
460 if (is_on) return; | 431 if (is_on) return; |
(...skipping 10 matching lines...) Expand all Loading... |
471 FLAGS_mmap_profile = true; | 442 FLAGS_mmap_profile = true; |
472 } | 443 } |
473 | 444 |
474 if (FLAGS_mmap_profile) { | 445 if (FLAGS_mmap_profile) { |
475 // Ask MemoryRegionMap to record all mmap, mremap, and sbrk | 446 // Ask MemoryRegionMap to record all mmap, mremap, and sbrk |
476 // call stack traces of at least size kMaxStackDepth: | 447 // call stack traces of at least size kMaxStackDepth: |
477 MemoryRegionMap::Init(HeapProfileTable::kMaxStackDepth); | 448 MemoryRegionMap::Init(HeapProfileTable::kMaxStackDepth); |
478 } | 449 } |
479 | 450 |
480 if (FLAGS_mmap_log) { | 451 if (FLAGS_mmap_log) { |
481 // Install our hooks to do the logging | 452 // Install our hooks to do the logging: |
482 // and maybe save MemoryRegionMap's hooks to call: | 453 RAW_CHECK(MallocHook::AddMmapHook(&MmapHook), ""); |
483 saved_mmap_hook = MallocHook::SetMmapHook(MmapHook); | 454 RAW_CHECK(MallocHook::AddMremapHook(&MremapHook), ""); |
484 saved_mremap_hook = MallocHook::SetMremapHook(MremapHook); | 455 RAW_CHECK(MallocHook::AddMunmapHook(&MunmapHook), ""); |
485 saved_munmap_hook = MallocHook::SetMunmapHook(MunmapHook); | 456 RAW_CHECK(MallocHook::AddSbrkHook(&SbrkHook), ""); |
486 saved_sbrk_hook = MallocHook::SetSbrkHook(SbrkHook); | |
487 } | 457 } |
488 | 458 |
489 heap_profiler_memory = | 459 heap_profiler_memory = |
490 LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); | 460 LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); |
491 | 461 |
492 // Reserve space now for the heap profiler, so we can still write a | 462 // Reserve space now for the heap profiler, so we can still write a |
493 // heap profile even if the application runs out of memory. | 463 // heap profile even if the application runs out of memory. |
494 global_profiler_buffer = | 464 global_profiler_buffer = |
495 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); | 465 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); |
496 | 466 |
497 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) | 467 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) |
498 HeapProfileTable(ProfilerMalloc, ProfilerFree); | 468 HeapProfileTable(ProfilerMalloc, ProfilerFree); |
499 | 469 |
500 last_dump_alloc = 0; | 470 last_dump_alloc = 0; |
501 last_dump_free = 0; | 471 last_dump_free = 0; |
502 high_water_mark = 0; | 472 high_water_mark = 0; |
503 | 473 |
504 // We do not reset dump_count so if the user does a sequence of | 474 // We do not reset dump_count so if the user does a sequence of |
505 // HeapProfilerStart/HeapProfileStop, we will get a continuous | 475 // HeapProfilerStart/HeapProfileStop, we will get a continuous |
506 // sequence of profiles. | 476 // sequence of profiles. |
507 | 477 |
508 if (FLAGS_only_mmap_profile == false) { | 478 if (FLAGS_only_mmap_profile == false) { |
509 // Now set the hooks that capture new/delete and malloc/free | 479 // Now set the hooks that capture new/delete and malloc/free. |
510 // and check that these are the only hooks: | 480 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); |
511 if (MallocHook::SetNewHook(NewHook) != NULL || | 481 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); |
512 MallocHook::SetDeleteHook(DeleteHook) != NULL) { | |
513 RAW_LOG(FATAL, "Had other new/delete MallocHook-s set. " | |
514 "Are you using the heap leak checker? " | |
515 "Use --heap_check=\"\" to avoid this conflict."); | |
516 } | |
517 } | 482 } |
518 | 483 |
519 // Copy filename prefix | 484 // Copy filename prefix |
520 RAW_DCHECK(filename_prefix == NULL, ""); | 485 RAW_DCHECK(filename_prefix == NULL, ""); |
521 const int prefix_length = strlen(prefix); | 486 const int prefix_length = strlen(prefix); |
522 filename_prefix = reinterpret_cast<char*>(ProfilerMalloc(prefix_length + 1)); | 487 filename_prefix = reinterpret_cast<char*>(ProfilerMalloc(prefix_length + 1)); |
523 memcpy(filename_prefix, prefix, prefix_length); | 488 memcpy(filename_prefix, prefix, prefix_length); |
524 filename_prefix[prefix_length] = '\0'; | 489 filename_prefix[prefix_length] = '\0'; |
525 } | 490 } |
526 | 491 |
527 extern "C" int IsHeapProfilerRunning() { | 492 extern "C" int IsHeapProfilerRunning() { |
528 SpinLockHolder l(&heap_lock); | 493 SpinLockHolder l(&heap_lock); |
529 return is_on ? 1 : 0; // return an int, because C code doesn't have bool | 494 return is_on ? 1 : 0; // return an int, because C code doesn't have bool |
530 } | 495 } |
531 | 496 |
532 extern "C" void HeapProfilerStop() { | 497 extern "C" void HeapProfilerStop() { |
533 SpinLockHolder l(&heap_lock); | 498 SpinLockHolder l(&heap_lock); |
534 | 499 |
535 if (!is_on) return; | 500 if (!is_on) return; |
536 | 501 |
537 if (FLAGS_only_mmap_profile == false) { | 502 if (FLAGS_only_mmap_profile == false) { |
538 // Unset our new/delete hooks, checking they were the ones set: | 503 // Unset our new/delete hooks, checking they were set: |
539 if (MallocHook::SetNewHook(NULL) != NewHook || | 504 RAW_CHECK(MallocHook::RemoveNewHook(&NewHook), ""); |
540 MallocHook::SetDeleteHook(NULL) != DeleteHook) { | 505 RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), ""); |
541 RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. " | |
542 "Are you using another MallocHook client? " | |
543 "Do not use --heap_profile=... to avoid this conflict."); | |
544 } | |
545 } | 506 } |
546 if (FLAGS_mmap_log) { | 507 if (FLAGS_mmap_log) { |
547 // Restore mmap/sbrk hooks, checking that our hooks were the ones set: | 508 // Restore mmap/sbrk hooks, checking that our hooks were set: |
548 if (MallocHook::SetMmapHook(saved_mmap_hook) != MmapHook || | 509 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), ""); |
549 MallocHook::SetMremapHook(saved_mremap_hook) != MremapHook || | 510 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), ""); |
550 MallocHook::SetMunmapHook(saved_munmap_hook) != MunmapHook || | 511 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), ""); |
551 MallocHook::SetSbrkHook(saved_sbrk_hook) != SbrkHook) { | 512 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); |
552 RAW_LOG(FATAL, "Had our mmap/mremap/munmap/sbrk MallocHook-s replaced. " | |
553 "Are you using another MallocHook client? " | |
554 "Do not use --heap_profile=... to avoid this conflict."); | |
555 } | |
556 } | 513 } |
557 | 514 |
558 // free profile | 515 // free profile |
559 heap_profile->~HeapProfileTable(); | 516 heap_profile->~HeapProfileTable(); |
560 ProfilerFree(heap_profile); | 517 ProfilerFree(heap_profile); |
561 heap_profile = NULL; | 518 heap_profile = NULL; |
562 | 519 |
563 // free output-buffer memory | 520 // free output-buffer memory |
564 ProfilerFree(global_profiler_buffer); | 521 ProfilerFree(global_profiler_buffer); |
565 | 522 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 | 569 |
613 // class used for finalization -- dumps the heap-profile at program exit | 570 // class used for finalization -- dumps the heap-profile at program exit |
614 struct HeapProfileEndWriter { | 571 struct HeapProfileEndWriter { |
615 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } | 572 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } |
616 }; | 573 }; |
617 | 574 |
618 // We want to make sure tcmalloc is up and running before starting the profiler | 575 // We want to make sure tcmalloc is up and running before starting the profiler |
619 static const TCMallocGuard tcmalloc_initializer; | 576 static const TCMallocGuard tcmalloc_initializer; |
620 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); | 577 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); |
621 static HeapProfileEndWriter heap_profile_end_writer; | 578 static HeapProfileEndWriter heap_profile_end_writer; |
OLD | NEW |