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 |