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" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
52 start_time); | 52 start_time); |
53 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( | 53 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( |
54 TRACE_DISABLED_BY_DEFAULT("gpu.device"), | 54 TRACE_DISABLED_BY_DEFAULT("gpu.device"), |
55 name.c_str(), | 55 name.c_str(), |
56 local_trace_id_, | 56 local_trace_id_, |
57 named_thread_.thread_id(), | 57 named_thread_.thread_id(), |
58 end_time); | 58 end_time); |
59 ++local_trace_id_; | 59 ++local_trace_id_; |
60 } | 60 } |
61 | 61 |
62 GPUTrace::GPUTrace(const std::string& name) | |
63 : name_(name), | |
64 outputter_(NULL), | |
65 offset_(0), | |
66 end_time_(0), | |
67 end_requested_(false), | |
68 enabled_(false) { | |
69 } | |
70 | |
71 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter, | 62 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter, |
72 const std::string& name, | 63 const std::string& name, |
73 int64 offset) | 64 int64 offset, |
65 GpuTracerType tracer_type) | |
74 : name_(name), | 66 : name_(name), |
75 outputter_(outputter), | 67 outputter_(outputter), |
76 offset_(offset), | 68 offset_(offset), |
77 start_time_(0), | 69 start_time_(0), |
78 end_time_(0), | 70 end_time_(0), |
79 end_requested_(false), | 71 tracer_type_(tracer_type), |
80 enabled_(true) { | 72 end_requested_(false) { |
81 glGenQueries(2, queries_); | 73 memset(queries_, 0, sizeof(queries_)); |
74 switch (tracer_type_) { | |
75 case kTracerTypeARBTimer: | |
76 case kTracerTypeDisjointTimer: | |
77 glGenQueriesARB(2, queries_); | |
78 break; | |
79 | |
80 default: | |
81 tracer_type_ = kTracerTypeInvalid; | |
82 } | |
82 } | 83 } |
83 | 84 |
84 GPUTrace::~GPUTrace() { | 85 GPUTrace::~GPUTrace() { |
85 if (enabled_) | 86 switch (tracer_type_) { |
86 glDeleteQueries(2, queries_); | 87 case kTracerTypeInvalid: |
88 break; | |
89 | |
90 case kTracerTypeARBTimer: | |
91 case kTracerTypeDisjointTimer: | |
92 glDeleteQueriesARB(2, queries_); | |
93 break; | |
94 } | |
87 } | 95 } |
88 | 96 |
89 void GPUTrace::Start() { | 97 void GPUTrace::Start() { |
90 TRACE_EVENT_COPY_ASYNC_BEGIN0( | 98 TRACE_EVENT_COPY_ASYNC_BEGIN0( |
91 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | 99 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
92 if (enabled_) { | 100 |
93 glQueryCounter(queries_[0], GL_TIMESTAMP); | 101 switch (tracer_type_) { |
102 case kTracerTypeInvalid: | |
103 break; | |
104 | |
105 case kTracerTypeARBTimer: | |
106 glQueryCounter(queries_[0], GL_TIMESTAMP); | |
107 break; | |
108 case kTracerTypeDisjointTimer: | |
109 glQueryCounter(queries_[0], GL_TIMESTAMP_EXT); | |
piman
2014/09/02 18:41:44
nit: GL_TIMESTAMP_EXT and GL_TIMESTAMP have the sa
David Yen
2014/09/02 18:45:36
I noticed that as well, but I wanted to follow the
David Yen
2014/09/02 22:03:55
Done.
| |
110 break; | |
94 } | 111 } |
95 } | 112 } |
96 | 113 |
97 void GPUTrace::End() { | 114 void GPUTrace::End() { |
98 if (enabled_) { | 115 end_requested_ = true; |
99 glQueryCounter(queries_[1], GL_TIMESTAMP); | 116 switch (tracer_type_) { |
100 end_requested_ = true; | 117 case kTracerTypeInvalid: |
118 break; | |
119 | |
120 case kTracerTypeARBTimer: | |
121 glQueryCounter(queries_[1], GL_TIMESTAMP); | |
122 break; | |
123 case kTracerTypeDisjointTimer: | |
124 glQueryCounter(queries_[1], GL_TIMESTAMP_EXT); | |
piman
2014/09/02 18:41:44
nit: same here
David Yen
2014/09/02 22:03:55
Done.
| |
125 break; | |
101 } | 126 } |
102 | 127 |
103 TRACE_EVENT_COPY_ASYNC_END0( | 128 TRACE_EVENT_COPY_ASYNC_END0( |
104 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | 129 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
105 } | 130 } |
106 | 131 |
107 bool GPUTrace::IsAvailable() { | 132 bool GPUTrace::IsAvailable() { |
108 if (!enabled_) | 133 if (tracer_type_ != kTracerTypeInvalid) { |
109 return true; | 134 if (!end_requested_) |
110 else if (!end_requested_) | 135 return false; |
111 return false; | |
112 | 136 |
113 GLint done = 0; | 137 GLint done = 0; |
114 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | 138 |
115 return !!done; | 139 switch (tracer_type_) { |
140 case kTracerTypeARBTimer: | |
141 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | |
142 break; | |
143 | |
144 case kTracerTypeDisjointTimer: | |
145 glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE_EXT, | |
146 &done); | |
piman
2014/09/02 18:41:44
Same here with GL_QUERY_RESULT_AVAILABLE_EXT vs GL
David Yen
2014/09/02 22:03:55
Done.
| |
147 break; | |
148 | |
149 default: | |
150 done = 1; | |
151 break; | |
152 } | |
153 | |
154 return !!done; | |
155 } | |
156 | |
157 return true; | |
116 } | 158 } |
117 | 159 |
118 void GPUTrace::Process() { | 160 void GPUTrace::Process() { |
119 if (!enabled_) | 161 if (tracer_type_ == kTracerTypeInvalid) |
120 return; | 162 return; |
121 | 163 |
122 DCHECK(IsAvailable()); | 164 DCHECK(IsAvailable()); |
123 | 165 |
124 GLuint64 timestamp; | 166 GLuint64 begin_stamp = 0; |
167 GLuint64 end_stamp = 0; | |
125 | 168 |
126 // 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. |
127 // 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 |
128 // wrapping. | 171 // wrapping. |
129 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); | 172 switch (tracer_type_) { |
130 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 173 case kTracerTypeARBTimer: |
174 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); | |
175 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); | |
176 break; | |
177 case kTracerTypeDisjointTimer: | |
178 glGetQueryObjectui64vEXT(queries_[0], GL_QUERY_RESULT_EXT, &begin_stamp); | |
179 glGetQueryObjectui64vEXT(queries_[1], GL_QUERY_RESULT_EXT, &end_stamp); | |
piman
2014/09/02 18:41:44
nit: can we collapse those as well?
David Yen
2014/09/02 18:45:36
When I collapsed these, it actually started to cra
David Yen
2014/09/02 22:03:55
Re-did this and the crashing no longer happens, mu
| |
180 break; | |
131 | 181 |
132 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); | 182 default: |
133 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 183 return; |
184 } | |
134 | 185 |
135 glDeleteQueries(2, queries_); | 186 start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + |
187 offset_; | |
188 end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
136 outputter_->Trace(name(), start_time_, end_time_); | 189 outputter_->Trace(name(), start_time_, end_time_); |
137 } | 190 } |
138 | 191 |
139 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) | 192 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
140 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 193 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
141 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), | 194 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
142 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 195 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
143 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), | 196 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
144 decoder_(decoder), | 197 decoder_(decoder), |
145 timer_offset_(0), | 198 timer_offset_(0), |
146 last_tracer_source_(kTraceGroupInvalid), | 199 last_tracer_source_(kTraceGroupInvalid), |
147 enabled_(false), | 200 tracer_type_(kTracerTypeInvalid), |
148 gpu_timing_synced_(false), | 201 gpu_timing_synced_(false), |
149 gpu_executing_(false), | 202 gpu_executing_(false), |
150 process_posted_(false) { | 203 process_posted_(false) { |
151 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | 204 if (gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { |
205 tracer_type_ = kTracerTypeDisjointTimer; | |
206 outputter_ = TraceOutputter::Create("GL_EXT_disjoint_timer_query"); | |
207 } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | |
208 tracer_type_ = kTracerTypeARBTimer; | |
152 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); | 209 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
153 enabled_ = true; | |
154 } | 210 } |
155 } | 211 } |
156 | 212 |
157 GPUTracer::~GPUTracer() { | 213 GPUTracer::~GPUTracer() { |
158 } | 214 } |
159 | 215 |
160 bool GPUTracer::BeginDecoding() { | 216 bool GPUTracer::BeginDecoding() { |
161 if (enabled_) { | |
162 if (*gpu_trace_dev_category) { | |
163 // Make sure timing is synced before tracing | |
164 if (!gpu_timing_synced_) { | |
165 CalculateTimerOffset(); | |
166 gpu_timing_synced_ = true; | |
167 } | |
168 } else { | |
169 // If GPU device category is off, invalidate timing sync | |
170 gpu_timing_synced_ = false; | |
171 } | |
172 } | |
173 | |
174 if (gpu_executing_) | 217 if (gpu_executing_) |
175 return false; | 218 return false; |
176 | 219 |
220 CalculateTimerOffset(); | |
177 gpu_executing_ = true; | 221 gpu_executing_ = true; |
178 | 222 |
179 if (IsTracing()) { | 223 if (IsTracing()) { |
224 // Reset disjoint bit for the disjoint timer. | |
225 if (tracer_type_ == kTracerTypeDisjointTimer) { | |
226 GLint disjoint_value = 0; | |
227 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
228 } | |
229 | |
180 // Begin a Trace for all active markers | 230 // Begin a Trace for all active markers |
181 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { | 231 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
182 for (size_t i = 0; i < markers_[n].size(); i++) { | 232 for (size_t i = 0; i < markers_[n].size(); i++) { |
183 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); | 233 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); |
184 markers_[n][i].trace_->Start(); | 234 markers_[n][i].trace_->Start(); |
185 } | 235 } |
186 } | 236 } |
187 } | 237 } |
188 return true; | 238 return true; |
189 } | 239 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
265 const std::string& GPUTracer::CurrentName() const { | 315 const std::string& GPUTracer::CurrentName() const { |
266 if (last_tracer_source_ >= 0 && | 316 if (last_tracer_source_ >= 0 && |
267 last_tracer_source_ < NUM_TRACER_SOURCES && | 317 last_tracer_source_ < NUM_TRACER_SOURCES && |
268 !markers_[last_tracer_source_].empty()) { | 318 !markers_[last_tracer_source_].empty()) { |
269 return markers_[last_tracer_source_].back().name_; | 319 return markers_[last_tracer_source_].back().name_; |
270 } | 320 } |
271 return base::EmptyString(); | 321 return base::EmptyString(); |
272 } | 322 } |
273 | 323 |
274 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& name) { | 324 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& name) { |
275 if (enabled_ && *gpu_trace_dev_category) | 325 GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : |
276 return new GPUTrace(outputter_, name, timer_offset_); | 326 kTracerTypeInvalid; |
277 else | 327 |
278 return new GPUTrace(name); | 328 return new GPUTrace(outputter_, name, timer_offset_, tracer_type); |
279 } | 329 } |
280 | 330 |
281 void GPUTracer::Process() { | 331 void GPUTracer::Process() { |
282 process_posted_ = false; | 332 process_posted_ = false; |
283 ProcessTraces(); | 333 ProcessTraces(); |
284 IssueProcessTask(); | 334 IssueProcessTask(); |
285 } | 335 } |
286 | 336 |
287 void GPUTracer::ProcessTraces() { | 337 void GPUTracer::ProcessTraces() { |
288 if (!enabled_) { | 338 if (tracer_type_ == kTracerTypeInvalid) { |
289 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 339 traces_.clear(); |
290 traces_.front()->Process(); | |
291 traces_.pop_front(); | |
292 } | |
293 return; | 340 return; |
294 } | 341 } |
295 | 342 |
296 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); | 343 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); |
297 | 344 |
298 // Make owning decoder's GL context current | 345 // Make owning decoder's GL context current |
299 if (!decoder_->MakeCurrent()) { | 346 if (!decoder_->MakeCurrent()) { |
300 // Skip subsequent GL calls if MakeCurrent fails | 347 // Skip subsequent GL calls if MakeCurrent fails |
301 traces_.clear(); | 348 traces_.clear(); |
302 return; | 349 return; |
303 } | 350 } |
304 | 351 |
352 // Check if disjoint operation has occurred, discard ongoing traces if so. | |
353 if (tracer_type_ == kTracerTypeDisjointTimer) { | |
354 GLint disjoint_value = 0; | |
355 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
356 if (disjoint_value) | |
357 traces_.clear(); | |
358 } | |
359 | |
305 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 360 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
306 traces_.front()->Process(); | 361 traces_.front()->Process(); |
307 traces_.pop_front(); | 362 traces_.pop_front(); |
308 } | 363 } |
309 | 364 |
310 // Clear pending traces if there were are any errors | 365 // Clear pending traces if there were are any errors |
311 GLenum err = glGetError(); | 366 GLenum err = glGetError(); |
312 if (err != GL_NO_ERROR) | 367 if (err != GL_NO_ERROR) |
313 traces_.clear(); | 368 traces_.clear(); |
314 } | 369 } |
315 | 370 |
316 void GPUTracer::CalculateTimerOffset() { | 371 void GPUTracer::CalculateTimerOffset() { |
317 if (enabled_) { | 372 if (tracer_type_ != kTracerTypeInvalid) { |
373 // If GPU device category is off, invalidate timing sync. | |
374 if (*gpu_trace_dev_category == '\0') { | |
375 gpu_timing_synced_ = false; | |
376 return; | |
377 } | |
378 | |
379 if (gpu_timing_synced_) | |
380 return; | |
381 | |
318 TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); | 382 TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); |
319 | 383 |
320 // NOTE(vmiura): It would be better to use glGetInteger64v, however | 384 // NOTE(vmiura): It would be better to use glGetInteger64v, however |
321 // it's not available everywhere. | 385 // it's not available everywhere. |
322 GLuint64 gl_now = 0; | 386 GLuint64 gl_now = 0; |
323 GLuint query; | 387 GLuint query; |
324 glFinish(); | 388 GLint disjoint_value = 0; |
325 glGenQueries(1, &query); | 389 |
326 glQueryCounter(query, GL_TIMESTAMP); | 390 switch (tracer_type_) { |
327 glFinish(); | 391 case kTracerTypeARBTimer: |
328 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | 392 glFinish(); |
393 glGenQueriesARB(1, &query); | |
394 glQueryCounter(query, GL_TIMESTAMP); | |
395 glFinish(); | |
396 | |
397 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | |
398 glDeleteQueriesARB(1, &query); | |
399 break; | |
400 | |
401 case kTracerTypeDisjointTimer: | |
402 // Clear the disjoint bit before we do any queries. | |
403 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
404 | |
405 glFinish(); | |
406 glGenQueriesARB(1, &query); | |
407 glQueryCounter(query, GL_TIMESTAMP_EXT); | |
408 glFinish(); | |
409 | |
410 glGetQueryObjectui64vEXT(query, GL_QUERY_RESULT_EXT, &gl_now); | |
411 glDeleteQueriesARB(1, &query); | |
412 | |
413 // Discard results if disjoint operation has occurred. | |
414 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
415 if (disjoint_value) | |
416 return; | |
417 | |
418 break; | |
419 | |
420 default: | |
421 break; | |
422 } | |
423 | |
329 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | 424 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
330 | 425 |
331 gl_now /= base::Time::kNanosecondsPerMicrosecond; | 426 gl_now /= base::Time::kNanosecondsPerMicrosecond; |
332 timer_offset_ = system_now.ToInternalValue() - gl_now; | 427 timer_offset_ = system_now.ToInternalValue() - gl_now; |
333 glDeleteQueries(1, &query); | 428 gpu_timing_synced_ = true; |
334 } | 429 } |
335 } | 430 } |
336 | 431 |
337 void GPUTracer::IssueProcessTask() { | 432 void GPUTracer::IssueProcessTask() { |
338 if (traces_.empty() || process_posted_) | 433 if (traces_.empty() || process_posted_) |
339 return; | 434 return; |
340 | 435 |
341 process_posted_ = true; | 436 process_posted_ = true; |
342 base::MessageLoop::current()->PostDelayedTask( | 437 base::MessageLoop::current()->PostDelayedTask( |
343 FROM_HERE, | 438 FROM_HERE, |
344 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), | 439 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), |
345 base::TimeDelta::FromMilliseconds(kProcessInterval)); | 440 base::TimeDelta::FromMilliseconds(kProcessInterval)); |
346 } | 441 } |
347 | 442 |
348 } // namespace gles2 | 443 } // namespace gles2 |
349 } // namespace gpu | 444 } // namespace gpu |
OLD | NEW |