Chromium Code Reviews| 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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 78 g_tls_alloc_ctx_tracker.Set(tracker); | 78 g_tls_alloc_ctx_tracker.Set(tracker); |
| 79 } | 79 } |
| 80 | 80 |
| 81 return tracker; | 81 return tracker; |
| 82 } | 82 } |
| 83 | 83 |
| 84 AllocationContextTracker::AllocationContextTracker() | 84 AllocationContextTracker::AllocationContextTracker() |
| 85 : thread_name_(nullptr), ignore_scope_depth_(0) { | 85 : thread_name_(nullptr), ignore_scope_depth_(0) { |
| 86 pseudo_stack_.reserve(kMaxStackDepth); | 86 pseudo_stack_.reserve(kMaxStackDepth); |
| 87 task_contexts_.reserve(kMaxTaskDepth); | 87 task_contexts_.reserve(kMaxTaskDepth); |
| 88 trace_categories_.reserve(kMaxStackDepth); | |
| 88 } | 89 } |
| 89 AllocationContextTracker::~AllocationContextTracker() {} | 90 AllocationContextTracker::~AllocationContextTracker() {} |
| 90 | 91 |
| 91 // static | 92 // static |
| 92 void AllocationContextTracker::SetCurrentThreadName(const char* name) { | 93 void AllocationContextTracker::SetCurrentThreadName(const char* name) { |
| 93 if (name && capture_mode() != CaptureMode::DISABLED) { | 94 if (name && capture_mode() != CaptureMode::DISABLED) { |
| 94 GetInstanceForCurrentThread()->thread_name_ = name; | 95 GetInstanceForCurrentThread()->thread_name_ = name; |
| 95 } | 96 } |
| 96 } | 97 } |
| 97 | 98 |
| 98 // static | 99 // static |
| 99 void AllocationContextTracker::SetCaptureMode(CaptureMode mode) { | 100 void AllocationContextTracker::SetCaptureMode(CaptureMode mode) { |
| 100 // When enabling capturing, also initialize the TLS slot. This does not create | 101 // When enabling capturing, also initialize the TLS slot. This does not create |
| 101 // a TLS instance yet. | 102 // a TLS instance yet. |
| 102 if (mode != CaptureMode::DISABLED && !g_tls_alloc_ctx_tracker.initialized()) | 103 if (mode != CaptureMode::DISABLED && !g_tls_alloc_ctx_tracker.initialized()) |
| 103 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); | 104 g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker); |
| 104 | 105 |
| 105 // Release ordering ensures that when a thread observes |capture_mode_| to | 106 // Release ordering ensures that when a thread observes |capture_mode_| to |
| 106 // be true through an acquire load, the TLS slot has been initialized. | 107 // be true through an acquire load, the TLS slot has been initialized. |
| 107 subtle::Release_Store(&capture_mode_, static_cast<int32_t>(mode)); | 108 subtle::Release_Store(&capture_mode_, static_cast<int32_t>(mode)); |
| 108 } | 109 } |
| 109 | 110 |
| 110 void AllocationContextTracker::PushPseudoStackFrame( | 111 void AllocationContextTracker::PushPseudoStackFrame( |
| 112 const char* category, | |
|
Primiano Tucci (use gerrit)
2016/08/25 16:31:15
s/category/trace_event_category/ for consistency w
ssid
2016/08/25 19:05:39
I just wanted the declaration in header file to fi
| |
| 111 const char* trace_event_name) { | 113 const char* trace_event_name) { |
| 112 // Impose a limit on the height to verify that every push is popped, because | 114 // 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. | 115 // in practice the pseudo stack never grows higher than ~20 frames. |
| 114 if (pseudo_stack_.size() < kMaxStackDepth) | 116 if (pseudo_stack_.size() < kMaxStackDepth) |
| 115 pseudo_stack_.push_back(trace_event_name); | 117 pseudo_stack_.push_back(trace_event_name); |
| 116 else | 118 else |
| 117 NOTREACHED(); | 119 NOTREACHED(); |
| 120 | |
| 121 // Ignore the category name if it has "," since it is confusing in UI. | |
| 122 if (strchr(category, ',') == nullptr && | |
|
Primiano Tucci (use gerrit)
2016/08/25 16:31:15
Can we do this check in the UI? This is going to s
ssid
2016/08/25 19:05:39
Yess, that is the reason I have a separate stack f
| |
| 123 trace_categories_.size() < kMaxStackDepth) { | |
| 124 trace_categories_.push_back(category); | |
| 125 } else { | |
| 126 DCHECK_LE(trace_categories_.size(), kMaxStackDepth); | |
| 127 } | |
| 118 } | 128 } |
| 119 | 129 |
| 120 void AllocationContextTracker::PopPseudoStackFrame( | 130 void AllocationContextTracker::PopPseudoStackFrame( |
| 131 const char* category, | |
| 121 const char* trace_event_name) { | 132 const char* trace_event_name) { |
| 122 // Guard for stack underflow. If tracing was started with a TRACE_EVENT in | 133 // 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 | 134 // scope, the frame was never pushed, so it is possible that pop is called |
| 124 // on an empty stack. | 135 // on an empty stack. |
| 125 if (pseudo_stack_.empty()) | 136 if (pseudo_stack_.empty()) |
| 126 return; | 137 return; |
| 127 | 138 |
| 128 // Assert that pushes and pops are nested correctly. This DCHECK can be | 139 // 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 | 140 // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call |
| 130 // without a corresponding TRACE_EVENT_BEGIN). | 141 // without a corresponding TRACE_EVENT_BEGIN). |
| 131 DCHECK_EQ(trace_event_name, pseudo_stack_.back()) | 142 DCHECK_EQ(trace_event_name, pseudo_stack_.back()) |
| 132 << "Encountered an unmatched TRACE_EVENT_END"; | 143 << "Encountered an unmatched TRACE_EVENT_END"; |
| 133 | 144 |
| 134 pseudo_stack_.pop_back(); | 145 pseudo_stack_.pop_back(); |
| 146 | |
| 147 if (!trace_categories_.empty() && trace_categories_.back() == category) | |
| 148 trace_categories_.pop_back(); | |
| 149 else | |
| 150 DCHECK(strchr(category, ',')); | |
| 135 } | 151 } |
| 136 | 152 |
| 137 void AllocationContextTracker::PushCurrentTaskContext(const char* context) { | 153 void AllocationContextTracker::PushCurrentTaskContext(const char* context) { |
| 138 DCHECK(context); | 154 DCHECK(context); |
| 139 if (task_contexts_.size() < kMaxTaskDepth) | 155 if (task_contexts_.size() < kMaxTaskDepth) |
| 140 task_contexts_.push_back(context); | 156 task_contexts_.push_back(context); |
| 141 else | 157 else |
| 142 NOTREACHED(); | 158 NOTREACHED(); |
| 143 } | 159 } |
| 144 | 160 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 *backtrace++ = StackFrame::FromThreadName(thread_name_); | 202 *backtrace++ = StackFrame::FromThreadName(thread_name_); |
| 187 } | 203 } |
| 188 | 204 |
| 189 switch (mode) { | 205 switch (mode) { |
| 190 case CaptureMode::DISABLED: | 206 case CaptureMode::DISABLED: |
| 191 { | 207 { |
| 192 break; | 208 break; |
| 193 } | 209 } |
| 194 case CaptureMode::PSEUDO_STACK: | 210 case CaptureMode::PSEUDO_STACK: |
| 195 { | 211 { |
| 196 for (const char* event_name: pseudo_stack_) { | 212 for (const char* event_name : pseudo_stack_) { |
| 197 if (backtrace == backtrace_end) { | 213 if (backtrace == backtrace_end) { |
| 198 break; | 214 break; |
| 199 } | 215 } |
| 200 *backtrace++ = StackFrame::FromTraceEventName(event_name); | 216 *backtrace++ = StackFrame::FromTraceEventName(event_name); |
| 201 } | 217 } |
| 202 break; | 218 break; |
| 203 } | 219 } |
| 204 case CaptureMode::NATIVE_STACK: | 220 case CaptureMode::NATIVE_STACK: |
| 205 { | 221 { |
| 206 // Backtrace contract requires us to return bottom frames, i.e. | 222 // Backtrace contract requires us to return bottom frames, i.e. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 230 *backtrace++ = StackFrame::FromProgramCounter(frame); | 246 *backtrace++ = StackFrame::FromProgramCounter(frame); |
| 231 } | 247 } |
| 232 break; | 248 break; |
| 233 } | 249 } |
| 234 } | 250 } |
| 235 | 251 |
| 236 ctx.backtrace.frame_count = backtrace - std::begin(ctx.backtrace.frames); | 252 ctx.backtrace.frame_count = backtrace - std::begin(ctx.backtrace.frames); |
| 237 | 253 |
| 238 // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension | 254 // 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. | 255 // (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(); | 256 if (!task_contexts_.empty()) { |
| 257 ctx.type_name = task_contexts_.back(); | |
| 258 } else if (!trace_categories_.empty()) { | |
| 259 ctx.type_name = trace_categories_.back(); | |
| 260 } | |
| 241 | 261 |
| 242 return ctx; | 262 return ctx; |
| 243 } | 263 } |
| 244 | 264 |
| 245 } // namespace trace_event | 265 } // namespace trace_event |
| 246 } // namespace base | 266 } // namespace base |
| OLD | NEW |