| 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" |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 // a TLS instance yet. | 101 // a TLS instance yet. |
| 102 if (mode != CaptureMode::DISABLED && !g_tls_alloc_ctx_tracker.initialized()) | 102 if (mode != CaptureMode::DISABLED && !g_tls_alloc_ctx_tracker.initialized()) |
| 103 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); | 103 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); |
| 104 | 104 |
| 105 // Release ordering ensures that when a thread observes |capture_mode_| to | 105 // Release ordering ensures that when a thread observes |capture_mode_| to |
| 106 // be true through an acquire load, the TLS slot has been initialized. | 106 // be true through an acquire load, the TLS slot has been initialized. |
| 107 subtle::Release_Store(&capture_mode_, static_cast<int32_t>(mode)); | 107 subtle::Release_Store(&capture_mode_, static_cast<int32_t>(mode)); |
| 108 } | 108 } |
| 109 | 109 |
| 110 void AllocationContextTracker::PushPseudoStackFrame( | 110 void AllocationContextTracker::PushPseudoStackFrame( |
| 111 const char* trace_event_name) { | 111 AllocationContextTracker::PseudoStackFrame stack_frame) { |
| 112 // Impose a limit on the height to verify that every push is popped, because | 112 // Impose a limit on the height to verify that every push is popped, because |
| 113 // in practice the pseudo stack never grows higher than ~20 frames. | 113 // in practice the pseudo stack never grows higher than ~20 frames. |
| 114 if (pseudo_stack_.size() < kMaxStackDepth) | 114 if (pseudo_stack_.size() < kMaxStackDepth) |
| 115 pseudo_stack_.push_back(trace_event_name); | 115 pseudo_stack_.push_back(stack_frame); |
| 116 else | 116 else |
| 117 NOTREACHED(); | 117 NOTREACHED(); |
| 118 } | 118 } |
| 119 | 119 |
| 120 void AllocationContextTracker::PopPseudoStackFrame( | 120 void AllocationContextTracker::PopPseudoStackFrame( |
| 121 const char* trace_event_name) { | 121 AllocationContextTracker::PseudoStackFrame stack_frame) { |
| 122 // Guard for stack underflow. If tracing was started with a TRACE_EVENT in | 122 // Guard for stack underflow. If tracing was started with a TRACE_EVENT in |
| 123 // scope, the frame was never pushed, so it is possible that pop is called | 123 // scope, the frame was never pushed, so it is possible that pop is called |
| 124 // on an empty stack. | 124 // on an empty stack. |
| 125 if (pseudo_stack_.empty()) | 125 if (pseudo_stack_.empty()) |
| 126 return; | 126 return; |
| 127 | 127 |
| 128 // Assert that pushes and pops are nested correctly. This DCHECK can be | 128 // Assert that pushes and pops are nested correctly. This DCHECK can be |
| 129 // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call | 129 // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call |
| 130 // without a corresponding TRACE_EVENT_BEGIN). | 130 // without a corresponding TRACE_EVENT_BEGIN). |
| 131 DCHECK_EQ(trace_event_name, pseudo_stack_.back()) | 131 DCHECK(stack_frame == pseudo_stack_.back()) |
| 132 << "Encountered an unmatched TRACE_EVENT_END"; | 132 << "Encountered an unmatched TRACE_EVENT_END"; |
| 133 | 133 |
| 134 pseudo_stack_.pop_back(); | 134 pseudo_stack_.pop_back(); |
| 135 } | 135 } |
| 136 | 136 |
| 137 void AllocationContextTracker::PushCurrentTaskContext(const char* context) { | 137 void AllocationContextTracker::PushCurrentTaskContext(const char* context) { |
| 138 DCHECK(context); | 138 DCHECK(context); |
| 139 if (task_contexts_.size() < kMaxTaskDepth) | 139 if (task_contexts_.size() < kMaxTaskDepth) |
| 140 task_contexts_.push_back(context); | 140 task_contexts_.push_back(context); |
| 141 else | 141 else |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 *backtrace++ = StackFrame::FromThreadName(thread_name_); | 186 *backtrace++ = StackFrame::FromThreadName(thread_name_); |
| 187 } | 187 } |
| 188 | 188 |
| 189 switch (mode) { | 189 switch (mode) { |
| 190 case CaptureMode::DISABLED: | 190 case CaptureMode::DISABLED: |
| 191 { | 191 { |
| 192 break; | 192 break; |
| 193 } | 193 } |
| 194 case CaptureMode::PSEUDO_STACK: | 194 case CaptureMode::PSEUDO_STACK: |
| 195 { | 195 { |
| 196 for (const char* event_name: pseudo_stack_) { | 196 for (const PseudoStackFrame& stack_frame : pseudo_stack_) { |
| 197 if (backtrace == backtrace_end) { | 197 if (backtrace == backtrace_end) { |
| 198 break; | 198 break; |
| 199 } | 199 } |
| 200 *backtrace++ = StackFrame::FromTraceEventName(event_name); | 200 *backtrace++ = |
| 201 StackFrame::FromTraceEventName(stack_frame.trace_event_name); |
| 201 } | 202 } |
| 202 break; | 203 break; |
| 203 } | 204 } |
| 204 case CaptureMode::NATIVE_STACK: | 205 case CaptureMode::NATIVE_STACK: |
| 205 { | 206 { |
| 206 // Backtrace contract requires us to return bottom frames, i.e. | 207 // Backtrace contract requires us to return bottom frames, i.e. |
| 207 // from main() and up. Stack unwinding produces top frames, i.e. | 208 // from main() and up. Stack unwinding produces top frames, i.e. |
| 208 // from this point and up until main(). We request many frames to | 209 // from this point and up until main(). We request many frames to |
| 209 // make sure we reach main(), and then copy bottom portion of them. | 210 // make sure we reach main(), and then copy bottom portion of them. |
| 210 const void* frames[128]; | 211 const void* frames[128]; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 230 *backtrace++ = StackFrame::FromProgramCounter(frame); | 231 *backtrace++ = StackFrame::FromProgramCounter(frame); |
| 231 } | 232 } |
| 232 break; | 233 break; |
| 233 } | 234 } |
| 234 } | 235 } |
| 235 | 236 |
| 236 ctx.backtrace.frame_count = backtrace - std::begin(ctx.backtrace.frames); | 237 ctx.backtrace.frame_count = backtrace - std::begin(ctx.backtrace.frames); |
| 237 | 238 |
| 238 // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension | 239 // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension |
| 239 // (component name) in the heap profiler and not piggy back on the type name. | 240 // (component name) in the heap profiler and not piggy back on the type name. |
| 240 ctx.type_name = task_contexts_.empty() ? nullptr : task_contexts_.back(); | 241 if (!task_contexts_.empty()) { |
| 242 ctx.type_name = task_contexts_.back(); |
| 243 } else if (!pseudo_stack_.empty()) { |
| 244 // If task context was unavailable, then the category names are taken from |
| 245 // trace events. |
| 246 ctx.type_name = pseudo_stack_.back().trace_event_category; |
| 247 } |
| 241 | 248 |
| 242 return ctx; | 249 return ctx; |
| 243 } | 250 } |
| 244 | 251 |
| 245 } // namespace trace_event | 252 } // namespace trace_event |
| 246 } // namespace base | 253 } // namespace base |
| OLD | NEW |