| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/trace_event/heap_profiler_allocation_context_tracker.h" | 5 #include "base/trace_event/heap_profiler_allocation_context_tracker.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iterator> | 8 #include <iterator> |
| 9 | 9 |
| 10 #include "base/atomicops.h" | 10 #include "base/atomicops.h" |
| 11 #include "base/threading/thread_local_storage.h" | 11 #include "base/threading/thread_local_storage.h" |
| 12 #include "base/trace_event/heap_profiler_allocation_context.h" | 12 #include "base/trace_event/heap_profiler_allocation_context.h" |
| 13 | 13 |
| 14 namespace base { | 14 namespace base { |
| 15 namespace trace_event { | 15 namespace trace_event { |
| 16 | 16 |
| 17 subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0; | 17 subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0; |
| 18 | 18 |
| 19 namespace { | 19 namespace { |
| 20 | 20 |
| 21 const size_t kMaxStackDepth = 128u; | 21 const size_t kMaxStackDepth = 128u; |
| 22 const size_t kMaxTaskDepth = 16u; | |
| 23 AllocationContextTracker* const kInitializingSentinel = | 22 AllocationContextTracker* const kInitializingSentinel = |
| 24 reinterpret_cast<AllocationContextTracker*>(-1); | 23 reinterpret_cast<AllocationContextTracker*>(-1); |
| 25 | 24 |
| 26 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; | 25 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; |
| 27 | 26 |
| 28 // This function is added to the TLS slot to clean up the instance when the | 27 // This function is added to the TLS slot to clean up the instance when the |
| 29 // thread exits. | 28 // thread exits. |
| 30 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { | 29 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { |
| 31 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); | 30 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); |
| 32 } | 31 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 45 g_tls_alloc_ctx_tracker.Set(kInitializingSentinel); | 44 g_tls_alloc_ctx_tracker.Set(kInitializingSentinel); |
| 46 tracker = new AllocationContextTracker(); | 45 tracker = new AllocationContextTracker(); |
| 47 g_tls_alloc_ctx_tracker.Set(tracker); | 46 g_tls_alloc_ctx_tracker.Set(tracker); |
| 48 } | 47 } |
| 49 | 48 |
| 50 return tracker; | 49 return tracker; |
| 51 } | 50 } |
| 52 | 51 |
| 53 AllocationContextTracker::AllocationContextTracker() : thread_name_(nullptr) { | 52 AllocationContextTracker::AllocationContextTracker() : thread_name_(nullptr) { |
| 54 pseudo_stack_.reserve(kMaxStackDepth); | 53 pseudo_stack_.reserve(kMaxStackDepth); |
| 55 task_contexts_.reserve(kMaxTaskDepth); | |
| 56 } | 54 } |
| 57 AllocationContextTracker::~AllocationContextTracker() {} | 55 AllocationContextTracker::~AllocationContextTracker() {} |
| 58 | 56 |
| 59 // static | 57 // static |
| 60 void AllocationContextTracker::SetCurrentThreadName(const char* name) { | 58 void AllocationContextTracker::SetCurrentThreadName(const char* name) { |
| 61 if (name && capture_enabled()) { | 59 if (name && capture_enabled()) { |
| 62 GetInstanceForCurrentThread()->thread_name_ = name; | 60 GetInstanceForCurrentThread()->thread_name_ = name; |
| 63 } | 61 } |
| 64 } | 62 } |
| 65 | 63 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 94 | 92 |
| 95 // Assert that pushes and pops are nested correctly. This DCHECK can be | 93 // Assert that pushes and pops are nested correctly. This DCHECK can be |
| 96 // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call | 94 // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call |
| 97 // without a corresponding TRACE_EVENT_BEGIN). | 95 // without a corresponding TRACE_EVENT_BEGIN). |
| 98 DCHECK_EQ(frame, pseudo_stack_.back()) | 96 DCHECK_EQ(frame, pseudo_stack_.back()) |
| 99 << "Encountered an unmatched TRACE_EVENT_END"; | 97 << "Encountered an unmatched TRACE_EVENT_END"; |
| 100 | 98 |
| 101 pseudo_stack_.pop_back(); | 99 pseudo_stack_.pop_back(); |
| 102 } | 100 } |
| 103 | 101 |
| 104 void AllocationContextTracker::PushCurrentTaskContext(const char* context) { | |
| 105 DCHECK(context); | |
| 106 if (task_contexts_.size() < kMaxTaskDepth) | |
| 107 task_contexts_.push_back(context); | |
| 108 else | |
| 109 NOTREACHED(); | |
| 110 } | |
| 111 | |
| 112 void AllocationContextTracker::PopCurrentTaskContext(const char* context) { | |
| 113 DCHECK_EQ(context, task_contexts_.back()) | |
| 114 << "Encountered an unmatched context end"; | |
| 115 task_contexts_.pop_back(); | |
| 116 } | |
| 117 | |
| 118 // static | 102 // static |
| 119 AllocationContext AllocationContextTracker::GetContextSnapshot() { | 103 AllocationContext AllocationContextTracker::GetContextSnapshot() { |
| 120 AllocationContext ctx; | 104 AllocationContext ctx; |
| 121 | 105 |
| 122 // Fill the backtrace. | 106 // Fill the backtrace. |
| 123 { | 107 { |
| 124 auto src = pseudo_stack_.begin(); | 108 auto src = pseudo_stack_.begin(); |
| 125 auto dst = std::begin(ctx.backtrace.frames); | 109 auto dst = std::begin(ctx.backtrace.frames); |
| 126 auto src_end = pseudo_stack_.end(); | 110 auto src_end = pseudo_stack_.end(); |
| 127 auto dst_end = std::end(ctx.backtrace.frames); | 111 auto dst_end = std::end(ctx.backtrace.frames); |
| 128 | 112 |
| 129 // Add the thread name as the first enrty in the backtrace. | 113 // Add the thread name as the first enrty in the backtrace. |
| 130 if (thread_name_) { | 114 if (thread_name_) { |
| 131 *dst = thread_name_; | 115 *dst = thread_name_; |
| 132 ++dst; | 116 ++dst; |
| 133 } | 117 } |
| 134 | 118 |
| 135 // Copy as much of the bottom of the pseudo stack into the backtrace as | 119 // Copy as much of the bottom of the pseudo stack into the backtrace as |
| 136 // possible. | 120 // possible. |
| 137 for (; src != src_end && dst != dst_end; src++, dst++) | 121 for (; src != src_end && dst != dst_end; src++, dst++) |
| 138 *dst = *src; | 122 *dst = *src; |
| 139 | 123 |
| 140 // If there is room for more, fill the remaining slots with empty frames. | 124 // If there is room for more, fill the remaining slots with empty frames. |
| 141 std::fill(dst, dst_end, nullptr); | 125 std::fill(dst, dst_end, nullptr); |
| 142 } | 126 } |
| 143 | 127 |
| 144 // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension | 128 ctx.type_name = nullptr; |
| 145 // (component name) in the heap profiler and not piggy back on the type name. | |
| 146 ctx.type_name = task_contexts_.empty() ? nullptr : task_contexts_.back(); | |
| 147 | 129 |
| 148 return ctx; | 130 return ctx; |
| 149 } | 131 } |
| 150 | 132 |
| 151 } // namespace trace_event | 133 } // namespace trace_event |
| 152 } // namespace base | 134 } // namespace base |
| OLD | NEW |