| 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 |