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 |