| 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 #include "base/basictypes.h" // for PRId64, among other things | 61 #include "base/basictypes.h" // for PRId64, among other things |
| 62 #include "base/googleinit.h" | 62 #include "base/googleinit.h" |
| 63 #include "base/commandlineflags.h" | 63 #include "base/commandlineflags.h" |
| 64 #include "malloc_hook-inl.h" | 64 #include "malloc_hook-inl.h" |
| 65 #include "tcmalloc_guard.h" | 65 #include "tcmalloc_guard.h" |
| 66 #include <gperftools/malloc_hook.h> | 66 #include <gperftools/malloc_hook.h> |
| 67 #include <gperftools/malloc_extension.h> | 67 #include <gperftools/malloc_extension.h> |
| 68 #include "base/spinlock.h" | 68 #include "base/spinlock.h" |
| 69 #include "base/low_level_alloc.h" | 69 #include "base/low_level_alloc.h" |
| 70 #include "base/sysinfo.h" // for GetUniquePathFromEnv() | 70 #include "base/sysinfo.h" // for GetUniquePathFromEnv() |
| 71 #include "deep-heap-profile.h" |
| 71 #include "heap-profile-table.h" | 72 #include "heap-profile-table.h" |
| 72 #include "memory_region_map.h" | 73 #include "memory_region_map.h" |
| 73 | 74 |
| 74 | 75 |
| 75 #ifndef PATH_MAX | 76 #ifndef PATH_MAX |
| 76 #ifdef MAXPATHLEN | 77 #ifdef MAXPATHLEN |
| 77 #define PATH_MAX MAXPATHLEN | 78 #define PATH_MAX MAXPATHLEN |
| 78 #else | 79 #else |
| 79 #define PATH_MAX 4096 // seems conservative for max filename len! | 80 #define PATH_MAX 4096 // seems conservative for max filename len! |
| 80 #endif | 81 #endif |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 DEFINE_bool(mmap_log, | 115 DEFINE_bool(mmap_log, |
| 115 EnvToBool("HEAP_PROFILE_MMAP_LOG", false), | 116 EnvToBool("HEAP_PROFILE_MMAP_LOG", false), |
| 116 "Should mmap/munmap calls be logged?"); | 117 "Should mmap/munmap calls be logged?"); |
| 117 DEFINE_bool(mmap_profile, | 118 DEFINE_bool(mmap_profile, |
| 118 EnvToBool("HEAP_PROFILE_MMAP", false), | 119 EnvToBool("HEAP_PROFILE_MMAP", false), |
| 119 "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); | 120 "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); |
| 120 DEFINE_bool(only_mmap_profile, | 121 DEFINE_bool(only_mmap_profile, |
| 121 EnvToBool("HEAP_PROFILE_ONLY_MMAP", false), | 122 EnvToBool("HEAP_PROFILE_ONLY_MMAP", false), |
| 122 "If heap-profiling is on, only profile mmap, mremap, and sbrk; " | 123 "If heap-profiling is on, only profile mmap, mremap, and sbrk; " |
| 123 "do not profile malloc/new/etc"); | 124 "do not profile malloc/new/etc"); |
| 125 DEFINE_bool(deep_heap_profile, |
| 126 EnvToBool("DEEP_HEAP_PROFILE", false), |
| 127 "If heap-profiling is on, profile deeper (only on Linux)"); |
| 124 | 128 |
| 125 | 129 |
| 126 //---------------------------------------------------------------------- | 130 //---------------------------------------------------------------------- |
| 127 // Locking | 131 // Locking |
| 128 //---------------------------------------------------------------------- | 132 //---------------------------------------------------------------------- |
| 129 | 133 |
| 130 // A pthread_mutex has way too much lock contention to be used here. | 134 // A pthread_mutex has way too much lock contention to be used here. |
| 131 // | 135 // |
| 132 // I would like to use Mutex, but it can call malloc(), | 136 // I would like to use Mutex, but it can call malloc(), |
| 133 // which can cause us to fall into an infinite recursion. | 137 // which can cause us to fall into an infinite recursion. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 static bool dumping = false; // Dumping status to prevent recursion | 176 static bool dumping = false; // Dumping status to prevent recursion |
| 173 static char* filename_prefix = NULL; // Prefix used for profile file names | 177 static char* filename_prefix = NULL; // Prefix used for profile file names |
| 174 // (NULL if no need for dumping yet) | 178 // (NULL if no need for dumping yet) |
| 175 static int dump_count = 0; // How many dumps so far | 179 static int dump_count = 0; // How many dumps so far |
| 176 static int64 last_dump_alloc = 0; // alloc_size when did we last dump | 180 static int64 last_dump_alloc = 0; // alloc_size when did we last dump |
| 177 static int64 last_dump_free = 0; // free_size when did we last dump | 181 static int64 last_dump_free = 0; // free_size when did we last dump |
| 178 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump | 182 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump |
| 179 static int64 last_dump_time = 0; // The time of the last dump | 183 static int64 last_dump_time = 0; // The time of the last dump |
| 180 | 184 |
| 181 static HeapProfileTable* heap_profile = NULL; // the heap profile table | 185 static HeapProfileTable* heap_profile = NULL; // the heap profile table |
| 186 static DeepHeapProfile* deep_profile = NULL; // deep memory profiler |
| 182 | 187 |
| 183 //---------------------------------------------------------------------- | 188 //---------------------------------------------------------------------- |
| 184 // Profile generation | 189 // Profile generation |
| 185 //---------------------------------------------------------------------- | 190 //---------------------------------------------------------------------- |
| 186 | 191 |
| 187 // Input must be a buffer of size at least 1MB. | 192 // Input must be a buffer of size at least 1MB. |
| 188 static char* DoGetHeapProfileLocked(char* buf, int buflen) { | 193 static char* DoGetHeapProfileLocked(char* buf, int buflen) { |
| 189 // We used to be smarter about estimating the required memory and | 194 // We used to be smarter about estimating the required memory and |
| 190 // then capping it to 1MB and generating the profile into that. | 195 // then capping it to 1MB and generating the profile into that. |
| 191 if (buf == NULL || buflen < 1) | 196 if (buf == NULL || buflen < 1) |
| 192 return NULL; | 197 return NULL; |
| 193 | 198 |
| 194 RAW_DCHECK(heap_lock.IsHeld(), ""); | 199 RAW_DCHECK(heap_lock.IsHeld(), ""); |
| 195 int bytes_written = 0; | 200 int bytes_written = 0; |
| 196 if (is_on) { | 201 if (is_on) { |
| 197 if (FLAGS_mmap_profile) { | 202 if (FLAGS_mmap_profile) { |
| 198 heap_profile->RefreshMMapData(); | 203 heap_profile->RefreshMMapData(); |
| 199 } | 204 } |
| 200 bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); | 205 if (deep_profile) { |
| 206 bytes_written = deep_profile->FillOrderedProfile(buf, buflen - 1); |
| 207 } else { |
| 208 bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); |
| 209 } |
| 201 if (FLAGS_mmap_profile) { | 210 if (FLAGS_mmap_profile) { |
| 202 heap_profile->ClearMMapData(); | 211 heap_profile->ClearMMapData(); |
| 203 } | 212 } |
| 204 } | 213 } |
| 205 buf[bytes_written] = '\0'; | 214 buf[bytes_written] = '\0'; |
| 206 RAW_DCHECK(bytes_written == strlen(buf), ""); | 215 RAW_DCHECK(bytes_written == strlen(buf), ""); |
| 207 | 216 |
| 208 return buf; | 217 return buf; |
| 209 } | 218 } |
| 210 | 219 |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); | 468 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); |
| 460 | 469 |
| 461 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) | 470 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) |
| 462 HeapProfileTable(ProfilerMalloc, ProfilerFree); | 471 HeapProfileTable(ProfilerMalloc, ProfilerFree); |
| 463 | 472 |
| 464 last_dump_alloc = 0; | 473 last_dump_alloc = 0; |
| 465 last_dump_free = 0; | 474 last_dump_free = 0; |
| 466 high_water_mark = 0; | 475 high_water_mark = 0; |
| 467 last_dump_time = 0; | 476 last_dump_time = 0; |
| 468 | 477 |
| 478 if (FLAGS_deep_heap_profile) { |
| 479 // Initialize deep memory profiler |
| 480 RAW_VLOG(0, "[%d] Starting a deep memory profiler", getpid()); |
| 481 deep_profile = new(ProfilerMalloc(sizeof(DeepHeapProfile))) |
| 482 DeepHeapProfile(heap_profile, prefix); |
| 483 } |
| 484 |
| 469 // We do not reset dump_count so if the user does a sequence of | 485 // We do not reset dump_count so if the user does a sequence of |
| 470 // HeapProfilerStart/HeapProfileStop, we will get a continuous | 486 // HeapProfilerStart/HeapProfileStop, we will get a continuous |
| 471 // sequence of profiles. | 487 // sequence of profiles. |
| 472 | 488 |
| 473 if (FLAGS_only_mmap_profile == false) { | 489 if (FLAGS_only_mmap_profile == false) { |
| 474 // Now set the hooks that capture new/delete and malloc/free. | 490 // Now set the hooks that capture new/delete and malloc/free. |
| 475 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); | 491 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); |
| 476 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); | 492 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); |
| 477 } | 493 } |
| 478 | 494 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 500 RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), ""); | 516 RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), ""); |
| 501 } | 517 } |
| 502 if (FLAGS_mmap_log) { | 518 if (FLAGS_mmap_log) { |
| 503 // Restore mmap/sbrk hooks, checking that our hooks were set: | 519 // Restore mmap/sbrk hooks, checking that our hooks were set: |
| 504 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), ""); | 520 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), ""); |
| 505 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), ""); | 521 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), ""); |
| 506 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), ""); | 522 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), ""); |
| 507 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); | 523 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); |
| 508 } | 524 } |
| 509 | 525 |
| 526 if (deep_profile) { |
| 527 // free deep memory profiler |
| 528 deep_profile->~DeepHeapProfile(); |
| 529 ProfilerFree(deep_profile); |
| 530 deep_profile = NULL; |
| 531 } |
| 532 |
| 510 // free profile | 533 // free profile |
| 511 heap_profile->~HeapProfileTable(); | 534 heap_profile->~HeapProfileTable(); |
| 512 ProfilerFree(heap_profile); | 535 ProfilerFree(heap_profile); |
| 513 heap_profile = NULL; | 536 heap_profile = NULL; |
| 514 | 537 |
| 515 // free output-buffer memory | 538 // free output-buffer memory |
| 516 ProfilerFree(global_profiler_buffer); | 539 ProfilerFree(global_profiler_buffer); |
| 517 | 540 |
| 518 // free prefix | 541 // free prefix |
| 519 ProfilerFree(filename_prefix); | 542 ProfilerFree(filename_prefix); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 | 587 |
| 565 // class used for finalization -- dumps the heap-profile at program exit | 588 // class used for finalization -- dumps the heap-profile at program exit |
| 566 struct HeapProfileEndWriter { | 589 struct HeapProfileEndWriter { |
| 567 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } | 590 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } |
| 568 }; | 591 }; |
| 569 | 592 |
| 570 // We want to make sure tcmalloc is up and running before starting the profiler | 593 // We want to make sure tcmalloc is up and running before starting the profiler |
| 571 static const TCMallocGuard tcmalloc_initializer; | 594 static const TCMallocGuard tcmalloc_initializer; |
| 572 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); | 595 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); |
| 573 static HeapProfileEndWriter heap_profile_end_writer; | 596 static HeapProfileEndWriter heap_profile_end_writer; |
| OLD | NEW |