Chromium Code Reviews| 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), |
| 71 tracer_type_(tracer_type), | |
| 79 end_requested_(false), | 72 end_requested_(false), |
| 80 enabled_(true) { | 73 discard_trace_(false) { |
| 81 glGenQueries(2, queries_); | 74 memset(queries_, 0, sizeof(queries_)); |
| 75 switch (tracer_type_) { | |
| 76 case kTracerTypeARBTimer: | |
| 77 glGenQueries(2, queries_); | |
| 78 break; | |
| 79 case kTracerTypeDisjointTimer: | |
| 80 glGenQueriesEXT(2, queries_); | |
| 81 break; | |
| 82 | |
| 83 default: | |
| 84 tracer_type_ = kTracerTypeInvalid; | |
| 85 } | |
| 82 } | 86 } |
| 83 | 87 |
| 84 GPUTrace::~GPUTrace() { | 88 GPUTrace::~GPUTrace() { |
| 85 if (enabled_) | 89 switch (tracer_type_) { |
| 86 glDeleteQueries(2, queries_); | 90 case kTracerTypeInvalid: |
| 91 break; | |
| 92 | |
| 93 case kTracerTypeARBTimer: | |
| 94 glDeleteQueries(2, queries_); | |
| 95 break; | |
| 96 case kTracerTypeDisjointTimer: | |
| 97 glDeleteQueriesEXT(2, queries_); | |
| 98 break; | |
| 99 } | |
| 87 } | 100 } |
| 88 | 101 |
| 89 void GPUTrace::Start() { | 102 void GPUTrace::Start() { |
| 90 TRACE_EVENT_COPY_ASYNC_BEGIN0( | 103 TRACE_EVENT_COPY_ASYNC_BEGIN0( |
| 91 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | 104 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
| 92 if (enabled_) { | 105 |
| 93 glQueryCounter(queries_[0], GL_TIMESTAMP); | 106 switch (tracer_type_) { |
| 107 case kTracerTypeInvalid: | |
| 108 break; | |
| 109 | |
| 110 case kTracerTypeARBTimer: | |
| 111 glQueryCounter(queries_[0], GL_TIMESTAMP); | |
| 112 break; | |
| 113 case kTracerTypeDisjointTimer: | |
| 114 glQueryCounterEXT(queries_[0], GL_TIMESTAMP_EXT); | |
| 115 break; | |
| 94 } | 116 } |
| 95 } | 117 } |
| 96 | 118 |
| 97 void GPUTrace::End() { | 119 void GPUTrace::End() { |
| 98 if (enabled_) { | 120 end_requested_ = true; |
| 99 glQueryCounter(queries_[1], GL_TIMESTAMP); | 121 switch (tracer_type_) { |
| 100 end_requested_ = true; | 122 case kTracerTypeInvalid: |
| 123 break; | |
| 124 | |
| 125 case kTracerTypeARBTimer: | |
| 126 glQueryCounter(queries_[1], GL_TIMESTAMP); | |
| 127 break; | |
| 128 case kTracerTypeDisjointTimer: | |
| 129 glQueryCounterEXT(queries_[1], GL_TIMESTAMP_EXT); | |
| 130 break; | |
| 101 } | 131 } |
| 102 | 132 |
| 103 TRACE_EVENT_COPY_ASYNC_END0( | 133 TRACE_EVENT_COPY_ASYNC_END0( |
| 104 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | 134 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
| 105 } | 135 } |
| 106 | 136 |
| 107 bool GPUTrace::IsAvailable() { | 137 bool GPUTrace::IsAvailable() { |
| 108 if (!enabled_) | 138 if (tracer_type_ != kTracerTypeInvalid) { |
| 109 return true; | 139 if (!end_requested_) |
| 110 else if (!end_requested_) | 140 return false; |
| 111 return false; | 141 else if (discard_trace_) |
| 142 return true; | |
| 112 | 143 |
| 113 GLint done = 0; | 144 GLint done = 0; |
| 114 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | 145 |
| 115 return !!done; | 146 switch (tracer_type_) { |
| 147 case kTracerTypeARBTimer: | |
| 148 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | |
| 149 break; | |
| 150 | |
| 151 case kTracerTypeDisjointTimer: | |
| 152 glGetQueryObjectivEXT(queries_[1], GL_QUERY_RESULT_AVAILABLE_EXT, | |
| 153 &done); | |
| 154 break; | |
| 155 | |
| 156 default: | |
| 157 done = 1; | |
| 158 break; | |
| 159 } | |
| 160 | |
| 161 return !!done; | |
| 162 } | |
| 163 | |
| 164 return true; | |
| 116 } | 165 } |
| 117 | 166 |
| 118 void GPUTrace::Process() { | 167 void GPUTrace::Process() { |
| 119 if (!enabled_) | 168 if (tracer_type_ == kTracerTypeInvalid) |
| 120 return; | 169 return; |
| 121 | 170 |
| 122 DCHECK(IsAvailable()); | 171 DCHECK(IsAvailable()); |
| 123 | 172 |
| 124 GLuint64 timestamp; | 173 GLuint64 beg_stamp = 0; |
| 174 GLuint64 end_stamp = 0; | |
| 125 | 175 |
| 126 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | 176 // 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 | 177 // We need to detect if the end is less then the start and correct for the |
| 128 // wrapping. | 178 // wrapping. |
| 129 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); | 179 switch (tracer_type_) { |
| 130 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 180 case kTracerTypeARBTimer: |
| 181 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &beg_stamp); | |
| 182 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); | |
| 183 glDeleteQueries(2, queries_); | |
|
vmiura
2014/08/26 23:47:26
~GPUTrace deletes the queries too so perhaps we sh
David Yen
2014/08/27 19:47:45
Done.
| |
| 184 break; | |
| 185 case kTracerTypeDisjointTimer: | |
| 186 glGetQueryObjectui64vEXT(queries_[0], GL_QUERY_RESULT_EXT, &beg_stamp); | |
| 187 glGetQueryObjectui64vEXT(queries_[1], GL_QUERY_RESULT_EXT, &end_stamp); | |
| 188 glDeleteQueriesEXT(2, queries_); | |
| 189 break; | |
| 131 | 190 |
| 132 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); | 191 default: |
| 133 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 192 return; |
| 193 } | |
| 134 | 194 |
| 135 glDeleteQueries(2, queries_); | 195 if (discard_trace_) |
| 196 return; | |
| 197 | |
| 198 start_time_ = (beg_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
| 199 end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
| 136 outputter_->Trace(name(), start_time_, end_time_); | 200 outputter_->Trace(name(), start_time_, end_time_); |
| 137 } | 201 } |
| 138 | 202 |
| 203 void GPUTrace::DiscardTrace() { | |
| 204 discard_trace_ = true; | |
| 205 } | |
| 206 | |
| 139 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) | 207 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
| 140 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 208 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| 141 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), | 209 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
| 142 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 210 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| 143 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), | 211 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
| 144 decoder_(decoder), | 212 decoder_(decoder), |
| 145 timer_offset_(0), | 213 timer_offset_(0), |
| 146 last_tracer_source_(kTraceGroupInvalid), | 214 last_tracer_source_(kTraceGroupInvalid), |
| 147 enabled_(false), | 215 tracer_type_(kTracerTypeInvalid), |
| 148 gpu_timing_synced_(false), | 216 gpu_timing_synced_(false), |
| 149 gpu_executing_(false), | 217 gpu_executing_(false), |
| 150 process_posted_(false) { | 218 process_posted_(false) { |
| 151 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | 219 if (gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { |
| 220 tracer_type_ = kTracerTypeDisjointTimer; | |
| 221 outputter_ = TraceOutputter::Create("GL_EXT_disjoint_timer_query"); | |
| 222 } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | |
| 223 tracer_type_ = kTracerTypeARBTimer; | |
| 152 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); | 224 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
| 153 enabled_ = true; | |
| 154 } | 225 } |
| 155 } | 226 } |
| 156 | 227 |
| 157 GPUTracer::~GPUTracer() { | 228 GPUTracer::~GPUTracer() { |
| 158 } | 229 } |
| 159 | 230 |
| 160 bool GPUTracer::BeginDecoding() { | 231 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; | |
|
vmiura
2014/08/26 23:47:26
I think we still need this part, so that we sync t
David Yen
2014/08/27 19:47:45
Okay good point. I've moved this to the CalculateT
| |
| 171 } | |
| 172 } | |
| 173 | |
| 174 if (gpu_executing_) | 232 if (gpu_executing_) |
| 175 return false; | 233 return false; |
| 176 | 234 |
| 235 CalculateTimerOffset(); | |
| 177 gpu_executing_ = true; | 236 gpu_executing_ = true; |
| 178 | 237 |
| 179 if (IsTracing()) { | 238 if (IsTracing()) { |
| 239 // Reset disjoint bit for the disjoint timer. | |
| 240 if (tracer_type_ == kTracerTypeDisjointTimer) { | |
| 241 GLint disjoint_value = 0; | |
| 242 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
| 243 } | |
| 244 | |
| 180 // Begin a Trace for all active markers | 245 // Begin a Trace for all active markers |
| 181 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { | 246 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
| 182 for (size_t i = 0; i < markers_[n].size(); i++) { | 247 for (size_t i = 0; i < markers_[n].size(); i++) { |
| 183 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); | 248 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); |
| 184 markers_[n][i].trace_->Start(); | 249 markers_[n][i].trace_->Start(); |
| 185 } | 250 } |
| 186 } | 251 } |
| 187 } | 252 } |
| 188 return true; | 253 return true; |
| 189 } | 254 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 const std::string& GPUTracer::CurrentName() const { | 330 const std::string& GPUTracer::CurrentName() const { |
| 266 if (last_tracer_source_ >= 0 && | 331 if (last_tracer_source_ >= 0 && |
| 267 last_tracer_source_ < NUM_TRACER_SOURCES && | 332 last_tracer_source_ < NUM_TRACER_SOURCES && |
| 268 !markers_[last_tracer_source_].empty()) { | 333 !markers_[last_tracer_source_].empty()) { |
| 269 return markers_[last_tracer_source_].back().name_; | 334 return markers_[last_tracer_source_].back().name_; |
| 270 } | 335 } |
| 271 return base::EmptyString(); | 336 return base::EmptyString(); |
| 272 } | 337 } |
| 273 | 338 |
| 274 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& name) { | 339 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& name) { |
| 275 if (enabled_ && *gpu_trace_dev_category) | 340 GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : |
| 276 return new GPUTrace(outputter_, name, timer_offset_); | 341 kTracerTypeInvalid; |
| 277 else | 342 |
| 278 return new GPUTrace(name); | 343 return new GPUTrace(outputter_, name, timer_offset_, tracer_type); |
| 279 } | 344 } |
| 280 | 345 |
| 281 void GPUTracer::Process() { | 346 void GPUTracer::Process() { |
| 282 process_posted_ = false; | 347 process_posted_ = false; |
| 283 ProcessTraces(); | 348 ProcessTraces(); |
| 284 IssueProcessTask(); | 349 IssueProcessTask(); |
| 285 } | 350 } |
| 286 | 351 |
| 287 void GPUTracer::ProcessTraces() { | 352 void GPUTracer::ProcessTraces() { |
| 288 if (!enabled_) { | 353 if (tracer_type_ == kTracerTypeInvalid) { |
| 289 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 354 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
| 290 traces_.front()->Process(); | 355 traces_.front()->Process(); |
| 291 traces_.pop_front(); | 356 traces_.pop_front(); |
| 292 } | 357 } |
| 293 return; | 358 return; |
| 294 } | 359 } |
| 295 | 360 |
| 296 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); | 361 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); |
| 297 | 362 |
| 298 // Make owning decoder's GL context current | 363 // Make owning decoder's GL context current |
| 299 if (!decoder_->MakeCurrent()) { | 364 if (!decoder_->MakeCurrent()) { |
| 300 // Skip subsequent GL calls if MakeCurrent fails | 365 // Skip subsequent GL calls if MakeCurrent fails |
| 301 traces_.clear(); | 366 traces_.clear(); |
| 302 return; | 367 return; |
| 303 } | 368 } |
| 304 | 369 |
| 370 // Check if disjoint operation has occurred, discard ongoing traces if so. | |
| 371 if (tracer_type_ == kTracerTypeDisjointTimer) { | |
| 372 GLint disjoint_value = 0; | |
| 373 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
| 374 if (disjoint_value) { | |
| 375 while (!traces_.empty()) { | |
| 376 traces_.front()->DiscardTrace(); | |
| 377 traces_.front()->Process(); | |
| 378 traces_.pop_front(); | |
|
vmiura
2014/08/26 23:47:26
Can we completely remove DiscardTrace() & Process(
David Yen
2014/08/27 19:47:45
Yes you are right, I think I was thrown off by how
| |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 305 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 383 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
| 306 traces_.front()->Process(); | 384 traces_.front()->Process(); |
| 307 traces_.pop_front(); | 385 traces_.pop_front(); |
| 308 } | 386 } |
| 309 | 387 |
| 310 // Clear pending traces if there were are any errors | 388 // Clear pending traces if there were are any errors |
| 311 GLenum err = glGetError(); | 389 GLenum err = glGetError(); |
| 312 if (err != GL_NO_ERROR) | 390 if (err != GL_NO_ERROR) |
| 313 traces_.clear(); | 391 traces_.clear(); |
| 314 } | 392 } |
| 315 | 393 |
| 316 void GPUTracer::CalculateTimerOffset() { | 394 void GPUTracer::CalculateTimerOffset() { |
| 317 if (enabled_) { | 395 if (*gpu_trace_dev_category && tracer_type_ != kTracerTypeInvalid) { |
| 396 if (gpu_timing_synced_) | |
| 397 return; | |
| 398 | |
| 318 TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); | 399 TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); |
| 319 | 400 |
| 320 // NOTE(vmiura): It would be better to use glGetInteger64v, however | 401 // NOTE(vmiura): It would be better to use glGetInteger64v, however |
| 321 // it's not available everywhere. | 402 // it's not available everywhere. |
| 322 GLuint64 gl_now = 0; | 403 GLuint64 gl_now = 0; |
| 323 GLuint query; | 404 GLuint query; |
| 324 glFinish(); | 405 GLint disjoint_value = 0; |
| 325 glGenQueries(1, &query); | 406 |
| 326 glQueryCounter(query, GL_TIMESTAMP); | 407 switch (tracer_type_) { |
| 327 glFinish(); | 408 case kTracerTypeARBTimer: |
| 328 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | 409 glFinish(); |
| 410 glGenQueries(1, &query); | |
| 411 glQueryCounter(query, GL_TIMESTAMP); | |
| 412 glFinish(); | |
| 413 | |
| 414 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | |
| 415 glDeleteQueries(1, &query); | |
| 416 break; | |
| 417 | |
| 418 case kTracerTypeDisjointTimer: | |
| 419 // Clear the disjoint bit before we do any queries. | |
| 420 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
| 421 | |
| 422 glFinish(); | |
| 423 glGenQueriesEXT(1, &query); | |
| 424 glQueryCounterEXT(query, GL_TIMESTAMP_EXT); | |
| 425 glFinish(); | |
| 426 | |
| 427 glGetQueryObjectui64vEXT(query, GL_QUERY_RESULT_EXT, &gl_now); | |
| 428 glDeleteQueriesEXT(1, &query); | |
| 429 | |
| 430 // Discard results if disjoint operation has occurred. | |
| 431 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
| 432 if (disjoint_value) | |
| 433 return; | |
| 434 | |
| 435 break; | |
| 436 | |
| 437 default: | |
| 438 break; | |
| 439 } | |
| 440 | |
| 329 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | 441 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
| 330 | 442 |
| 331 gl_now /= base::Time::kNanosecondsPerMicrosecond; | 443 gl_now /= base::Time::kNanosecondsPerMicrosecond; |
| 332 timer_offset_ = system_now.ToInternalValue() - gl_now; | 444 timer_offset_ = system_now.ToInternalValue() - gl_now; |
| 333 glDeleteQueries(1, &query); | 445 gpu_timing_synced_ = true; |
| 334 } | 446 } |
| 335 } | 447 } |
| 336 | 448 |
| 337 void GPUTracer::IssueProcessTask() { | 449 void GPUTracer::IssueProcessTask() { |
| 338 if (traces_.empty() || process_posted_) | 450 if (traces_.empty() || process_posted_) |
| 339 return; | 451 return; |
| 340 | 452 |
| 341 process_posted_ = true; | 453 process_posted_ = true; |
| 342 base::MessageLoop::current()->PostDelayedTask( | 454 base::MessageLoop::current()->PostDelayedTask( |
| 343 FROM_HERE, | 455 FROM_HERE, |
| 344 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), | 456 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), |
| 345 base::TimeDelta::FromMilliseconds(kProcessInterval)); | 457 base::TimeDelta::FromMilliseconds(kProcessInterval)); |
| 346 } | 458 } |
| 347 | 459 |
| 348 } // namespace gles2 | 460 } // namespace gles2 |
| 349 } // namespace gpu | 461 } // namespace gpu |
| OLD | NEW |