Chromium Code Reviews| 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 |