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/compiler_specific.h" | |
11 #include "base/threading/thread_local_storage.h" | 12 #include "base/threading/thread_local_storage.h" |
12 #include "base/trace_event/heap_profiler_allocation_context.h" | 13 #include "base/trace_event/heap_profiler_allocation_context.h" |
13 | 14 |
14 namespace base { | 15 namespace base { |
15 namespace trace_event { | 16 namespace trace_event { |
16 | 17 |
17 subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0; | 18 subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0; |
18 | 19 |
19 namespace { | 20 namespace { |
20 | 21 |
21 const size_t kMaxStackDepth = 128u; | 22 const size_t kMaxStackDepth = 128u; |
23 const size_t kMaxTaskDepth = 16u; | |
22 AllocationContextTracker* const kInitializingSentinel = | 24 AllocationContextTracker* const kInitializingSentinel = |
23 reinterpret_cast<AllocationContextTracker*>(-1); | 25 reinterpret_cast<AllocationContextTracker*>(-1); |
24 | 26 |
25 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; | 27 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; |
26 | 28 |
27 // This function is added to the TLS slot to clean up the instance when the | 29 // This function is added to the TLS slot to clean up the instance when the |
28 // thread exits. | 30 // thread exits. |
29 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { | 31 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { |
30 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); | 32 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); |
31 } | 33 } |
32 | 34 |
33 } // namespace | 35 } // namespace |
34 | 36 |
37 AllocationContextTracker::ScopedTaskExecutionEvent::ScopedTaskExecutionEvent( | |
38 const char* category_group, | |
39 const char* posted_reason) | |
40 : category_(category_group) { | |
41 if (UNLIKELY(capture_enabled())) { | |
42 AllocationContextTracker* tracker = GetInstanceForCurrentThread(); | |
43 tracker->PushCurrentCategoryName(category_); | |
44 } | |
45 } | |
46 | |
47 AllocationContextTracker::ScopedTaskExecutionEvent:: | |
48 ~ScopedTaskExecutionEvent() { | |
49 if (UNLIKELY(capture_enabled())) { | |
50 AllocationContextTracker* tracker = GetInstanceForCurrentThread(); | |
51 tracker->PopCurrentCategoryName(category_); | |
52 } | |
53 } | |
54 | |
35 // static | 55 // static |
36 AllocationContextTracker* | 56 AllocationContextTracker* |
37 AllocationContextTracker::GetInstanceForCurrentThread() { | 57 AllocationContextTracker::GetInstanceForCurrentThread() { |
38 AllocationContextTracker* tracker = | 58 AllocationContextTracker* tracker = |
39 static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get()); | 59 static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get()); |
40 if (tracker == kInitializingSentinel) | 60 if (tracker == kInitializingSentinel) |
41 return nullptr; // Re-entrancy case. | 61 return nullptr; // Re-entrancy case. |
42 | 62 |
43 if (!tracker) { | 63 if (!tracker) { |
44 g_tls_alloc_ctx_tracker.Set(kInitializingSentinel); | 64 g_tls_alloc_ctx_tracker.Set(kInitializingSentinel); |
45 tracker = new AllocationContextTracker(); | 65 tracker = new AllocationContextTracker(); |
46 g_tls_alloc_ctx_tracker.Set(tracker); | 66 g_tls_alloc_ctx_tracker.Set(tracker); |
47 } | 67 } |
48 | 68 |
49 return tracker; | 69 return tracker; |
50 } | 70 } |
51 | 71 |
52 AllocationContextTracker::AllocationContextTracker() { | 72 AllocationContextTracker::AllocationContextTracker() { |
53 pseudo_stack_.reserve(kMaxStackDepth); | 73 pseudo_stack_.reserve(kMaxStackDepth); |
74 categories_.reserve(kMaxTaskDepth); | |
54 } | 75 } |
55 AllocationContextTracker::~AllocationContextTracker() {} | 76 AllocationContextTracker::~AllocationContextTracker() {} |
56 | 77 |
57 // static | 78 // static |
58 void AllocationContextTracker::SetCaptureEnabled(bool enabled) { | 79 void AllocationContextTracker::SetCaptureEnabled(bool enabled) { |
59 // When enabling capturing, also initialize the TLS slot. This does not create | 80 // When enabling capturing, also initialize the TLS slot. This does not create |
60 // a TLS instance yet. | 81 // a TLS instance yet. |
61 if (enabled && !g_tls_alloc_ctx_tracker.initialized()) | 82 if (enabled && !g_tls_alloc_ctx_tracker.initialized()) |
62 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); | 83 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); |
63 | 84 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
115 | 136 |
116 // Copy as much of the bottom of the pseudo stack into the backtrace as | 137 // Copy as much of the bottom of the pseudo stack into the backtrace as |
117 // possible. | 138 // possible. |
118 for (; src != src_end && dst != dst_end; src++, dst++) | 139 for (; src != src_end && dst != dst_end; src++, dst++) |
119 *dst = *src; | 140 *dst = *src; |
120 | 141 |
121 // If there is room for more, fill the remaining slots with empty frames. | 142 // If there is room for more, fill the remaining slots with empty frames. |
122 std::fill(dst, dst_end, nullptr); | 143 std::fill(dst, dst_end, nullptr); |
123 } | 144 } |
124 | 145 |
125 ctx.type_name = nullptr; | 146 // Set the default type name to file name where the task was posted from. |
147 // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension | |
148 // (component name) in the heap profiler and not piggy back on the type name. | |
149 ctx.type_name = categories_.empty() ? nullptr : categories_.back(); | |
126 | 150 |
127 return ctx; | 151 return ctx; |
128 } | 152 } |
129 | 153 |
154 void AllocationContextTracker::PushCurrentCategoryName(const char* category) { | |
155 DCHECK(category != nullptr); | |
Primiano Tucci (use gerrit)
2016/03/25 01:56:31
I think as a general stylistic pattern we don't bo
ssid
2016/03/28 18:14:49
Done.
| |
156 if (categories_.size() < kMaxTaskDepth) | |
157 categories_.push_back(category); | |
158 else | |
159 NOTREACHED(); | |
160 } | |
161 | |
162 void AllocationContextTracker::PopCurrentCategoryName(const char* category) { | |
163 DCHECK_EQ(category, categories_.back()) | |
164 << "Encountered an unmatched category end"; | |
165 categories_.pop_back(); | |
166 } | |
167 | |
130 } // namespace trace_event | 168 } // namespace trace_event |
131 } // namespace base | 169 } // namespace base |
OLD | NEW |