| 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 |