OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "gpu/command_buffer/service/gpu_tracer.h" | 5 #include "gpu/command_buffer/service/gpu_tracer.h" |
6 | 6 |
7 #include <deque> | 7 #include <deque> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
13 #include "gpu/command_buffer/common/gles2_cmd_utils.h" | 13 #include "gpu/command_buffer/common/gles2_cmd_utils.h" |
14 | 14 |
15 namespace gpu { | 15 namespace gpu { |
16 namespace gles2 { | 16 namespace gles2 { |
17 | 17 |
18 static const unsigned int kProcessInterval = 16; | 18 static const unsigned int kProcessInterval = 16; |
19 static TraceOutputter* g_outputter_thread = NULL; | 19 static TraceOutputter* g_outputter_thread = NULL; |
20 | 20 |
21 TraceMarker::TraceMarker(const std::string& name) | 21 TraceMarker::TraceMarker(const std::string& category, const std::string& name) |
22 : name_(name), | 22 : category_(category), |
| 23 name_(name), |
23 trace_(NULL) { | 24 trace_(NULL) { |
24 } | 25 } |
25 | 26 |
26 TraceMarker::~TraceMarker() { | 27 TraceMarker::~TraceMarker() { |
27 } | 28 } |
28 | 29 |
29 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) { | 30 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) { |
30 if (!g_outputter_thread) { | 31 if (!g_outputter_thread) { |
31 g_outputter_thread = new TraceOutputter(name); | 32 g_outputter_thread = new TraceOutputter(name); |
32 } | 33 } |
33 return g_outputter_thread; | 34 return g_outputter_thread; |
34 } | 35 } |
35 | 36 |
36 TraceOutputter::TraceOutputter(const std::string& name) | 37 TraceOutputter::TraceOutputter(const std::string& name) |
37 : named_thread_(name.c_str()), local_trace_id_(0) { | 38 : named_thread_(name.c_str()), local_trace_id_(0) { |
38 named_thread_.Start(); | 39 named_thread_.Start(); |
39 named_thread_.Stop(); | 40 named_thread_.Stop(); |
40 } | 41 } |
41 | 42 |
42 TraceOutputter::~TraceOutputter() { g_outputter_thread = NULL; } | 43 TraceOutputter::~TraceOutputter() { g_outputter_thread = NULL; } |
43 | 44 |
44 void TraceOutputter::Trace(const std::string& name, | 45 void TraceOutputter::Trace(const std::string& category, |
| 46 const std::string& name, |
45 int64 start_time, | 47 int64 start_time, |
46 int64 end_time) { | 48 int64 end_time) { |
47 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( | 49 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category.c_str(), |
48 TRACE_DISABLED_BY_DEFAULT("gpu.device"), | 50 name.c_str(), |
49 name.c_str(), | 51 local_trace_id_, |
50 local_trace_id_, | 52 named_thread_.thread_id(), |
51 named_thread_.thread_id(), | 53 start_time); |
52 start_time); | 54 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0(category.c_str(), |
53 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( | 55 name.c_str(), |
54 TRACE_DISABLED_BY_DEFAULT("gpu.device"), | 56 local_trace_id_, |
55 name.c_str(), | 57 named_thread_.thread_id(), |
56 local_trace_id_, | 58 end_time); |
57 named_thread_.thread_id(), | |
58 end_time); | |
59 ++local_trace_id_; | 59 ++local_trace_id_; |
60 } | 60 } |
61 | 61 |
62 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter, | 62 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter, |
| 63 const std::string& category, |
63 const std::string& name, | 64 const std::string& name, |
64 int64 offset, | 65 int64 offset, |
65 GpuTracerType tracer_type) | 66 GpuTracerType tracer_type) |
66 : name_(name), | 67 : category_(category), |
| 68 name_(name), |
67 outputter_(outputter), | 69 outputter_(outputter), |
68 offset_(offset), | 70 offset_(offset), |
69 start_time_(0), | 71 start_time_(0), |
70 end_time_(0), | 72 end_time_(0), |
71 tracer_type_(tracer_type), | 73 tracer_type_(tracer_type), |
72 end_requested_(false) { | 74 end_requested_(false) { |
73 memset(queries_, 0, sizeof(queries_)); | 75 memset(queries_, 0, sizeof(queries_)); |
74 switch (tracer_type_) { | 76 switch (tracer_type_) { |
75 case kTracerTypeARBTimer: | 77 case kTracerTypeARBTimer: |
76 case kTracerTypeDisjointTimer: | 78 case kTracerTypeDisjointTimer: |
(...skipping 10 matching lines...) Expand all Loading... |
87 case kTracerTypeInvalid: | 89 case kTracerTypeInvalid: |
88 break; | 90 break; |
89 | 91 |
90 case kTracerTypeARBTimer: | 92 case kTracerTypeARBTimer: |
91 case kTracerTypeDisjointTimer: | 93 case kTracerTypeDisjointTimer: |
92 glDeleteQueriesARB(2, queries_); | 94 glDeleteQueriesARB(2, queries_); |
93 break; | 95 break; |
94 } | 96 } |
95 } | 97 } |
96 | 98 |
97 void GPUTrace::Start() { | 99 void GPUTrace::Start(bool trace_service) { |
98 TRACE_EVENT_COPY_ASYNC_BEGIN0( | 100 if (trace_service) { |
99 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | 101 TRACE_EVENT_COPY_ASYNC_BEGIN0(category().c_str(), name().c_str(), this); |
| 102 } |
100 | 103 |
101 switch (tracer_type_) { | 104 switch (tracer_type_) { |
102 case kTracerTypeInvalid: | 105 case kTracerTypeInvalid: |
103 break; | 106 break; |
104 | 107 |
105 case kTracerTypeDisjointTimer: | 108 case kTracerTypeDisjointTimer: |
106 // For the disjoint timer, GPU idle time does not seem to increment the | 109 // For the disjoint timer, GPU idle time does not seem to increment the |
107 // internal counter. We must calculate the offset before any query. The | 110 // internal counter. We must calculate the offset before any query. The |
108 // good news is any device that supports disjoint timer will also support | 111 // good news is any device that supports disjoint timer will also support |
109 // glGetInteger64v, so we can query it directly unlike the ARBTimer case. | 112 // glGetInteger64v, so we can query it directly unlike the ARBTimer case. |
110 // The "offset_" variable will always be 0 during normal use cases, only | 113 // The "offset_" variable will always be 0 during normal use cases, only |
111 // under the unit tests will it be set to specific test values. | 114 // under the unit tests will it be set to specific test values. |
112 if (offset_ == 0) { | 115 if (offset_ == 0) { |
113 GLint64 gl_now = 0; | 116 GLint64 gl_now = 0; |
114 glGetInteger64v(GL_TIMESTAMP, &gl_now); | 117 glGetInteger64v(GL_TIMESTAMP, &gl_now); |
115 offset_ = base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() - | 118 offset_ = base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() - |
116 gl_now / base::Time::kNanosecondsPerMicrosecond; | 119 gl_now / base::Time::kNanosecondsPerMicrosecond; |
117 } | 120 } |
118 // Intentionally fall through to kTracerTypeARBTimer case.xs | 121 // Intentionally fall through to kTracerTypeARBTimer case.xs |
119 case kTracerTypeARBTimer: | 122 case kTracerTypeARBTimer: |
120 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. | 123 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. |
121 glQueryCounter(queries_[0], GL_TIMESTAMP); | 124 glQueryCounter(queries_[0], GL_TIMESTAMP); |
122 break; | 125 break; |
123 } | 126 } |
124 } | 127 } |
125 | 128 |
126 void GPUTrace::End() { | 129 void GPUTrace::End(bool tracing_service) { |
127 end_requested_ = true; | 130 end_requested_ = true; |
128 switch (tracer_type_) { | 131 switch (tracer_type_) { |
129 case kTracerTypeInvalid: | 132 case kTracerTypeInvalid: |
130 break; | 133 break; |
131 | 134 |
132 case kTracerTypeARBTimer: | 135 case kTracerTypeARBTimer: |
133 case kTracerTypeDisjointTimer: | 136 case kTracerTypeDisjointTimer: |
134 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. | 137 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. |
135 glQueryCounter(queries_[1], GL_TIMESTAMP); | 138 glQueryCounter(queries_[1], GL_TIMESTAMP); |
136 break; | 139 break; |
137 } | 140 } |
138 | 141 |
139 TRACE_EVENT_COPY_ASYNC_END0( | 142 if (tracing_service) { |
140 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | 143 TRACE_EVENT_COPY_ASYNC_END0(category().c_str(), name().c_str(), this); |
| 144 } |
141 } | 145 } |
142 | 146 |
143 bool GPUTrace::IsAvailable() { | 147 bool GPUTrace::IsAvailable() { |
144 if (tracer_type_ != kTracerTypeInvalid) { | 148 if (tracer_type_ != kTracerTypeInvalid) { |
145 if (!end_requested_) | 149 if (!end_requested_) |
146 return false; | 150 return false; |
147 | 151 |
148 GLint done = 0; | 152 GLint done = 0; |
149 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | 153 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
150 return !!done; | 154 return !!done; |
(...skipping 13 matching lines...) Expand all Loading... |
164 | 168 |
165 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | 169 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
166 // We need to detect if the end is less then the start and correct for the | 170 // We need to detect if the end is less then the start and correct for the |
167 // wrapping. | 171 // wrapping. |
168 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); | 172 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); |
169 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); | 173 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); |
170 | 174 |
171 start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + | 175 start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + |
172 offset_; | 176 offset_; |
173 end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 177 end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
174 outputter_->Trace(name(), start_time_, end_time_); | 178 outputter_->Trace(category(), name(), start_time_, end_time_); |
175 } | 179 } |
176 | 180 |
177 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) | 181 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
178 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 182 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
179 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), | 183 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
180 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 184 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
181 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), | 185 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
182 decoder_(decoder), | 186 decoder_(decoder), |
183 timer_offset_(0), | 187 timer_offset_(0), |
184 last_tracer_source_(kTraceGroupInvalid), | 188 last_tracer_source_(kTraceGroupInvalid), |
(...skipping 23 matching lines...) Expand all Loading... |
208 if (IsTracing()) { | 212 if (IsTracing()) { |
209 // Reset disjoint bit for the disjoint timer. | 213 // Reset disjoint bit for the disjoint timer. |
210 if (tracer_type_ == kTracerTypeDisjointTimer) { | 214 if (tracer_type_ == kTracerTypeDisjointTimer) { |
211 GLint disjoint_value = 0; | 215 GLint disjoint_value = 0; |
212 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | 216 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
213 } | 217 } |
214 | 218 |
215 // Begin a Trace for all active markers | 219 // Begin a Trace for all active markers |
216 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { | 220 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
217 for (size_t i = 0; i < markers_[n].size(); i++) { | 221 for (size_t i = 0; i < markers_[n].size(); i++) { |
218 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); | 222 TraceMarker& trace_marker = markers_[n][i]; |
219 markers_[n][i].trace_->Start(); | 223 trace_marker.trace_ = CreateTrace(trace_marker.category_, |
| 224 trace_marker.name_); |
| 225 trace_marker.trace_->Start(*gpu_trace_srv_category != 0); |
220 } | 226 } |
221 } | 227 } |
222 } | 228 } |
223 return true; | 229 return true; |
224 } | 230 } |
225 | 231 |
226 bool GPUTracer::EndDecoding() { | 232 bool GPUTracer::EndDecoding() { |
227 if (!gpu_executing_) | 233 if (!gpu_executing_) |
228 return false; | 234 return false; |
229 | 235 |
230 // End Trace for all active markers | 236 // End Trace for all active markers |
231 if (IsTracing()) { | 237 if (IsTracing()) { |
232 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { | 238 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
233 for (size_t i = 0; i < markers_[n].size(); i++) { | 239 for (size_t i = 0; i < markers_[n].size(); i++) { |
234 if (markers_[n][i].trace_.get()) { | 240 if (markers_[n][i].trace_.get()) { |
235 markers_[n][i].trace_->End(); | 241 markers_[n][i].trace_->End(*gpu_trace_srv_category != 0); |
236 if (markers_[n][i].trace_->IsEnabled()) | 242 if (markers_[n][i].trace_->IsEnabled()) |
237 traces_.push_back(markers_[n][i].trace_); | 243 traces_.push_back(markers_[n][i].trace_); |
238 markers_[n][i].trace_ = 0; | 244 markers_[n][i].trace_ = 0; |
239 } | 245 } |
240 } | 246 } |
241 } | 247 } |
242 IssueProcessTask(); | 248 IssueProcessTask(); |
243 } | 249 } |
244 | 250 |
245 gpu_executing_ = false; | 251 gpu_executing_ = false; |
246 | 252 |
247 // NOTE(vmiura): glFlush() here can help give better trace results, | 253 // NOTE(vmiura): glFlush() here can help give better trace results, |
248 // but it distorts the normal device behavior. | 254 // but it distorts the normal device behavior. |
249 return true; | 255 return true; |
250 } | 256 } |
251 | 257 |
252 bool GPUTracer::Begin(const std::string& name, GpuTracerSource source) { | 258 bool GPUTracer::Begin(const std::string& category, const std::string& name, |
| 259 GpuTracerSource source) { |
253 if (!gpu_executing_) | 260 if (!gpu_executing_) |
254 return false; | 261 return false; |
255 | 262 |
256 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES); | 263 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES); |
257 | 264 |
258 // Push new marker from given 'source' | 265 // Push new marker from given 'source' |
259 last_tracer_source_ = source; | 266 last_tracer_source_ = source; |
260 markers_[source].push_back(TraceMarker(name)); | 267 markers_[source].push_back(TraceMarker(category, name)); |
261 | 268 |
262 // Create trace | 269 // Create trace |
263 if (IsTracing()) { | 270 if (IsTracing()) { |
264 scoped_refptr<GPUTrace> trace = CreateTrace(name); | 271 scoped_refptr<GPUTrace> trace = CreateTrace(category, name); |
265 trace->Start(); | 272 trace->Start(*gpu_trace_srv_category != 0); |
266 markers_[source].back().trace_ = trace; | 273 markers_[source].back().trace_ = trace; |
267 } | 274 } |
268 | 275 |
269 return true; | 276 return true; |
270 } | 277 } |
271 | 278 |
272 bool GPUTracer::End(GpuTracerSource source) { | 279 bool GPUTracer::End(GpuTracerSource source) { |
273 if (!gpu_executing_) | 280 if (!gpu_executing_) |
274 return false; | 281 return false; |
275 | 282 |
276 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES); | 283 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES); |
277 | 284 |
278 // Pop last marker with matching 'source' | 285 // Pop last marker with matching 'source' |
279 if (!markers_[source].empty()) { | 286 if (!markers_[source].empty()) { |
280 if (IsTracing()) { | 287 if (IsTracing()) { |
281 scoped_refptr<GPUTrace> trace = markers_[source].back().trace_; | 288 scoped_refptr<GPUTrace> trace = markers_[source].back().trace_; |
282 if (trace.get()) { | 289 if (trace.get()) { |
283 trace->End(); | 290 trace->End(*gpu_trace_srv_category != 0); |
284 if (trace->IsEnabled()) | 291 if (trace->IsEnabled()) |
285 traces_.push_back(trace); | 292 traces_.push_back(trace); |
286 IssueProcessTask(); | 293 IssueProcessTask(); |
287 } | 294 } |
288 } | 295 } |
289 | 296 |
290 markers_[source].pop_back(); | 297 markers_[source].pop_back(); |
291 return true; | 298 return true; |
292 } | 299 } |
293 return false; | 300 return false; |
294 } | 301 } |
295 | 302 |
296 bool GPUTracer::IsTracing() { | 303 bool GPUTracer::IsTracing() { |
297 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); | 304 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); |
298 } | 305 } |
299 | 306 |
| 307 const std::string& GPUTracer::CurrentCategory() const { |
| 308 if (last_tracer_source_ >= 0 && |
| 309 last_tracer_source_ < NUM_TRACER_SOURCES && |
| 310 !markers_[last_tracer_source_].empty()) { |
| 311 return markers_[last_tracer_source_].back().category_; |
| 312 } |
| 313 return base::EmptyString(); |
| 314 } |
| 315 |
300 const std::string& GPUTracer::CurrentName() const { | 316 const std::string& GPUTracer::CurrentName() const { |
301 if (last_tracer_source_ >= 0 && | 317 if (last_tracer_source_ >= 0 && |
302 last_tracer_source_ < NUM_TRACER_SOURCES && | 318 last_tracer_source_ < NUM_TRACER_SOURCES && |
303 !markers_[last_tracer_source_].empty()) { | 319 !markers_[last_tracer_source_].empty()) { |
304 return markers_[last_tracer_source_].back().name_; | 320 return markers_[last_tracer_source_].back().name_; |
305 } | 321 } |
306 return base::EmptyString(); | 322 return base::EmptyString(); |
307 } | 323 } |
308 | 324 |
309 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& name) { | 325 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& category, |
| 326 const std::string& name) { |
310 GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : | 327 GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : |
311 kTracerTypeInvalid; | 328 kTracerTypeInvalid; |
312 | 329 |
313 return new GPUTrace(outputter_, name, timer_offset_, tracer_type); | 330 return new GPUTrace(outputter_, category, name, timer_offset_, tracer_type); |
314 } | 331 } |
315 | 332 |
316 void GPUTracer::Process() { | 333 void GPUTracer::Process() { |
317 process_posted_ = false; | 334 process_posted_ = false; |
318 ProcessTraces(); | 335 ProcessTraces(); |
319 IssueProcessTask(); | 336 IssueProcessTask(); |
320 } | 337 } |
321 | 338 |
322 void GPUTracer::ProcessTraces() { | 339 void GPUTracer::ProcessTraces() { |
323 if (tracer_type_ == kTracerTypeInvalid) { | 340 if (tracer_type_ == kTracerTypeInvalid) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 | 415 |
399 process_posted_ = true; | 416 process_posted_ = true; |
400 base::MessageLoop::current()->PostDelayedTask( | 417 base::MessageLoop::current()->PostDelayedTask( |
401 FROM_HERE, | 418 FROM_HERE, |
402 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), | 419 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), |
403 base::TimeDelta::FromMilliseconds(kProcessInterval)); | 420 base::TimeDelta::FromMilliseconds(kProcessInterval)); |
404 } | 421 } |
405 | 422 |
406 } // namespace gles2 | 423 } // namespace gles2 |
407 } // namespace gpu | 424 } // namespace gpu |
OLD | NEW |