| Index: base/trace_event/memory_profiler_allocation_context.cc
|
| diff --git a/base/trace_event/memory_profiler_allocation_context.cc b/base/trace_event/memory_profiler_allocation_context.cc
|
| index 99d250fe67c148c92082fb5640102882e4049ad8..b82e2109845b0494c82ee7d689aefe5f7a7d960b 100644
|
| --- a/base/trace_event/memory_profiler_allocation_context.cc
|
| +++ b/base/trace_event/memory_profiler_allocation_context.cc
|
| @@ -4,6 +4,8 @@
|
|
|
| #include "base/trace_event/memory_profiler_allocation_context.h"
|
|
|
| +#include <algorithm>
|
| +
|
| #include "base/threading/thread_local_storage.h"
|
|
|
| namespace base {
|
| @@ -60,7 +62,9 @@ void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
|
| // static
|
| void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
|
| auto tracker = AllocationContextTracker::GetThreadLocalTracker();
|
| - DCHECK_EQ(frame, *tracker->pseudo_stack_.top());
|
| + // Assert that pushes and pops are nested correctly. |top()| points past the
|
| + // top of the stack, so |top() - 1| dereferences to the topmost frame.
|
| + DCHECK_EQ(frame, *(tracker->pseudo_stack_.top() - 1));
|
| tracker->pseudo_stack_.pop();
|
| }
|
|
|
| @@ -77,16 +81,51 @@ void AllocationContextTracker::UnsetContextField(const char* key) {
|
| tracker->context_.erase(key);
|
| }
|
|
|
| -// static
|
| -AllocationStack* AllocationContextTracker::GetPseudoStackForTesting() {
|
| - auto tracker = AllocationContextTracker::GetThreadLocalTracker();
|
| - return &tracker->pseudo_stack_;
|
| +// Returns a pointer past the end of the fixed-size array |array| of |T| of
|
| +// length |N|, identical to C++11 |std::end|.
|
| +template <typename T, int N>
|
| +T* End(T(&array)[N]) {
|
| + return array + N;
|
| }
|
|
|
| // static
|
| -AllocationContext AllocationContextTracker::GetContext() {
|
| - // TODO(ruuda): Implement this in a follow-up CL.
|
| - return AllocationContext();
|
| +AllocationContext AllocationContextTracker::GetContextSnapshot() {
|
| + AllocationContextTracker* tracker = GetThreadLocalTracker();
|
| + AllocationContext ctx;
|
| +
|
| + // Fill the backtrace.
|
| + {
|
| + auto src = tracker->pseudo_stack_.bottom();
|
| + auto dst = ctx.backtrace.frames;
|
| + auto src_end = tracker->pseudo_stack_.top();
|
| + auto dst_end = End(ctx.backtrace.frames);
|
| +
|
| + // Copy as much of the bottom of the pseudo stack into the backtrace as
|
| + // possible.
|
| + for (; src != src_end && dst != dst_end; src++, dst++)
|
| + *dst = *src;
|
| +
|
| + // If there is room for more, fill the remaining slots with empty frames.
|
| + std::fill(dst, dst_end, nullptr);
|
| + }
|
| +
|
| + // Fill the context fields.
|
| + {
|
| + auto src = tracker->context_.begin();
|
| + auto dst = ctx.fields;
|
| + auto src_end = tracker->context_.end();
|
| + auto dst_end = End(ctx.fields);
|
| +
|
| + // Copy as much (key, value) pairs as possible.
|
| + for (; src != src_end && dst != dst_end; src++, dst++)
|
| + *dst = *src;
|
| +
|
| + // If there is room for more, fill the remaining slots with nullptr keys.
|
| + for (; dst != dst_end; dst++)
|
| + dst->first = nullptr;
|
| + }
|
| +
|
| + return ctx;
|
| }
|
|
|
| } // namespace trace_event
|
|
|