Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(498)

Unified Diff: base/trace_event/heap_profiler_allocation_context_tracker.cc

Issue 1839503002: [tracing] Add native allocation tracing mode. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add type to StackFrame; format thread name Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/trace_event/heap_profiler_allocation_context_tracker.cc
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
index 1fc8bc008a522419f7b1eb454c9b45a6d8c739b0..13e13c4cc349a6ed12745cadf55a9777e33d32e0 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker.cc
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <iterator>
+#include "base/allocator/features.h"
#include "base/atomicops.h"
#include "base/threading/thread_local_storage.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
@@ -14,7 +15,8 @@
namespace base {
namespace trace_event {
-subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0;
+subtle::Atomic32 AllocationContextTracker::capture_mode_ =
+ AllocationContextTracker::DONT_CAPTURE;
namespace {
@@ -31,6 +33,59 @@ void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
}
+// Walks stack frames and collects a trace. Unlike base::debug::StackTrace
+// (which uses unwinding) this function uses frame pointers and is fast.
+// However, by default frame pointers are not enabled in optimized builds
+// unless -fno-omit-frame-pointer flag is specified.
+// Adapted from TCMalloc's stacktrace_x86-inl.h
+size_t WalkStackFrames(const void** trace,
+ size_t max_depth,
+ size_t skip_count) {
+ uintptr_t sp = reinterpret_cast<uintptr_t>(
Primiano Tucci (use gerrit) 2016/04/07 15:51:56 Should this have a #if !BUILDFLAG(ENABLE_PROFILIN
+ __builtin_frame_address(0));
+
+ size_t n = 0;
+ while (sp && n < max_depth) {
+ if (reinterpret_cast<void**>(sp)[1] == nullptr) {
+ // In 64-bit code, we often see a frame that
+ // points to itself and has a return address of 0.
+ break;
+ }
+
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ trace[n] = reinterpret_cast<void**>(sp)[1];
+ n++;
+ }
+
+ {
+ uintptr_t next_sp = reinterpret_cast<uintptr_t*>(sp)[0];
+
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (next_sp <= sp) break;
+
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if (next_sp - sp > 100000) break;
+
+ // Check alignment.
+ if (next_sp & (sizeof(void*) - 1)) break;
+
+#ifdef __i386__
+ // On 64-bit machines, the stack pointer can be very close to
+ // 0xffffffff, so we explicitly check for a pointer into the
+ // last two pages in the address space
+ if (next_sp >= 0xffffe000) break;
+#endif
+
+ sp = next_sp;
+ }
+ }
+
+ return n;
+}
+
} // namespace
// static
@@ -64,15 +119,19 @@ void AllocationContextTracker::SetCurrentThreadName(const char* name) {
}
// static
-void AllocationContextTracker::SetCaptureEnabled(bool enabled) {
+void AllocationContextTracker::SetCaptureMode(CaptureMode mode) {
// When enabling capturing, also initialize the TLS slot. This does not create
// a TLS instance yet.
- if (enabled && !g_tls_alloc_ctx_tracker.initialized())
+ if (mode != DONT_CAPTURE && !g_tls_alloc_ctx_tracker.initialized())
g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
- // Release ordering ensures that when a thread observes |capture_enabled_| to
+ // Release ordering ensures that when a thread observes |capture_mode_| to
// be true through an acquire load, the TLS slot has been initialized.
- subtle::Release_Store(&capture_enabled_, enabled);
+ subtle::Release_Store(&capture_mode_, mode);
+}
+
+void AllocationContextTracker::PushPseudoStackFrame(const char* frame_value) {
+ PushPseudoStackFrame(StackFrame::FromSymbol(frame_value));
}
void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
@@ -84,8 +143,7 @@ void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
NOTREACHED();
}
-// static
-void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
+void AllocationContextTracker::PopPseudoStackFrame(const void* frame_value) {
// Guard for stack underflow. If tracing was started with a TRACE_EVENT in
// scope, the frame was never pushed, so it is possible that pop is called
// on an empty stack.
@@ -95,7 +153,7 @@ void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
// Assert that pushes and pops are nested correctly. This DCHECK can be
// hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call
// without a corresponding TRACE_EVENT_BEGIN).
- DCHECK_EQ(frame, pseudo_stack_.back())
+ DCHECK_EQ(frame_value, pseudo_stack_.back().value)
<< "Encountered an unmatched TRACE_EVENT_END";
pseudo_stack_.pop_back();
@@ -115,31 +173,77 @@ void AllocationContextTracker::PopCurrentTaskContext(const char* context) {
task_contexts_.pop_back();
}
-// static
AllocationContext AllocationContextTracker::GetContextSnapshot() {
AllocationContext ctx;
- // Fill the backtrace.
- {
- auto src = pseudo_stack_.begin();
- auto dst = std::begin(ctx.backtrace.frames);
- auto src_end = pseudo_stack_.end();
- auto dst_end = std::end(ctx.backtrace.frames);
-
- // Add the thread name as the first enrty in the backtrace.
- if (thread_name_) {
- DCHECK(dst < dst_end);
- *dst = thread_name_;
- ++dst;
- }
+ CaptureMode mode = static_cast<CaptureMode>(
+ subtle::Acquire_Load(&capture_mode_));
Primiano Tucci (use gerrit) 2016/04/07 15:51:56 We are going to call this on each malloc. I'd keep
Dmitry Skiba 2016/04/12 18:22:11 Done.
+
+ switch (mode) {
+ case DONT_CAPTURE:
+ {
+ NOTREACHED();
+ return AllocationContext::Empty();
+ }
+ case CAPTURE_PSEUDO_STACK:
+ {
+ auto src = pseudo_stack_.begin();
Primiano Tucci (use gerrit) 2016/04/07 15:51:56 I think there is some duplicated logic between thi
Dmitry Skiba 2016/04/12 18:22:11 Done.
+ auto dst = std::begin(ctx.backtrace.frames);
+ auto src_end = pseudo_stack_.end();
+ auto dst_end = std::end(ctx.backtrace.frames);
+
+ // Add the thread name as the first enrty in the backtrace.
+ if (thread_name_) {
+ DCHECK(dst < dst_end);
+ *dst = StackFrame::FromThreadName(thread_name_);
+ ++dst;
+ }
+
+ // 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, StackFrame::Empty());
+
+ break;
+ }
+ case CAPTURE_NATIVE_STACK:
+ {
+ // WalkStackFrames()
+ // base::trace_event::AllocationContextTracker::GetContextSnapshot()
+ const size_t known_frame_count = 2;
+
+ const size_t max_frame_count = arraysize(ctx.backtrace.frames);
+ const void* frames[max_frame_count];
+ size_t frame_count = WalkStackFrames(frames,
+ max_frame_count,
+ known_frame_count);
+
+ size_t frame_shift = 0;
+ if (thread_name_) {
+ ctx.backtrace.frames[frame_shift++] =
+ StackFrame::FromThreadName(thread_name_);
+ }
+
+ if (frame_count + frame_shift > max_frame_count) {
+ frame_count = max_frame_count - frame_shift;
+ }
- // 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;
+ // Copy frames backwards
+ for (size_t i = 0; i != frame_count; ++i) {
+ ctx.backtrace.frames[i + frame_shift] =
+ StackFrame::FromPC(frames[frame_count - 1 - i]);
+ }
- // If there is room for more, fill the remaining slots with empty frames.
- std::fill(dst, dst_end, nullptr);
+ // Fill remainder with empty frames
+ std::fill(ctx.backtrace.frames + frame_shift + frame_count,
+ ctx.backtrace.frames + max_frame_count,
+ StackFrame::Empty());
+ break;
+ }
}
// TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension

Powered by Google App Engine
This is Rietveld 408576698