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; |
22 AllocationContextTracker* const kInitializingSentinel = | 23 AllocationContextTracker* const kInitializingSentinel = |
23 reinterpret_cast<AllocationContextTracker*>(-1); | 24 reinterpret_cast<AllocationContextTracker*>(-1); |
24 | 25 |
25 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; | 26 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; |
26 | 27 |
27 // This function is added to the TLS slot to clean up the instance when the | 28 // This function is added to the TLS slot to clean up the instance when the |
28 // thread exits. | 29 // thread exits. |
29 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { | 30 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { |
30 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); | 31 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); |
31 } | 32 } |
(...skipping 12 matching lines...) Expand all Loading... |
44 g_tls_alloc_ctx_tracker.Set(kInitializingSentinel); | 45 g_tls_alloc_ctx_tracker.Set(kInitializingSentinel); |
45 tracker = new AllocationContextTracker(); | 46 tracker = new AllocationContextTracker(); |
46 g_tls_alloc_ctx_tracker.Set(tracker); | 47 g_tls_alloc_ctx_tracker.Set(tracker); |
47 } | 48 } |
48 | 49 |
49 return tracker; | 50 return tracker; |
50 } | 51 } |
51 | 52 |
52 AllocationContextTracker::AllocationContextTracker() : thread_name_(nullptr) { | 53 AllocationContextTracker::AllocationContextTracker() : thread_name_(nullptr) { |
53 pseudo_stack_.reserve(kMaxStackDepth); | 54 pseudo_stack_.reserve(kMaxStackDepth); |
| 55 task_contexts_.reserve(kMaxTaskDepth); |
54 } | 56 } |
55 AllocationContextTracker::~AllocationContextTracker() {} | 57 AllocationContextTracker::~AllocationContextTracker() {} |
56 | 58 |
57 // static | 59 // static |
58 void AllocationContextTracker::SetCurrentThreadName(const char* name) { | 60 void AllocationContextTracker::SetCurrentThreadName(const char* name) { |
59 if (name && capture_enabled()) { | 61 if (name && capture_enabled()) { |
60 GetInstanceForCurrentThread()->thread_name_ = name; | 62 GetInstanceForCurrentThread()->thread_name_ = name; |
61 } | 63 } |
62 } | 64 } |
63 | 65 |
(...skipping 28 matching lines...) Expand all Loading... |
92 | 94 |
93 // Assert that pushes and pops are nested correctly. This DCHECK can be | 95 // Assert that pushes and pops are nested correctly. This DCHECK can be |
94 // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call | 96 // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call |
95 // without a corresponding TRACE_EVENT_BEGIN). | 97 // without a corresponding TRACE_EVENT_BEGIN). |
96 DCHECK_EQ(frame, pseudo_stack_.back()) | 98 DCHECK_EQ(frame, pseudo_stack_.back()) |
97 << "Encountered an unmatched TRACE_EVENT_END"; | 99 << "Encountered an unmatched TRACE_EVENT_END"; |
98 | 100 |
99 pseudo_stack_.pop_back(); | 101 pseudo_stack_.pop_back(); |
100 } | 102 } |
101 | 103 |
| 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 |
102 // static | 118 // static |
103 AllocationContext AllocationContextTracker::GetContextSnapshot() { | 119 AllocationContext AllocationContextTracker::GetContextSnapshot() { |
104 AllocationContext ctx; | 120 AllocationContext ctx; |
105 | 121 |
106 // Fill the backtrace. | 122 // Fill the backtrace. |
107 { | 123 { |
108 auto src = pseudo_stack_.begin(); | 124 auto src = pseudo_stack_.begin(); |
109 auto dst = std::begin(ctx.backtrace.frames); | 125 auto dst = std::begin(ctx.backtrace.frames); |
110 auto src_end = pseudo_stack_.end(); | 126 auto src_end = pseudo_stack_.end(); |
111 auto dst_end = std::end(ctx.backtrace.frames); | 127 auto dst_end = std::end(ctx.backtrace.frames); |
112 | 128 |
113 // Add the thread name as the first enrty in the backtrace. | 129 // Add the thread name as the first enrty in the backtrace. |
114 if (thread_name_) { | 130 if (thread_name_) { |
115 *dst = thread_name_; | 131 *dst = thread_name_; |
116 ++dst; | 132 ++dst; |
117 } | 133 } |
118 | 134 |
119 // Copy as much of the bottom of the pseudo stack into the backtrace as | 135 // Copy as much of the bottom of the pseudo stack into the backtrace as |
120 // possible. | 136 // possible. |
121 for (; src != src_end && dst != dst_end; src++, dst++) | 137 for (; src != src_end && dst != dst_end; src++, dst++) |
122 *dst = *src; | 138 *dst = *src; |
123 | 139 |
124 // If there is room for more, fill the remaining slots with empty frames. | 140 // If there is room for more, fill the remaining slots with empty frames. |
125 std::fill(dst, dst_end, nullptr); | 141 std::fill(dst, dst_end, nullptr); |
126 } | 142 } |
127 | 143 |
128 ctx.type_name = nullptr; | 144 // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension |
| 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(); |
129 | 147 |
130 return ctx; | 148 return ctx; |
131 } | 149 } |
132 | 150 |
133 } // namespace trace_event | 151 } // namespace trace_event |
134 } // namespace base | 152 } // namespace base |
OLD | NEW |