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