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 |