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/memory_profiler_allocation_context.h" | 5 #include "base/trace_event/memory_profiler_allocation_context.h" |
6 | 6 |
| 7 #include <algorithm> |
| 8 |
7 #include "base/threading/thread_local_storage.h" | 9 #include "base/threading/thread_local_storage.h" |
8 | 10 |
9 namespace base { | 11 namespace base { |
10 namespace trace_event { | 12 namespace trace_event { |
11 | 13 |
12 subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0; | 14 subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0; |
13 | 15 |
14 namespace { | 16 namespace { |
15 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; | 17 ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER; |
16 } | 18 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 | 55 |
54 // static | 56 // static |
55 void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) { | 57 void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) { |
56 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); | 58 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); |
57 tracker->pseudo_stack_.push(frame); | 59 tracker->pseudo_stack_.push(frame); |
58 } | 60 } |
59 | 61 |
60 // static | 62 // static |
61 void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) { | 63 void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) { |
62 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); | 64 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); |
63 DCHECK_EQ(frame, *tracker->pseudo_stack_.top()); | 65 // Assert that pushes and pops are nested correctly. |top()| points past the |
| 66 // top of the stack, so |top() - 1| dereferences to the topmost frame. |
| 67 DCHECK_EQ(frame, *(tracker->pseudo_stack_.top() - 1)); |
64 tracker->pseudo_stack_.pop(); | 68 tracker->pseudo_stack_.pop(); |
65 } | 69 } |
66 | 70 |
67 // static | 71 // static |
68 void AllocationContextTracker::SetContextField(const char* key, | 72 void AllocationContextTracker::SetContextField(const char* key, |
69 const char* value) { | 73 const char* value) { |
70 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); | 74 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); |
71 tracker->context_[key] = value; | 75 tracker->context_[key] = value; |
72 } | 76 } |
73 | 77 |
74 // static | 78 // static |
75 void AllocationContextTracker::UnsetContextField(const char* key) { | 79 void AllocationContextTracker::UnsetContextField(const char* key) { |
76 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); | 80 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); |
77 tracker->context_.erase(key); | 81 tracker->context_.erase(key); |
78 } | 82 } |
79 | 83 |
80 // static | 84 // Returns a pointer past the end of the fixed-size array |array| of |T| of |
81 AllocationStack* AllocationContextTracker::GetPseudoStackForTesting() { | 85 // length |N|, identical to C++11 |std::end|. |
82 auto tracker = AllocationContextTracker::GetThreadLocalTracker(); | 86 template <typename T, int N> |
83 return &tracker->pseudo_stack_; | 87 T* End(T(&array)[N]) { |
| 88 return array + N; |
84 } | 89 } |
85 | 90 |
86 // static | 91 // static |
87 AllocationContext AllocationContextTracker::GetContext() { | 92 AllocationContext AllocationContextTracker::GetContextSnapshot() { |
88 // TODO(ruuda): Implement this in a follow-up CL. | 93 AllocationContextTracker* tracker = GetThreadLocalTracker(); |
89 return AllocationContext(); | 94 AllocationContext ctx; |
| 95 |
| 96 // Fill the backtrace. |
| 97 { |
| 98 auto src = tracker->pseudo_stack_.bottom(); |
| 99 auto dst = ctx.backtrace.frames; |
| 100 auto src_end = tracker->pseudo_stack_.top(); |
| 101 auto dst_end = End(ctx.backtrace.frames); |
| 102 |
| 103 // Copy as much of the bottom of the pseudo stack into the backtrace as |
| 104 // possible. |
| 105 for (; src != src_end && dst != dst_end; src++, dst++) |
| 106 *dst = *src; |
| 107 |
| 108 // If there is room for more, fill the remaining slots with empty frames. |
| 109 std::fill(dst, dst_end, nullptr); |
| 110 } |
| 111 |
| 112 // Fill the context fields. |
| 113 { |
| 114 auto src = tracker->context_.begin(); |
| 115 auto dst = ctx.fields; |
| 116 auto src_end = tracker->context_.end(); |
| 117 auto dst_end = End(ctx.fields); |
| 118 |
| 119 // Copy as much (key, value) pairs as possible. |
| 120 for (; src != src_end && dst != dst_end; src++, dst++) |
| 121 *dst = *src; |
| 122 |
| 123 // If there is room for more, fill the remaining slots with nullptr keys. |
| 124 for (; dst != dst_end; dst++) |
| 125 dst->first = nullptr; |
| 126 } |
| 127 |
| 128 return ctx; |
90 } | 129 } |
91 | 130 |
92 } // namespace trace_event | 131 } // namespace trace_event |
93 } // namespace base | 132 } // namespace base |
OLD | NEW |