| 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" | |
| 72 #include "heap-profile-table.h" | 71 #include "heap-profile-table.h" |
| 73 #include "memory_region_map.h" | 72 #include "memory_region_map.h" |
| 74 | 73 |
| 75 | 74 |
| 76 #ifndef PATH_MAX | 75 #ifndef PATH_MAX |
| 77 #ifdef MAXPATHLEN | 76 #ifdef MAXPATHLEN |
| 78 #define PATH_MAX MAXPATHLEN | 77 #define PATH_MAX MAXPATHLEN |
| 79 #else | 78 #else |
| 80 #define PATH_MAX 4096 // seems conservative for max filename len! | 79 #define PATH_MAX 4096 // seems conservative for max filename len! |
| 81 #endif | 80 #endif |
| 82 #endif | 81 #endif |
| 83 | 82 |
| 84 #if defined(__ANDROID__) || defined(ANDROID) | |
| 85 // On android, there are no environment variables. | |
| 86 // Instead, we use system properties, set via: | |
| 87 // adb shell setprop prop_name prop_value | |
| 88 // From <sys/system_properties.h>, | |
| 89 // PROP_NAME_MAX 32 | |
| 90 // PROP_VALUE_MAX 92 | |
| 91 #define HEAPPROFILE "heapprof" | |
| 92 #define HEAP_PROFILE_ALLOCATION_INTERVAL "heapprof.allocation_interval" | |
| 93 #define HEAP_PROFILE_DEALLOCATION_INTERVAL "heapprof.deallocation_interval" | |
| 94 #define HEAP_PROFILE_INUSE_INTERVAL "heapprof.inuse_interval" | |
| 95 #define HEAP_PROFILE_TIME_INTERVAL "heapprof.time_interval" | |
| 96 #define HEAP_PROFILE_MMAP_LOG "heapprof.mmap_log" | |
| 97 #define HEAP_PROFILE_MMAP "heapprof.mmap" | |
| 98 #define HEAP_PROFILE_ONLY_MMAP "heapprof.only_mmap" | |
| 99 #define DEEP_HEAP_PROFILE "heapprof.deep_heap_profile" | |
| 100 #define DEEP_HEAP_PROFILE_PAGEFRAME "heapprof.deep.pageframe" | |
| 101 #define HEAP_PROFILE_TYPE_STATISTICS "heapprof.type_statistics" | |
| 102 #else // defined(__ANDROID__) || defined(ANDROID) | |
| 103 #define HEAPPROFILE "HEAPPROFILE" | |
| 104 #define HEAP_PROFILE_ALLOCATION_INTERVAL "HEAP_PROFILE_ALLOCATION_INTERVAL" | |
| 105 #define HEAP_PROFILE_DEALLOCATION_INTERVAL "HEAP_PROFILE_DEALLOCATION_INTERVAL" | |
| 106 #define HEAP_PROFILE_INUSE_INTERVAL "HEAP_PROFILE_INUSE_INTERVAL" | |
| 107 #define HEAP_PROFILE_TIME_INTERVAL "HEAP_PROFILE_TIME_INTERVAL" | |
| 108 #define HEAP_PROFILE_MMAP_LOG "HEAP_PROFILE_MMAP_LOG" | |
| 109 #define HEAP_PROFILE_MMAP "HEAP_PROFILE_MMAP" | |
| 110 #define HEAP_PROFILE_ONLY_MMAP "HEAP_PROFILE_ONLY_MMAP" | |
| 111 #define DEEP_HEAP_PROFILE "DEEP_HEAP_PROFILE" | |
| 112 #define DEEP_HEAP_PROFILE_PAGEFRAME "DEEP_HEAP_PROFILE_PAGEFRAME" | |
| 113 #define HEAP_PROFILE_TYPE_STATISTICS "HEAP_PROFILE_TYPE_STATISTICS" | |
| 114 #endif // defined(__ANDROID__) || defined(ANDROID) | |
| 115 | |
| 116 using STL_NAMESPACE::string; | 83 using STL_NAMESPACE::string; |
| 117 using STL_NAMESPACE::sort; | 84 using STL_NAMESPACE::sort; |
| 118 | 85 |
| 119 //---------------------------------------------------------------------- | 86 //---------------------------------------------------------------------- |
| 120 // Flags that control heap-profiling | 87 // Flags that control heap-profiling |
| 121 // | 88 // |
| 122 // The thread-safety of the profiler depends on these being immutable | 89 // The thread-safety of the profiler depends on these being immutable |
| 123 // after main starts, so don't change them. | 90 // after main starts, so don't change them. |
| 124 //---------------------------------------------------------------------- | 91 //---------------------------------------------------------------------- |
| 125 | 92 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 147 DEFINE_bool(mmap_log, | 114 DEFINE_bool(mmap_log, |
| 148 EnvToBool(HEAP_PROFILE_MMAP_LOG, false), | 115 EnvToBool(HEAP_PROFILE_MMAP_LOG, false), |
| 149 "Should mmap/munmap calls be logged?"); | 116 "Should mmap/munmap calls be logged?"); |
| 150 DEFINE_bool(mmap_profile, | 117 DEFINE_bool(mmap_profile, |
| 151 EnvToBool(HEAP_PROFILE_MMAP, false), | 118 EnvToBool(HEAP_PROFILE_MMAP, false), |
| 152 "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); | 119 "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); |
| 153 DEFINE_bool(only_mmap_profile, | 120 DEFINE_bool(only_mmap_profile, |
| 154 EnvToBool(HEAP_PROFILE_ONLY_MMAP, false), | 121 EnvToBool(HEAP_PROFILE_ONLY_MMAP, false), |
| 155 "If heap-profiling is on, only profile mmap, mremap, and sbrk; " | 122 "If heap-profiling is on, only profile mmap, mremap, and sbrk; " |
| 156 "do not profile malloc/new/etc"); | 123 "do not profile malloc/new/etc"); |
| 157 DEFINE_bool(deep_heap_profile, | |
| 158 EnvToBool(DEEP_HEAP_PROFILE, false), | |
| 159 "If heap-profiling is on, profile deeper (Linux and Android)"); | |
| 160 DEFINE_int32(deep_heap_profile_pageframe, | |
| 161 EnvToInt(DEEP_HEAP_PROFILE_PAGEFRAME, 0), | |
| 162 "Needs deeper profile. If 1, dump page frame numbers (PFNs). " | |
| 163 "If 2, dump page counts (/proc/kpagecount) with PFNs."); | |
| 164 #if defined(TYPE_PROFILING) | |
| 165 DEFINE_bool(heap_profile_type_statistics, | |
| 166 EnvToBool(HEAP_PROFILE_TYPE_STATISTICS, false), | |
| 167 "If heap-profiling is on, dump type statistics."); | |
| 168 #endif // defined(TYPE_PROFILING) | |
| 169 | |
| 170 | |
| 171 //---------------------------------------------------------------------- | 124 //---------------------------------------------------------------------- |
| 172 // Locking | 125 // Locking |
| 173 //---------------------------------------------------------------------- | 126 //---------------------------------------------------------------------- |
| 174 | 127 |
| 175 // A pthread_mutex has way too much lock contention to be used here. | 128 // A pthread_mutex has way too much lock contention to be used here. |
| 176 // | 129 // |
| 177 // I would like to use Mutex, but it can call malloc(), | 130 // I would like to use Mutex, but it can call malloc(), |
| 178 // which can cause us to fall into an infinite recursion. | 131 // which can cause us to fall into an infinite recursion. |
| 179 // | 132 // |
| 180 // So we use a simple spinlock. | 133 // So we use a simple spinlock. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 static bool dumping = false; // Dumping status to prevent recursion | 166 static bool dumping = false; // Dumping status to prevent recursion |
| 214 static char* filename_prefix = NULL; // Prefix used for profile file names | 167 static char* filename_prefix = NULL; // Prefix used for profile file names |
| 215 // (NULL if no need for dumping yet) | 168 // (NULL if no need for dumping yet) |
| 216 static int dump_count = 0; // How many dumps so far | 169 static int dump_count = 0; // How many dumps so far |
| 217 static int64 last_dump_alloc = 0; // alloc_size when did we last dump | 170 static int64 last_dump_alloc = 0; // alloc_size when did we last dump |
| 218 static int64 last_dump_free = 0; // free_size when did we last dump | 171 static int64 last_dump_free = 0; // free_size when did we last dump |
| 219 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump | 172 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump |
| 220 static int64 last_dump_time = 0; // The time of the last dump | 173 static int64 last_dump_time = 0; // The time of the last dump |
| 221 | 174 |
| 222 static HeapProfileTable* heap_profile = NULL; // the heap profile table | 175 static HeapProfileTable* heap_profile = NULL; // the heap profile table |
| 223 static DeepHeapProfile* deep_profile = NULL; // deep memory profiler | |
| 224 | 176 |
| 225 // Callback to generate a stack trace for an allocation. May be overriden | 177 // Callback to generate a stack trace for an allocation. May be overriden |
| 226 // by an application to provide its own pseudo-stacks. | 178 // by an application to provide its own pseudo-stacks. |
| 227 static StackGeneratorFunction stack_generator_function = | 179 static StackGeneratorFunction stack_generator_function = |
| 228 HeapProfileTable::GetCallerStackTrace; | 180 HeapProfileTable::GetCallerStackTrace; |
| 229 | 181 |
| 230 //---------------------------------------------------------------------- | 182 //---------------------------------------------------------------------- |
| 231 // Profile generation | 183 // Profile generation |
| 232 //---------------------------------------------------------------------- | 184 //---------------------------------------------------------------------- |
| 233 | 185 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 return; | 246 return; |
| 295 } | 247 } |
| 296 | 248 |
| 297 // This case may be impossible, but it's best to be safe. | 249 // This case may be impossible, but it's best to be safe. |
| 298 // It's safe to use the global buffer: we're protected by heap_lock. | 250 // It's safe to use the global buffer: we're protected by heap_lock. |
| 299 if (global_profiler_buffer == NULL) { | 251 if (global_profiler_buffer == NULL) { |
| 300 global_profiler_buffer = | 252 global_profiler_buffer = |
| 301 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); | 253 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); |
| 302 } | 254 } |
| 303 | 255 |
| 304 if (deep_profile) { | 256 char* profile = |
| 305 deep_profile->DumpOrderedProfile(reason, global_profiler_buffer, | 257 DoGetHeapProfileLocked(global_profiler_buffer, kProfileBufferSize); |
| 306 kProfileBufferSize, fd); | 258 RawWrite(fd, profile, strlen(profile)); |
| 307 } else { | |
| 308 char* profile = DoGetHeapProfileLocked(global_profiler_buffer, | |
| 309 kProfileBufferSize); | |
| 310 RawWrite(fd, profile, strlen(profile)); | |
| 311 } | |
| 312 RawClose(fd); | 259 RawClose(fd); |
| 313 | 260 |
| 314 #if defined(TYPE_PROFILING) | |
| 315 if (FLAGS_heap_profile_type_statistics) { | |
| 316 snprintf(file_name, sizeof(file_name), "%s.%05d.%04d.type", | |
| 317 filename_prefix, getpid(), dump_count); | |
| 318 RAW_VLOG(0, "Dumping type statistics to %s", file_name); | |
| 319 heap_profile->DumpTypeStatistics(file_name); | |
| 320 } | |
| 321 #endif // defined(TYPE_PROFILING) | |
| 322 | |
| 323 dumping = false; | 261 dumping = false; |
| 324 } | 262 } |
| 325 | 263 |
| 326 //---------------------------------------------------------------------- | 264 //---------------------------------------------------------------------- |
| 327 // Profile collection | 265 // Profile collection |
| 328 //---------------------------------------------------------------------- | 266 //---------------------------------------------------------------------- |
| 329 | 267 |
| 330 // Dump a profile after either an allocation or deallocation, if | 268 // Dump a profile after either an allocation or deallocation, if |
| 331 // the memory use has changed enough since the last dump. | 269 // the memory use has changed enough since the last dump. |
| 332 static void MaybeDumpProfileLocked() { | 270 static void MaybeDumpProfileLocked() { |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); | 460 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); |
| 523 | 461 |
| 524 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) | 462 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) |
| 525 HeapProfileTable(ProfilerMalloc, ProfilerFree, FLAGS_mmap_profile); | 463 HeapProfileTable(ProfilerMalloc, ProfilerFree, FLAGS_mmap_profile); |
| 526 | 464 |
| 527 last_dump_alloc = 0; | 465 last_dump_alloc = 0; |
| 528 last_dump_free = 0; | 466 last_dump_free = 0; |
| 529 high_water_mark = 0; | 467 high_water_mark = 0; |
| 530 last_dump_time = 0; | 468 last_dump_time = 0; |
| 531 | 469 |
| 532 if (FLAGS_deep_heap_profile) { | |
| 533 // Initialize deep memory profiler | |
| 534 RAW_VLOG(0, "[%d] Starting a deep memory profiler", getpid()); | |
| 535 deep_profile = new(ProfilerMalloc(sizeof(DeepHeapProfile))) | |
| 536 DeepHeapProfile(heap_profile, prefix, DeepHeapProfile::PageFrameType( | |
| 537 FLAGS_deep_heap_profile_pageframe)); | |
| 538 } | |
| 539 | |
| 540 // We do not reset dump_count so if the user does a sequence of | 470 // We do not reset dump_count so if the user does a sequence of |
| 541 // HeapProfilerStart/HeapProfileStop, we will get a continuous | 471 // HeapProfilerStart/HeapProfileStop, we will get a continuous |
| 542 // sequence of profiles. | 472 // sequence of profiles. |
| 543 | 473 |
| 544 if (FLAGS_only_mmap_profile == false) { | 474 if (FLAGS_only_mmap_profile == false) { |
| 545 // Now set the hooks that capture new/delete and malloc/free. | 475 // Now set the hooks that capture new/delete and malloc/free. |
| 546 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); | 476 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); |
| 547 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); | 477 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); |
| 548 } | 478 } |
| 549 | 479 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), ""); | 521 RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), ""); |
| 592 } | 522 } |
| 593 if (FLAGS_mmap_log) { | 523 if (FLAGS_mmap_log) { |
| 594 // Restore mmap/sbrk hooks, checking that our hooks were set: | 524 // Restore mmap/sbrk hooks, checking that our hooks were set: |
| 595 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), ""); | 525 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), ""); |
| 596 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), ""); | 526 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), ""); |
| 597 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), ""); | 527 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), ""); |
| 598 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); | 528 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); |
| 599 } | 529 } |
| 600 | 530 |
| 601 if (deep_profile) { | |
| 602 // free deep memory profiler | |
| 603 deep_profile->~DeepHeapProfile(); | |
| 604 ProfilerFree(deep_profile); | |
| 605 deep_profile = NULL; | |
| 606 } | |
| 607 | |
| 608 // free profile | 531 // free profile |
| 609 heap_profile->~HeapProfileTable(); | 532 heap_profile->~HeapProfileTable(); |
| 610 ProfilerFree(heap_profile); | 533 ProfilerFree(heap_profile); |
| 611 heap_profile = NULL; | 534 heap_profile = NULL; |
| 612 | 535 |
| 613 // free output-buffer memory | 536 // free output-buffer memory |
| 614 ProfilerFree(global_profiler_buffer); | 537 ProfilerFree(global_profiler_buffer); |
| 615 | 538 |
| 616 // free prefix | 539 // free prefix |
| 617 ProfilerFree(filename_prefix); | 540 ProfilerFree(filename_prefix); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 // class used for finalization -- dumps the heap-profile at program exit | 610 // class used for finalization -- dumps the heap-profile at program exit |
| 688 struct HeapProfileEndWriter { | 611 struct HeapProfileEndWriter { |
| 689 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } | 612 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } |
| 690 }; | 613 }; |
| 691 | 614 |
| 692 // We want to make sure tcmalloc is up and running before starting the profiler | 615 // We want to make sure tcmalloc is up and running before starting the profiler |
| 693 static const TCMallocGuard tcmalloc_initializer; | 616 static const TCMallocGuard tcmalloc_initializer; |
| 694 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); | 617 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); |
| 695 static HeapProfileEndWriter heap_profile_end_writer; | 618 static HeapProfileEndWriter heap_profile_end_writer; |
| 696 #endif // defined(ENABLE_PROFILING) | 619 #endif // defined(ENABLE_PROFILING) |
| OLD | NEW |