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/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; | |
| 22 AllocationContextTracker* const kInitializingSentinel = | |
| 23 reinterpret_cast<AllocationContextTracker*>(-1); | |
|
petrcermak
2016/03/11 11:09:23
Is this really a safe thing to do? Wouldn't it be
Primiano Tucci (use gerrit)
2016/03/11 13:57:57
It's extremely unlikely that a pointer would end u
| |
| 24 | |
| 21 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; | 25 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; |
| 22 | 26 |
| 23 // 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 |
| 24 // thread exits. | 28 // thread exits. |
| 25 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { | 29 void DestructAllocationContextTracker(void* alloc_ctx_tracker) { |
| 26 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); | 30 delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker); |
| 27 } | 31 } |
| 28 | 32 |
| 29 } // namespace | 33 } // namespace |
| 30 | 34 |
| 31 AllocationContextTracker::AllocationContextTracker() {} | 35 AllocationContextTracker::AllocationContextTracker() { |
| 36 pseudo_stack_.reserve(kMaxStackDepth); | |
| 37 } | |
| 32 AllocationContextTracker::~AllocationContextTracker() {} | 38 AllocationContextTracker::~AllocationContextTracker() {} |
| 33 | 39 |
| 34 // static | 40 // static |
| 41 AllocationContextTracker::InitializationState | |
| 42 AllocationContextTracker::GetStateForCurrentThread() { | |
| 43 auto tracker = | |
| 44 static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get()); | |
| 45 if (!tracker) | |
| 46 return kNotInitialized; | |
| 47 if (tracker == kInitializingSentinel) | |
| 48 return kInitializing; | |
| 49 return kInitialized; | |
| 50 } | |
| 51 | |
| 52 // static | |
| 53 AllocationContextTracker* | |
| 54 AllocationContextTracker::InitializeForCurrentThread() { | |
| 55 DCHECK_EQ(kNotInitialized, GetStateForCurrentThread()); | |
| 56 g_tls_alloc_ctx_tracker.Set(kInitializingSentinel); | |
| 57 AllocationContextTracker* tracker = new AllocationContextTracker(); | |
| 58 g_tls_alloc_ctx_tracker.Set(tracker); | |
| 59 return tracker; | |
| 60 } | |
| 61 | |
| 62 // static | |
| 35 AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() { | 63 AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() { |
| 36 auto tracker = | 64 auto tracker = |
| 37 static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get()); | 65 static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get()); |
| 38 | 66 DCHECK_NE(kInitializingSentinel, tracker); |
| 39 if (!tracker) { | 67 if (!tracker) |
| 40 tracker = new AllocationContextTracker(); | 68 tracker = InitializeForCurrentThread(); |
| 41 g_tls_alloc_ctx_tracker.Set(tracker); | |
| 42 } | |
| 43 | |
| 44 return tracker; | 69 return tracker; |
| 45 } | 70 } |
| 46 | 71 |
| 47 // static | 72 // static |
| 48 void AllocationContextTracker::SetCaptureEnabled(bool enabled) { | 73 void AllocationContextTracker::SetCaptureEnabled(bool enabled) { |
| 49 // When enabling capturing, also initialize the TLS slot. This does not create | 74 // When enabling capturing, also initialize the TLS slot. This does not create |
| 50 // a TLS instance yet. | 75 // a TLS instance yet. |
| 51 if (enabled && !g_tls_alloc_ctx_tracker.initialized()) | 76 if (enabled && !g_tls_alloc_ctx_tracker.initialized()) |
| 52 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); | 77 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); |
| 53 | 78 |
| 54 // Release ordering ensures that when a thread observes |capture_enabled_| to | 79 // Release ordering ensures that when a thread observes |capture_enabled_| to |
| 55 // be true through an acquire load, the TLS slot has been initialized. | 80 // be true through an acquire load, the TLS slot has been initialized. |
| 56 subtle::Release_Store(&capture_enabled_, enabled); | 81 subtle::Release_Store(&capture_enabled_, enabled); |
| 57 } | 82 } |
| 58 | 83 |
| 59 // static | 84 // static |
| 60 void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) { | 85 void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) { |
| 61 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); | 86 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); |
| 62 | 87 |
| 63 // Impose a limit on the height to verify that every push is popped, because | 88 // Impose a limit on the height to verify that every push is popped, because |
| 64 // in practice the pseudo stack never grows higher than ~20 frames. | 89 // in practice the pseudo stack never grows higher than ~20 frames. |
| 65 DCHECK_LT(tracker->pseudo_stack_.size(), 128u); | 90 if (tracker->pseudo_stack_.size() < kMaxStackDepth) |
| 66 tracker->pseudo_stack_.push_back(frame); | 91 tracker->pseudo_stack_.push_back(frame); |
| 92 else | |
| 93 NOTREACHED(); | |
| 67 } | 94 } |
| 68 | 95 |
| 69 // static | 96 // static |
| 70 void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) { | 97 void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) { |
| 71 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); | 98 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); |
| 72 | 99 |
| 73 // Guard for stack underflow. If tracing was started with a TRACE_EVENT in | 100 // Guard for stack underflow. If tracing was started with a TRACE_EVENT in |
| 74 // scope, the frame was never pushed, so it is possible that pop is called | 101 // scope, the frame was never pushed, so it is possible that pop is called |
| 75 // on an empty stack. | 102 // on an empty stack. |
| 76 if (tracker->pseudo_stack_.empty()) | 103 if (tracker->pseudo_stack_.empty()) |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 106 std::fill(dst, dst_end, nullptr); | 133 std::fill(dst, dst_end, nullptr); |
| 107 } | 134 } |
| 108 | 135 |
| 109 ctx.type_name = nullptr; | 136 ctx.type_name = nullptr; |
| 110 | 137 |
| 111 return ctx; | 138 return ctx; |
| 112 } | 139 } |
| 113 | 140 |
| 114 } // namespace trace_event | 141 } // namespace trace_event |
| 115 } // namespace base | 142 } // namespace base |
| OLD | NEW |