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 |