Restore variadic macros in DevToolsEmbedderMessageDispatcher
[chromium-blink-merge.git] / third_party / tcmalloc / chromium / src / heap-profiler.cc
blob693023abc4b1d82b80d23a6a23e14228115b1cb6
1 // Copyright (c) 2005, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 // ---
31 // Author: Sanjay Ghemawat
33 // TODO: Log large allocations
35 #include <config.h>
36 #include <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #ifdef HAVE_INTTYPES_H
43 #include <inttypes.h>
44 #endif
45 #ifdef HAVE_FCNTL_H
46 #include <fcntl.h> // for open()
47 #endif
48 #ifdef HAVE_MMAP
49 #include <sys/mman.h>
50 #endif
51 #include <errno.h>
52 #include <assert.h>
53 #include <sys/types.h>
55 #include <algorithm>
56 #include <string>
58 #include <gperftools/heap-profiler.h>
60 #include "base/logging.h"
61 #include "base/basictypes.h" // for PRId64, among other things
62 #include "base/googleinit.h"
63 #include "base/commandlineflags.h"
64 #include "malloc_hook-inl.h"
65 #include "tcmalloc_guard.h"
66 #include <gperftools/malloc_hook.h>
67 #include <gperftools/malloc_extension.h>
68 #include "base/spinlock.h"
69 #include "base/low_level_alloc.h"
70 #include "base/sysinfo.h" // for GetUniquePathFromEnv()
71 #include "heap-profile-table.h"
72 #include "memory_region_map.h"
75 #ifndef PATH_MAX
76 #ifdef MAXPATHLEN
77 #define PATH_MAX MAXPATHLEN
78 #else
79 #define PATH_MAX 4096 // seems conservative for max filename len!
80 #endif
81 #endif
83 #if defined(__ANDROID__) || defined(ANDROID)
84 // On android, there are no environment variables.
85 // Instead, we use system properties, set via:
86 // adb shell setprop prop_name prop_value
87 // From <sys/system_properties.h>,
88 // PROP_NAME_MAX 32
89 // PROP_VALUE_MAX 92
90 #define HEAPPROFILE "heapprof"
91 #define HEAP_PROFILE_ALLOCATION_INTERVAL "heapprof.allocation_interval"
92 #define HEAP_PROFILE_DEALLOCATION_INTERVAL "heapprof.deallocation_interval"
93 #define HEAP_PROFILE_INUSE_INTERVAL "heapprof.inuse_interval"
94 #define HEAP_PROFILE_TIME_INTERVAL "heapprof.time_interval"
95 #define HEAP_PROFILE_MMAP_LOG "heapprof.mmap_log"
96 #define HEAP_PROFILE_MMAP "heapprof.mmap"
97 #define HEAP_PROFILE_ONLY_MMAP "heapprof.only_mmap"
98 #else // defined(__ANDROID__) || defined(ANDROID)
99 #define HEAPPROFILE "HEAPPROFILE"
100 #define HEAP_PROFILE_ALLOCATION_INTERVAL "HEAP_PROFILE_ALLOCATION_INTERVAL"
101 #define HEAP_PROFILE_DEALLOCATION_INTERVAL "HEAP_PROFILE_DEALLOCATION_INTERVAL"
102 #define HEAP_PROFILE_INUSE_INTERVAL "HEAP_PROFILE_INUSE_INTERVAL"
103 #define HEAP_PROFILE_TIME_INTERVAL "HEAP_PROFILE_TIME_INTERVAL"
104 #define HEAP_PROFILE_MMAP_LOG "HEAP_PROFILE_MMAP_LOG"
105 #define HEAP_PROFILE_MMAP "HEAP_PROFILE_MMAP"
106 #define HEAP_PROFILE_ONLY_MMAP "HEAP_PROFILE_ONLY_MMAP"
107 #endif // defined(__ANDROID__) || defined(ANDROID)
109 using STL_NAMESPACE::string;
110 using STL_NAMESPACE::sort;
112 //----------------------------------------------------------------------
113 // Flags that control heap-profiling
115 // The thread-safety of the profiler depends on these being immutable
116 // after main starts, so don't change them.
117 //----------------------------------------------------------------------
119 DEFINE_int64(heap_profile_allocation_interval,
120 EnvToInt64(HEAP_PROFILE_ALLOCATION_INTERVAL, 1 << 30 /*1GB*/),
121 "If non-zero, dump heap profiling information once every "
122 "specified number of bytes allocated by the program since "
123 "the last dump.");
124 DEFINE_int64(heap_profile_deallocation_interval,
125 EnvToInt64(HEAP_PROFILE_DEALLOCATION_INTERVAL, 0),
126 "If non-zero, dump heap profiling information once every "
127 "specified number of bytes deallocated by the program "
128 "since the last dump.");
129 // We could also add flags that report whenever inuse_bytes changes by
130 // X or -X, but there hasn't been a need for that yet, so we haven't.
131 DEFINE_int64(heap_profile_inuse_interval,
132 EnvToInt64(HEAP_PROFILE_INUSE_INTERVAL, 100 << 20 /*100MB*/),
133 "If non-zero, dump heap profiling information whenever "
134 "the high-water memory usage mark increases by the specified "
135 "number of bytes.");
136 DEFINE_int64(heap_profile_time_interval,
137 EnvToInt64(HEAP_PROFILE_TIME_INTERVAL, 0),
138 "If non-zero, dump heap profiling information once every "
139 "specified number of seconds since the last dump.");
140 DEFINE_bool(mmap_log,
141 EnvToBool(HEAP_PROFILE_MMAP_LOG, false),
142 "Should mmap/munmap calls be logged?");
143 DEFINE_bool(mmap_profile,
144 EnvToBool(HEAP_PROFILE_MMAP, false),
145 "If heap-profiling is on, also profile mmap, mremap, and sbrk)");
146 DEFINE_bool(only_mmap_profile,
147 EnvToBool(HEAP_PROFILE_ONLY_MMAP, false),
148 "If heap-profiling is on, only profile mmap, mremap, and sbrk; "
149 "do not profile malloc/new/etc");
150 //----------------------------------------------------------------------
151 // Locking
152 //----------------------------------------------------------------------
154 // A pthread_mutex has way too much lock contention to be used here.
156 // I would like to use Mutex, but it can call malloc(),
157 // which can cause us to fall into an infinite recursion.
159 // So we use a simple spinlock.
160 static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED);
162 //----------------------------------------------------------------------
163 // Simple allocator for heap profiler's internal memory
164 //----------------------------------------------------------------------
166 static LowLevelAlloc::Arena *heap_profiler_memory;
168 static void* ProfilerMalloc(size_t bytes) {
169 return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory);
171 static void ProfilerFree(void* p) {
172 LowLevelAlloc::Free(p);
175 // We use buffers of this size in DoGetHeapProfile.
176 static const int kProfileBufferSize = 1 << 20;
178 // This is a last-ditch buffer we use in DumpProfileLocked in case we
179 // can't allocate more memory from ProfilerMalloc. We expect this
180 // will be used by HeapProfileEndWriter when the application has to
181 // exit due to out-of-memory. This buffer is allocated in
182 // HeapProfilerStart. Access to this must be protected by heap_lock.
183 static char* global_profiler_buffer = NULL;
186 //----------------------------------------------------------------------
187 // Profiling control/state data
188 //----------------------------------------------------------------------
190 // Access to all of these is protected by heap_lock.
191 static bool is_on = false; // If are on as a subsytem.
192 static bool dumping = false; // Dumping status to prevent recursion
193 static char* filename_prefix = NULL; // Prefix used for profile file names
194 // (NULL if no need for dumping yet)
195 static int dump_count = 0; // How many dumps so far
196 static int64 last_dump_alloc = 0; // alloc_size when did we last dump
197 static int64 last_dump_free = 0; // free_size when did we last dump
198 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump
199 static int64 last_dump_time = 0; // The time of the last dump
201 static HeapProfileTable* heap_profile = NULL; // the heap profile table
203 // Callback to generate a stack trace for an allocation. May be overriden
204 // by an application to provide its own pseudo-stacks.
205 static StackGeneratorFunction stack_generator_function =
206 HeapProfileTable::GetCallerStackTrace;
208 //----------------------------------------------------------------------
209 // Profile generation
210 //----------------------------------------------------------------------
212 // Input must be a buffer of size at least 1MB.
213 static char* DoGetHeapProfileLocked(char* buf, int buflen) {
214 // We used to be smarter about estimating the required memory and
215 // then capping it to 1MB and generating the profile into that.
216 if (buf == NULL || buflen < 1)
217 return NULL;
219 RAW_DCHECK(heap_lock.IsHeld(), "");
220 int bytes_written = 0;
221 if (is_on) {
222 HeapProfileTable::Stats const stats = heap_profile->total();
223 (void)stats; // avoid an unused-variable warning in non-debug mode.
224 bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1);
225 // FillOrderedProfile should not reduce the set of active mmap-ed regions,
226 // hence MemoryRegionMap will let us remove everything we've added above:
227 RAW_DCHECK(stats.Equivalent(heap_profile->total()), "");
228 // if this fails, we somehow removed by FillOrderedProfile
229 // more than we have added.
231 buf[bytes_written] = '\0';
232 RAW_DCHECK(bytes_written == strlen(buf), "");
234 return buf;
237 extern "C" char* GetHeapProfile() {
238 // Use normal malloc: we return the profile to the user to free it:
239 char* buffer = reinterpret_cast<char*>(malloc(kProfileBufferSize));
240 SpinLockHolder l(&heap_lock);
241 return DoGetHeapProfileLocked(buffer, kProfileBufferSize);
244 // defined below
245 static void NewHook(const void* ptr, size_t size);
246 static void DeleteHook(const void* ptr);
248 // Helper for HeapProfilerDump.
249 static void DumpProfileLocked(const char* reason) {
250 RAW_DCHECK(heap_lock.IsHeld(), "");
251 RAW_DCHECK(is_on, "");
252 RAW_DCHECK(!dumping, "");
254 if (filename_prefix == NULL) return; // we do not yet need dumping
256 dumping = true;
258 // Make file name
259 char file_name[1000];
260 dump_count++;
261 snprintf(file_name, sizeof(file_name), "%s.%05d.%04d%s",
262 filename_prefix, getpid(), dump_count, HeapProfileTable::kFileExt);
264 // Dump the profile
265 RAW_VLOG(0, "Dumping heap profile to %s (%s)", file_name, reason);
266 // We must use file routines that don't access memory, since we hold
267 // a memory lock now.
268 RawFD fd = RawOpenForWriting(file_name);
269 if (fd == kIllegalRawFD) {
270 RAW_LOG(ERROR, "Failed dumping heap profile to %s", file_name);
271 dumping = false;
272 return;
275 // This case may be impossible, but it's best to be safe.
276 // It's safe to use the global buffer: we're protected by heap_lock.
277 if (global_profiler_buffer == NULL) {
278 global_profiler_buffer =
279 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize));
282 char* profile = DoGetHeapProfileLocked(global_profiler_buffer,
283 kProfileBufferSize);
284 RawWrite(fd, profile, strlen(profile));
285 RawClose(fd);
287 dumping = false;
290 //----------------------------------------------------------------------
291 // Profile collection
292 //----------------------------------------------------------------------
294 // Dump a profile after either an allocation or deallocation, if
295 // the memory use has changed enough since the last dump.
296 static void MaybeDumpProfileLocked() {
297 if (!dumping) {
298 const HeapProfileTable::Stats& total = heap_profile->total();
299 const int64 inuse_bytes = total.alloc_size - total.free_size;
300 bool need_to_dump = false;
301 char buf[128];
302 int64 current_time = time(NULL);
303 if (FLAGS_heap_profile_allocation_interval > 0 &&
304 total.alloc_size >=
305 last_dump_alloc + FLAGS_heap_profile_allocation_interval) {
306 snprintf(buf, sizeof(buf), ("%" PRId64 " MB allocated cumulatively, "
307 "%" PRId64 " MB currently in use"),
308 total.alloc_size >> 20, inuse_bytes >> 20);
309 need_to_dump = true;
310 } else if (FLAGS_heap_profile_deallocation_interval > 0 &&
311 total.free_size >=
312 last_dump_free + FLAGS_heap_profile_deallocation_interval) {
313 snprintf(buf, sizeof(buf), ("%" PRId64 " MB freed cumulatively, "
314 "%" PRId64 " MB currently in use"),
315 total.free_size >> 20, inuse_bytes >> 20);
316 need_to_dump = true;
317 } else if (FLAGS_heap_profile_inuse_interval > 0 &&
318 inuse_bytes >
319 high_water_mark + FLAGS_heap_profile_inuse_interval) {
320 snprintf(buf, sizeof(buf), "%" PRId64 " MB currently in use",
321 inuse_bytes >> 20);
322 need_to_dump = true;
323 } else if (FLAGS_heap_profile_time_interval > 0 &&
324 current_time - last_dump_time >=
325 FLAGS_heap_profile_time_interval) {
326 snprintf(buf, sizeof(buf), "%" PRId64 " sec since the last dump",
327 current_time - last_dump_time);
328 need_to_dump = true;
329 last_dump_time = current_time;
331 if (need_to_dump) {
332 DumpProfileLocked(buf);
334 last_dump_alloc = total.alloc_size;
335 last_dump_free = total.free_size;
336 if (inuse_bytes > high_water_mark)
337 high_water_mark = inuse_bytes;
342 // Record an allocation in the profile.
343 static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) {
344 // Take the stack trace outside the critical section.
345 void* stack[HeapProfileTable::kMaxStackDepth];
346 int depth = stack_generator_function(skip_count + 1, stack);
347 SpinLockHolder l(&heap_lock);
348 if (is_on) {
349 heap_profile->RecordAlloc(ptr, bytes, depth, stack);
350 MaybeDumpProfileLocked();
354 // Record a deallocation in the profile.
355 static void RecordFree(const void* ptr) {
356 SpinLockHolder l(&heap_lock);
357 if (is_on) {
358 heap_profile->RecordFree(ptr);
359 MaybeDumpProfileLocked();
363 //----------------------------------------------------------------------
364 // Allocation/deallocation hooks for MallocHook
365 //----------------------------------------------------------------------
367 // static
368 void NewHook(const void* ptr, size_t size) {
369 if (ptr != NULL) RecordAlloc(ptr, size, 0);
372 // static
373 void DeleteHook(const void* ptr) {
374 if (ptr != NULL) RecordFree(ptr);
377 // TODO(jandrews): Re-enable stack tracing
378 #ifdef TODO_REENABLE_STACK_TRACING
379 static void RawInfoStackDumper(const char* message, void*) {
380 RAW_LOG(INFO, "%.*s", static_cast<int>(strlen(message) - 1), message);
381 // -1 is to chop the \n which will be added by RAW_LOG
383 #endif
385 static void MmapHook(const void* result, const void* start, size_t size,
386 int prot, int flags, int fd, off_t offset) {
387 if (FLAGS_mmap_log) { // log it
388 // We use PRIxS not just '%p' to avoid deadlocks
389 // in pretty-printing of NULL as "nil".
390 // TODO(maxim): instead should use a safe snprintf reimplementation
391 RAW_LOG(INFO,
392 "mmap(start=0x%" PRIxPTR ", len=%" PRIuS ", prot=0x%x, flags=0x%x, "
393 "fd=%d, offset=0x%x) = 0x%" PRIxPTR,
394 (uintptr_t) start, size, prot, flags, fd, (unsigned int) offset,
395 (uintptr_t) result);
396 #ifdef TODO_REENABLE_STACK_TRACING
397 DumpStackTrace(1, RawInfoStackDumper, NULL);
398 #endif
402 static void MremapHook(const void* result, const void* old_addr,
403 size_t old_size, size_t new_size,
404 int flags, const void* new_addr) {
405 if (FLAGS_mmap_log) { // log it
406 // We use PRIxS not just '%p' to avoid deadlocks
407 // in pretty-printing of NULL as "nil".
408 // TODO(maxim): instead should use a safe snprintf reimplementation
409 RAW_LOG(INFO,
410 "mremap(old_addr=0x%" PRIxPTR ", old_size=%" PRIuS ", "
411 "new_size=%" PRIuS ", flags=0x%x, new_addr=0x%" PRIxPTR ") = "
412 "0x%" PRIxPTR,
413 (uintptr_t) old_addr, old_size, new_size, flags,
414 (uintptr_t) new_addr, (uintptr_t) result);
415 #ifdef TODO_REENABLE_STACK_TRACING
416 DumpStackTrace(1, RawInfoStackDumper, NULL);
417 #endif
421 static void MunmapHook(const void* ptr, size_t size) {
422 if (FLAGS_mmap_log) { // log it
423 // We use PRIxS not just '%p' to avoid deadlocks
424 // in pretty-printing of NULL as "nil".
425 // TODO(maxim): instead should use a safe snprintf reimplementation
426 RAW_LOG(INFO, "munmap(start=0x%" PRIxPTR ", len=%" PRIuS ")",
427 (uintptr_t) ptr, size);
428 #ifdef TODO_REENABLE_STACK_TRACING
429 DumpStackTrace(1, RawInfoStackDumper, NULL);
430 #endif
434 static void SbrkHook(const void* result, ptrdiff_t increment) {
435 if (FLAGS_mmap_log) { // log it
436 RAW_LOG(INFO, "sbrk(inc=%" PRIdS ") = 0x%" PRIxPTR,
437 increment, (uintptr_t) result);
438 #ifdef TODO_REENABLE_STACK_TRACING
439 DumpStackTrace(1, RawInfoStackDumper, NULL);
440 #endif
444 //----------------------------------------------------------------------
445 // Starting/stopping/dumping
446 //----------------------------------------------------------------------
448 extern "C" void HeapProfilerStart(const char* prefix) {
449 SpinLockHolder l(&heap_lock);
451 if (is_on) return;
453 is_on = true;
455 RAW_VLOG(0, "Starting tracking the heap");
457 // This should be done before the hooks are set up, since it should
458 // call new, and we want that to be accounted for correctly.
459 MallocExtension::Initialize();
461 if (FLAGS_only_mmap_profile) {
462 FLAGS_mmap_profile = true;
465 if (FLAGS_mmap_profile) {
466 // Ask MemoryRegionMap to record all mmap, mremap, and sbrk
467 // call stack traces of at least size kMaxStackDepth:
468 MemoryRegionMap::Init(HeapProfileTable::kMaxStackDepth,
469 /* use_buckets */ true);
472 if (FLAGS_mmap_log) {
473 // Install our hooks to do the logging:
474 RAW_CHECK(MallocHook::AddMmapHook(&MmapHook), "");
475 RAW_CHECK(MallocHook::AddMremapHook(&MremapHook), "");
476 RAW_CHECK(MallocHook::AddMunmapHook(&MunmapHook), "");
477 RAW_CHECK(MallocHook::AddSbrkHook(&SbrkHook), "");
480 heap_profiler_memory =
481 LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena());
483 // Reserve space now for the heap profiler, so we can still write a
484 // heap profile even if the application runs out of memory.
485 global_profiler_buffer =
486 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize));
488 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable)))
489 HeapProfileTable(ProfilerMalloc, ProfilerFree, FLAGS_mmap_profile);
491 last_dump_alloc = 0;
492 last_dump_free = 0;
493 high_water_mark = 0;
494 last_dump_time = 0;
496 // We do not reset dump_count so if the user does a sequence of
497 // HeapProfilerStart/HeapProfileStop, we will get a continuous
498 // sequence of profiles.
500 if (FLAGS_only_mmap_profile == false) {
501 // Now set the hooks that capture new/delete and malloc/free.
502 RAW_CHECK(MallocHook::AddNewHook(&NewHook), "");
503 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), "");
506 // Copy filename prefix only if provided.
507 if (!prefix)
508 return;
509 RAW_DCHECK(filename_prefix == NULL, "");
510 const int prefix_length = strlen(prefix);
511 filename_prefix = reinterpret_cast<char*>(ProfilerMalloc(prefix_length + 1));
512 memcpy(filename_prefix, prefix, prefix_length);
513 filename_prefix[prefix_length] = '\0';
516 extern "C" void HeapProfilerWithPseudoStackStart(
517 StackGeneratorFunction callback) {
519 // Ensure the callback is set before allocations can be recorded.
520 SpinLockHolder l(&heap_lock);
521 stack_generator_function = callback;
523 HeapProfilerStart(NULL);
526 extern "C" void IterateAllocatedObjects(AddressVisitor visitor, void* data) {
527 SpinLockHolder l(&heap_lock);
529 if (!is_on) return;
531 heap_profile->IterateAllocationAddresses(visitor, data);
534 extern "C" int IsHeapProfilerRunning() {
535 SpinLockHolder l(&heap_lock);
536 return is_on ? 1 : 0; // return an int, because C code doesn't have bool
539 extern "C" void HeapProfilerStop() {
540 SpinLockHolder l(&heap_lock);
542 if (!is_on) return;
544 if (FLAGS_only_mmap_profile == false) {
545 // Unset our new/delete hooks, checking they were set:
546 RAW_CHECK(MallocHook::RemoveNewHook(&NewHook), "");
547 RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), "");
549 if (FLAGS_mmap_log) {
550 // Restore mmap/sbrk hooks, checking that our hooks were set:
551 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), "");
552 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), "");
553 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), "");
554 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), "");
557 // free profile
558 heap_profile->~HeapProfileTable();
559 ProfilerFree(heap_profile);
560 heap_profile = NULL;
562 // free output-buffer memory
563 ProfilerFree(global_profiler_buffer);
565 // free prefix
566 ProfilerFree(filename_prefix);
567 filename_prefix = NULL;
569 if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) {
570 RAW_LOG(FATAL, "Memory leak in HeapProfiler:");
573 if (FLAGS_mmap_profile) {
574 MemoryRegionMap::Shutdown();
577 is_on = false;
580 extern "C" void HeapProfilerDump(const char* reason) {
581 SpinLockHolder l(&heap_lock);
582 if (is_on && !dumping) {
583 DumpProfileLocked(reason);
587 extern "C" void HeapProfilerMarkBaseline() {
588 SpinLockHolder l(&heap_lock);
590 if (!is_on) return;
592 heap_profile->MarkCurrentAllocations(HeapProfileTable::MARK_ONE);
595 extern "C" void HeapProfilerMarkInteresting() {
596 SpinLockHolder l(&heap_lock);
598 if (!is_on) return;
600 heap_profile->MarkUnmarkedAllocations(HeapProfileTable::MARK_TWO);
603 extern "C" void HeapProfilerDumpAliveObjects(const char* filename) {
604 SpinLockHolder l(&heap_lock);
606 if (!is_on) return;
608 heap_profile->DumpMarkedObjects(HeapProfileTable::MARK_TWO, filename);
611 //----------------------------------------------------------------------
612 // Initialization/finalization code
613 //----------------------------------------------------------------------
614 #if defined(ENABLE_PROFILING)
615 // Initialization code
616 static void HeapProfilerInit() {
617 // Everything after this point is for setting up the profiler based on envvar
618 char fname[PATH_MAX];
619 if (!GetUniquePathFromEnv(HEAPPROFILE, fname)) {
620 return;
622 // We do a uid check so we don't write out files in a setuid executable.
623 #ifdef HAVE_GETEUID
624 if (getuid() != geteuid()) {
625 RAW_LOG(WARNING, ("HeapProfiler: ignoring " HEAPPROFILE " because "
626 "program seems to be setuid\n"));
627 return;
629 #endif
631 HeapProfileTable::CleanupOldProfiles(fname);
633 HeapProfilerStart(fname);
636 // class used for finalization -- dumps the heap-profile at program exit
637 struct HeapProfileEndWriter {
638 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); }
641 // We want to make sure tcmalloc is up and running before starting the profiler
642 static const TCMallocGuard tcmalloc_initializer;
643 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit());
644 static HeapProfileEndWriter heap_profile_end_writer;
645 #endif // defined(ENABLE_PROFILING)