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 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 // I would like to use Mutex, but it can call malloc(), | 136 // I would like to use Mutex, but it can call malloc(), |
137 // which can cause us to fall into an infinite recursion. | 137 // which can cause us to fall into an infinite recursion. |
138 // | 138 // |
139 // So we use a simple spinlock. | 139 // So we use a simple spinlock. |
140 static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED); | 140 static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED); |
141 | 141 |
142 //---------------------------------------------------------------------- | 142 //---------------------------------------------------------------------- |
143 // Simple allocator for heap profiler's internal memory | 143 // Simple allocator for heap profiler's internal memory |
144 //---------------------------------------------------------------------- | 144 //---------------------------------------------------------------------- |
145 | 145 |
146 static LowLevelAlloc::Arena *heap_profiler_memory; | 146 static LowLevelAlloc::Arena* heap_profiler_memory; |
147 | 147 |
148 static void* ProfilerMalloc(size_t bytes) { | 148 static void* ProfilerMalloc(size_t bytes) { |
149 return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory); | 149 return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory); |
150 } | 150 } |
151 static void ProfilerFree(void* p) { | 151 static void ProfilerFree(void* p) { |
152 LowLevelAlloc::Free(p); | 152 LowLevelAlloc::Free(p); |
153 } | 153 } |
154 | 154 |
| 155 //---------------------------------------------------------------------- |
| 156 // Another allocator for heap profiler's internal mmap address map |
| 157 // |
| 158 // Large amount of memory is consumed if we use an arena 'heap_profiler_memory' |
| 159 // for the internal mmap address map. It looks like memory fragmentation |
| 160 // because of repeated allocation/deallocation in the arena. |
| 161 // |
| 162 // 'mmap_heap_profiler_memory' is a dedicated arena for the mmap address map. |
| 163 // This arena is reserved for every construction of the mmap address map, and |
| 164 // disposed after every use. |
| 165 //---------------------------------------------------------------------- |
| 166 |
| 167 static LowLevelAlloc::Arena* mmap_heap_profiler_memory = NULL; |
| 168 |
| 169 static void* MMapProfilerMalloc(size_t bytes) { |
| 170 return LowLevelAlloc::AllocWithArena(bytes, mmap_heap_profiler_memory); |
| 171 } |
| 172 static void MMapProfilerFree(void* p) { |
| 173 LowLevelAlloc::Free(p); |
| 174 } |
| 175 |
| 176 // This function should be called from a locked scope. |
| 177 // It returns false if failed in deleting the arena. |
| 178 static bool DeleteMMapProfilerArenaIfExistsLocked() { |
| 179 if (mmap_heap_profiler_memory == NULL) return true; |
| 180 if (!LowLevelAlloc::DeleteArena(mmap_heap_profiler_memory)) return false; |
| 181 mmap_heap_profiler_memory = NULL; |
| 182 return true; |
| 183 } |
| 184 |
155 // We use buffers of this size in DoGetHeapProfile. | 185 // We use buffers of this size in DoGetHeapProfile. |
156 // The size is 1 << 20 in the original google-perftools. Changed it to | 186 // The size is 1 << 20 in the original google-perftools. Changed it to |
157 // 5 << 20 since a larger buffer is requried for deeper profiling in Chromium. | 187 // 5 << 20 since a larger buffer is requried for deeper profiling in Chromium. |
158 // The buffer is allocated only when the environment variable HEAPPROFILE is | 188 // The buffer is allocated only when the environment variable HEAPPROFILE is |
159 // specified to dump heap information. | 189 // specified to dump heap information. |
160 static const int kProfileBufferSize = 5 << 20; | 190 static const int kProfileBufferSize = 5 << 20; |
161 | 191 |
162 // This is a last-ditch buffer we use in DumpProfileLocked in case we | 192 // This is a last-ditch buffer we use in DumpProfileLocked in case we |
163 // can't allocate more memory from ProfilerMalloc. We expect this | 193 // can't allocate more memory from ProfilerMalloc. We expect this |
164 // will be used by HeapProfileEndWriter when the application has to | 194 // will be used by HeapProfileEndWriter when the application has to |
(...skipping 28 matching lines...) Expand all Loading... |
193 static char* DoGetHeapProfileLocked(char* buf, int buflen) { | 223 static char* DoGetHeapProfileLocked(char* buf, int buflen) { |
194 // We used to be smarter about estimating the required memory and | 224 // We used to be smarter about estimating the required memory and |
195 // then capping it to 1MB and generating the profile into that. | 225 // then capping it to 1MB and generating the profile into that. |
196 if (buf == NULL || buflen < 1) | 226 if (buf == NULL || buflen < 1) |
197 return NULL; | 227 return NULL; |
198 | 228 |
199 RAW_DCHECK(heap_lock.IsHeld(), ""); | 229 RAW_DCHECK(heap_lock.IsHeld(), ""); |
200 int bytes_written = 0; | 230 int bytes_written = 0; |
201 if (is_on) { | 231 if (is_on) { |
202 if (FLAGS_mmap_profile) { | 232 if (FLAGS_mmap_profile) { |
203 heap_profile->RefreshMMapData(); | 233 if (!DeleteMMapProfilerArenaIfExistsLocked()) { |
| 234 RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); |
| 235 } |
| 236 mmap_heap_profiler_memory = |
| 237 LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); |
| 238 heap_profile->RefreshMMapData(MMapProfilerMalloc, MMapProfilerFree); |
204 } | 239 } |
205 if (deep_profile) { | 240 if (deep_profile) { |
206 bytes_written = deep_profile->FillOrderedProfile(buf, buflen - 1); | 241 bytes_written = deep_profile->FillOrderedProfile(buf, buflen - 1); |
207 } else { | 242 } else { |
208 bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); | 243 bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); |
209 } | 244 } |
210 if (FLAGS_mmap_profile) { | 245 if (FLAGS_mmap_profile) { |
211 heap_profile->ClearMMapData(); | 246 heap_profile->ClearMMapData(); |
| 247 if (!DeleteMMapProfilerArenaIfExistsLocked()) { |
| 248 RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); |
| 249 } |
212 } | 250 } |
213 } | 251 } |
214 buf[bytes_written] = '\0'; | 252 buf[bytes_written] = '\0'; |
215 RAW_DCHECK(bytes_written == strlen(buf), ""); | 253 RAW_DCHECK(bytes_written == strlen(buf), ""); |
216 | 254 |
217 return buf; | 255 return buf; |
218 } | 256 } |
219 | 257 |
220 extern "C" char* GetHeapProfile() { | 258 extern "C" char* GetHeapProfile() { |
221 // Use normal malloc: we return the profile to the user to free it: | 259 // Use normal malloc: we return the profile to the user to free it: |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 | 563 |
526 if (deep_profile) { | 564 if (deep_profile) { |
527 // free deep memory profiler | 565 // free deep memory profiler |
528 deep_profile->~DeepHeapProfile(); | 566 deep_profile->~DeepHeapProfile(); |
529 ProfilerFree(deep_profile); | 567 ProfilerFree(deep_profile); |
530 deep_profile = NULL; | 568 deep_profile = NULL; |
531 } | 569 } |
532 | 570 |
533 // free profile | 571 // free profile |
534 heap_profile->~HeapProfileTable(); | 572 heap_profile->~HeapProfileTable(); |
| 573 if (!DeleteMMapProfilerArenaIfExistsLocked()) { |
| 574 RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); |
| 575 } |
535 ProfilerFree(heap_profile); | 576 ProfilerFree(heap_profile); |
536 heap_profile = NULL; | 577 heap_profile = NULL; |
537 | 578 |
538 // free output-buffer memory | 579 // free output-buffer memory |
539 ProfilerFree(global_profiler_buffer); | 580 ProfilerFree(global_profiler_buffer); |
540 | 581 |
541 // free prefix | 582 // free prefix |
542 ProfilerFree(filename_prefix); | 583 ProfilerFree(filename_prefix); |
543 filename_prefix = NULL; | 584 filename_prefix = NULL; |
544 | 585 |
545 if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) { | 586 if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) { |
546 RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); | 587 RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); |
547 } | 588 } |
548 | 589 |
549 if (FLAGS_mmap_profile) { | 590 if (FLAGS_mmap_profile) { |
550 MemoryRegionMap::Shutdown(); | 591 MemoryRegionMap::Shutdown(); |
551 } | 592 } |
552 | 593 |
553 is_on = false; | 594 is_on = false; |
554 } | 595 } |
555 | 596 |
556 extern "C" void HeapProfilerDump(const char *reason) { | 597 extern "C" void HeapProfilerDump(const char* reason) { |
557 SpinLockHolder l(&heap_lock); | 598 SpinLockHolder l(&heap_lock); |
558 if (is_on && !dumping) { | 599 if (is_on && !dumping) { |
559 DumpProfileLocked(reason); | 600 DumpProfileLocked(reason); |
560 } | 601 } |
561 } | 602 } |
562 | 603 |
563 //---------------------------------------------------------------------- | 604 //---------------------------------------------------------------------- |
564 // Initialization/finalization code | 605 // Initialization/finalization code |
565 //---------------------------------------------------------------------- | 606 //---------------------------------------------------------------------- |
566 | 607 |
(...skipping 20 matching lines...) Expand all Loading... |
587 | 628 |
588 // class used for finalization -- dumps the heap-profile at program exit | 629 // class used for finalization -- dumps the heap-profile at program exit |
589 struct HeapProfileEndWriter { | 630 struct HeapProfileEndWriter { |
590 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } | 631 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } |
591 }; | 632 }; |
592 | 633 |
593 // We want to make sure tcmalloc is up and running before starting the profiler | 634 // We want to make sure tcmalloc is up and running before starting the profiler |
594 static const TCMallocGuard tcmalloc_initializer; | 635 static const TCMallocGuard tcmalloc_initializer; |
595 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); | 636 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); |
596 static HeapProfileEndWriter heap_profile_end_writer; | 637 static HeapProfileEndWriter heap_profile_end_writer; |
OLD | NEW |