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 |