diff options
Diffstat (limited to 'base/trace_event/heap_profiler_allocation_context_tracker.cc')
-rw-r--r-- | base/trace_event/heap_profiler_allocation_context_tracker.cc | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc new file mode 100644 index 0000000000..791ab7a6fe --- /dev/null +++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc @@ -0,0 +1,115 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/trace_event/heap_profiler_allocation_context_tracker.h" + +#include <algorithm> +#include <iterator> + +#include "base/atomicops.h" +#include "base/threading/thread_local_storage.h" +#include "base/trace_event/heap_profiler_allocation_context.h" + +namespace base { +namespace trace_event { + +subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0; + +namespace { + +ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; + +// This function is added to the TLS slot to clean up the instance when the +// thread exits. +void DestructAllocationContextTracker(void* alloc_ctx_tracker) { + delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); +} + +} // namespace + +AllocationContextTracker::AllocationContextTracker() {} +AllocationContextTracker::~AllocationContextTracker() {} + +// static +AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() { + auto tracker = + static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get()); + + if (!tracker) { + tracker = new AllocationContextTracker(); + g_tls_alloc_ctx_tracker.Set(tracker); + } + + return tracker; +} + +// static +void AllocationContextTracker::SetCaptureEnabled(bool enabled) { + // When enabling capturing, also initialize the TLS slot. This does not create + // a TLS instance yet. + if (enabled && !g_tls_alloc_ctx_tracker.initialized()) + g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); + + // Release ordering ensures that when a thread observes |capture_enabled_| to + // be true through an acquire load, the TLS slot has been initialized. + subtle::Release_Store(&capture_enabled_, enabled); +} + +// static +void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) { + auto tracker = AllocationContextTracker::GetThreadLocalTracker(); + + // Impose a limit on the height to verify that every push is popped, because + // in practice the pseudo stack never grows higher than ~20 frames. + DCHECK_LT(tracker->pseudo_stack_.size(), 128u); + tracker->pseudo_stack_.push_back(frame); +} + +// static +void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) { + auto tracker = AllocationContextTracker::GetThreadLocalTracker(); + + // Guard for stack underflow. If tracing was started with a TRACE_EVENT in + // scope, the frame was never pushed, so it is possible that pop is called + // on an empty stack. + if (tracker->pseudo_stack_.empty()) + return; + + // Assert that pushes and pops are nested correctly. This DCHECK can be + // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call + // without a corresponding TRACE_EVENT_BEGIN). + DCHECK_EQ(frame, tracker->pseudo_stack_.back()) + << "Encountered an unmatched TRACE_EVENT_END"; + + tracker->pseudo_stack_.pop_back(); +} + +// static +AllocationContext AllocationContextTracker::GetContextSnapshot() { + AllocationContextTracker* tracker = GetThreadLocalTracker(); + AllocationContext ctx; + + // Fill the backtrace. + { + auto src = tracker->pseudo_stack_.begin(); + auto dst = std::begin(ctx.backtrace.frames); + auto src_end = tracker->pseudo_stack_.end(); + auto dst_end = std::end(ctx.backtrace.frames); + + // Copy as much of the bottom of the pseudo stack into the backtrace as + // possible. + for (; src != src_end && dst != dst_end; src++, dst++) + *dst = *src; + + // If there is room for more, fill the remaining slots with empty frames. + std::fill(dst, dst_end, nullptr); + } + + ctx.type_name = nullptr; + + return ctx; +} + +} // namespace trace_event +} // namespace base |