Chromium Code Reviews| Index: gpu/command_buffer/service/gpu_tracer.cc |
| diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc |
| index 2cd38e79ca470b6a5c595541c5c3a5c8f640d320..7bbd83e416782b0bcd23c503ccd1fcbc73fb3ace 100644 |
| --- a/gpu/command_buffer/service/gpu_tracer.cc |
| +++ b/gpu/command_buffer/service/gpu_tracer.cc |
| @@ -74,146 +74,41 @@ class NoopTrace : public Trace { |
| DISALLOW_COPY_AND_ASSIGN(NoopTrace); |
| }; |
| -struct TraceMarker { |
| - TraceMarker(const std::string& name, GpuTracerSource source) |
| - : name_(name), source_(source) {} |
| - |
| - std::string name_; |
| - GpuTracerSource source_; |
| - scoped_refptr<Trace> trace_; |
| -}; |
| - |
| -class GPUTracerImpl |
| - : public GPUTracer, |
| - public base::SupportsWeakPtr<GPUTracerImpl> { |
| - public: |
| - GPUTracerImpl() |
| - : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| - TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
| - gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| - TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
| - gpu_executing_(false), |
| - process_posted_(false) {} |
| - virtual ~GPUTracerImpl() {} |
| - |
| - // Implementation of gpu::gles2::GPUTracer |
| - virtual bool BeginDecoding() OVERRIDE; |
| - virtual bool EndDecoding() OVERRIDE; |
| - virtual bool Begin(const std::string& name, GpuTracerSource source) OVERRIDE; |
| - virtual bool End(GpuTracerSource source) OVERRIDE; |
| - virtual const std::string& CurrentName() const OVERRIDE; |
| - virtual bool IsTracing() OVERRIDE { |
| - return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); |
| +GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
| + : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| + TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
| + gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| + TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
| + decoder_(decoder), |
| + timer_offset_(0), |
| + last_tracer_source_(kTraceGroupInvalid), |
| + enabled_(false), |
| + gpu_timing_synced_(false), |
| + gpu_executing_(false), |
| + process_posted_(false) { |
| + if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
| + outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
| + enabled_ = true; |
| } |
| - virtual void CalculateTimerOffset() {} |
| - |
| - // Process any completed traces. |
| - virtual void Process(); |
| - virtual void ProcessTraces(); |
| - |
| - protected: |
| - // Create a new trace. |
| - virtual scoped_refptr<Trace> CreateTrace(const std::string& name); |
| - |
| - const unsigned char* gpu_trace_srv_category; |
| - const unsigned char* gpu_trace_dev_category; |
| - |
| - protected: |
| - void IssueProcessTask(); |
| - |
| - std::vector<TraceMarker> markers_; |
| - std::deque<scoped_refptr<Trace> > traces_; |
| - |
| - bool gpu_executing_; |
| - bool process_posted_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl); |
| -}; |
| - |
| -class GPUTracerARBTimerQuery : public GPUTracerImpl { |
| - public: |
| - explicit GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder); |
| - virtual ~GPUTracerARBTimerQuery(); |
| - |
| - // Implementation of GPUTracerImpl |
| - virtual void ProcessTraces() OVERRIDE; |
| - |
| - protected: |
| - // Implementation of GPUTracerImpl. |
| - virtual bool BeginDecoding() OVERRIDE; |
| - virtual bool EndDecoding() OVERRIDE; |
| - virtual scoped_refptr<Trace> CreateTrace(const std::string& name) OVERRIDE; |
| - virtual void CalculateTimerOffset() OVERRIDE; |
| - |
| - scoped_refptr<Outputter> outputter_; |
| - |
| - bool gpu_timing_synced_; |
| - int64 timer_offset_; |
| - |
| - gles2::GLES2Decoder* decoder_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); |
| -}; |
| - |
| -bool Trace::IsProcessable() { return true; } |
| - |
| -const std::string& Trace::name() { return name_; } |
| - |
| -GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter, |
| - const std::string& name, |
| - int64 offset) |
| - : Trace(name), |
| - outputter_(outputter), |
| - offset_(offset), |
| - start_time_(0), |
| - end_time_(0), |
| - end_requested_(false) { |
| - glGenQueries(2, queries_); |
| } |
| -GLARBTimerTrace::~GLARBTimerTrace() { glDeleteQueries(2, queries_); } |
| - |
| -void GLARBTimerTrace::Start() { |
| - TRACE_EVENT_COPY_ASYNC_BEGIN0( |
| - TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
| - glQueryCounter(queries_[0], GL_TIMESTAMP); |
| +GPUTracer::~GPUTracer() { |
| } |
| -void GLARBTimerTrace::End() { |
| - glQueryCounter(queries_[1], GL_TIMESTAMP); |
| - end_requested_ = true; |
| - TRACE_EVENT_COPY_ASYNC_END0( |
| - TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
| -} |
| - |
| -bool GLARBTimerTrace::IsAvailable() { |
| - if (!end_requested_) |
| - return false; |
| - |
| - GLint done = 0; |
| - glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
| - return !!done; |
| -} |
| - |
| -void GLARBTimerTrace::Process() { |
| - DCHECK(IsAvailable()); |
| - |
| - GLuint64 timestamp; |
| - |
| - // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
| - // We need to detect if the end is less then the start and correct for the |
| - // wrapping. |
| - glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); |
| - start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| - |
| - glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); |
| - end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| - |
| - glDeleteQueries(2, queries_); |
| - outputter_->Trace(name(), start_time_, end_time_); |
| -} |
| +bool GPUTracer::BeginDecoding() { |
| + if (enabled_) { |
| + if (*gpu_trace_dev_category) { |
| + // Make sure timing is synced before tracing |
| + if (!gpu_timing_synced_) { |
| + CalculateTimerOffset(); |
| + gpu_timing_synced_ = true; |
| + } |
| + } else { |
| + // If GPU device category is off, invalidate timing sync |
| + gpu_timing_synced_ = false; |
| + } |
| + } |
| -bool GPUTracerImpl::BeginDecoding() { |
| if (gpu_executing_) |
| return false; |
| @@ -221,150 +116,144 @@ bool GPUTracerImpl::BeginDecoding() { |
| if (IsTracing()) { |
| // Begin a Trace for all active markers |
| - for (size_t i = 0; i < markers_.size(); i++) { |
| - markers_[i].trace_ = CreateTrace(markers_[i].name_); |
| - markers_[i].trace_->Start(); |
| + for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
| + for (size_t i = 0; i < markers_[n].size(); i++) { |
| + markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); |
| + markers_[n][i].trace_->Start(); |
| + } |
| } |
| } |
| return true; |
| } |
| -bool GPUTracerImpl::EndDecoding() { |
| +bool GPUTracer::EndDecoding() { |
| if (!gpu_executing_) |
| return false; |
| // End Trace for all active markers |
| if (IsTracing()) { |
| - for (size_t i = 0; i < markers_.size(); i++) { |
| - if (markers_[i].trace_) { |
| - markers_[i].trace_->End(); |
| - if (markers_[i].trace_->IsProcessable()) |
| - traces_.push_back(markers_[i].trace_); |
| - markers_[i].trace_ = 0; |
| + for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
| + for (size_t i = 0; i < markers_[n].size(); i++) { |
| + if (markers_[n][i].trace_) { |
| + markers_[n][i].trace_->End(); |
| + if (markers_[n][i].trace_->IsProcessable()) |
| + traces_.push_back(markers_[n][i].trace_); |
| + markers_[n][i].trace_ = 0; |
| + } |
| } |
| } |
| IssueProcessTask(); |
| } |
| gpu_executing_ = false; |
| + |
| + // NOTE(vmiura_: glFlush() here can help give better trace results, |
|
vmiura
2014/07/29 23:45:30
nit: NOTE(vmiura)
David Yen
2014/08/04 22:20:05
Done.
|
| + // but it distorts the normal device behavior. |
| return true; |
| } |
| -bool GPUTracerImpl::Begin(const std::string& name, GpuTracerSource source) { |
| +bool GPUTracer::Begin(const std::string& name, GpuTracerSource source) { |
| if (!gpu_executing_) |
| return false; |
| + assert(source >= 0 && source < NUM_TRACER_SOURCES); |
|
vmiura
2014/07/29 23:45:30
Please use DCHECK instead of assert here and below
David Yen
2014/08/04 22:20:05
Done.
|
| + |
| // Push new marker from given 'source' |
| - markers_.push_back(TraceMarker(name, source)); |
| + last_tracer_source_ = source; |
| + markers_[source].push_back(TraceMarker(name)); |
| // Create trace |
| if (IsTracing()) { |
| scoped_refptr<Trace> trace = CreateTrace(name); |
| trace->Start(); |
| - markers_.back().trace_ = trace; |
| + markers_[source].back().trace_ = trace; |
| } |
| + |
| return true; |
| } |
| -bool GPUTracerImpl::End(GpuTracerSource source) { |
| +bool GPUTracer::End(GpuTracerSource source) { |
| if (!gpu_executing_) |
| return false; |
| + assert(source >= 0 && source < NUM_TRACER_SOURCES); |
| + |
| // Pop last marker with matching 'source' |
| - for (int i = markers_.size() - 1; i >= 0; i--) { |
| - if (markers_[i].source_ == source) { |
| - // End trace |
| - if (IsTracing()) { |
| - scoped_refptr<Trace> trace = markers_[i].trace_; |
| - if (trace) { |
| - trace->End(); |
| - if (trace->IsProcessable()) |
| - traces_.push_back(trace); |
| - IssueProcessTask(); |
| - } |
| + if (!markers_[source].empty()) { |
| + if (IsTracing()) { |
| + scoped_refptr<Trace> trace = markers_[source].back().trace_; |
| + if (trace) { |
| + trace->End(); |
| + if (trace->IsProcessable()) |
| + traces_.push_back(trace); |
| + IssueProcessTask(); |
| } |
| - |
| - markers_.erase(markers_.begin() + i); |
| - return true; |
| } |
| + |
| + markers_[source].pop_back(); |
| + return true; |
| } |
| return false; |
| } |
| -void GPUTracerImpl::Process() { |
| - process_posted_ = false; |
| - ProcessTraces(); |
| - IssueProcessTask(); |
| +bool GPUTracer::IsTracing() { |
| + return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); |
| } |
| -void GPUTracerImpl::ProcessTraces() { |
| - while (!traces_.empty() && traces_.front()->IsAvailable()) { |
| - traces_.front()->Process(); |
| - traces_.pop_front(); |
| +const std::string& GPUTracer::CurrentName() const { |
| + if (last_tracer_source_ >= 0 && |
| + last_tracer_source_ < NUM_TRACER_SOURCES && |
| + !markers_[last_tracer_source_].empty()) { |
| + return markers_[last_tracer_source_].back().name_; |
| } |
| + return base::EmptyString(); |
| } |
| -const std::string& GPUTracerImpl::CurrentName() const { |
| - if (markers_.empty()) |
| - return base::EmptyString(); |
| - return markers_.back().name_; |
| +void GPUTracer::CalculateTimerOffset() { |
| + if (enabled_) { |
| + TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); |
| + |
| + // NOTE(vmiura): It would be better to use glGetInteger64v, however |
| + // it's not available everywhere. |
| + GLuint64 gl_now = 0; |
| + GLuint query; |
| + glFinish(); |
| + glGenQueries(1, &query); |
| + glQueryCounter(query, GL_TIMESTAMP); |
| + glFinish(); |
| + glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
| + base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
| + |
| + gl_now /= base::Time::kNanosecondsPerMicrosecond; |
| + timer_offset_ = system_now.ToInternalValue() - gl_now; |
| + glDeleteQueries(1, &query); |
| + } |
| } |
| -scoped_refptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) { |
| +scoped_refptr<Trace> GPUTracer::CreateTrace(const std::string& name) { |
| + if (enabled_) { |
| + if (*gpu_trace_dev_category) |
| + return new GLARBTimerTrace(outputter_, name, timer_offset_); |
| + } |
| return new NoopTrace(name); |
| } |
| -void GPUTracerImpl::IssueProcessTask() { |
| - if (traces_.empty() || process_posted_) |
| - return; |
| - |
| - process_posted_ = true; |
| - base::MessageLoop::current()->PostDelayedTask( |
| - FROM_HERE, |
| - base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)), |
| - base::TimeDelta::FromMilliseconds(kProcessInterval)); |
| -} |
| - |
| -GPUTracerARBTimerQuery::GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder) |
| - : timer_offset_(0), decoder_(decoder) { |
| - outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
| -} |
| - |
| -GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { |
| -} |
| - |
| -scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace( |
| - const std::string& name) { |
| - if (*gpu_trace_dev_category) |
| - return new GLARBTimerTrace(outputter_, name, timer_offset_); |
| - return GPUTracerImpl::CreateTrace(name); |
| +void GPUTracer::Process() { |
| + process_posted_ = false; |
| + ProcessTraces(); |
| + IssueProcessTask(); |
| } |
| -bool GPUTracerARBTimerQuery::BeginDecoding() { |
| - if (*gpu_trace_dev_category) { |
| - // Make sure timing is synced before tracing |
| - if (!gpu_timing_synced_) { |
| - CalculateTimerOffset(); |
| - gpu_timing_synced_ = true; |
| +void GPUTracer::ProcessTraces() { |
| + if (!enabled_) { |
| + while (!traces_.empty() && traces_.front()->IsAvailable()) { |
| + traces_.front()->Process(); |
| + traces_.pop_front(); |
| } |
| - } else { |
| - // If GPU device category is off, invalidate timing sync |
| - gpu_timing_synced_ = false; |
| + return; |
| } |
| - return GPUTracerImpl::BeginDecoding(); |
| -} |
| - |
| -bool GPUTracerARBTimerQuery::EndDecoding() { |
| - bool ret = GPUTracerImpl::EndDecoding(); |
| - |
| - // NOTE(vmiura_: glFlush() here can help give better trace results, |
| - // but it distorts the normal device behavior. |
| - return ret; |
| -} |
| - |
| -void GPUTracerARBTimerQuery::ProcessTraces() { |
| - TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::ProcessTraces"); |
| + TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); |
| // Make owning decoder's GL context current |
| if (!decoder_->MakeCurrent()) { |
| @@ -384,34 +273,73 @@ void GPUTracerARBTimerQuery::ProcessTraces() { |
| traces_.clear(); |
| } |
| -void GPUTracerARBTimerQuery::CalculateTimerOffset() { |
| - TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::CalculateTimerOffset"); |
| - |
| - // NOTE(vmiura): It would be better to use glGetInteger64v, however |
| - // it's not available everywhere. |
| - GLuint64 gl_now = 0; |
| - GLuint query; |
| - glFinish(); |
| - glGenQueries(1, &query); |
| - glQueryCounter(query, GL_TIMESTAMP); |
| - glFinish(); |
| - glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
| - base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
| - |
| - gl_now /= base::Time::kNanosecondsPerMicrosecond; |
| - timer_offset_ = system_now.ToInternalValue() - gl_now; |
| - glDeleteQueries(1, &query); |
| +void GPUTracer::IssueProcessTask() { |
| + if (traces_.empty() || process_posted_) |
| + return; |
| + |
| + process_posted_ = true; |
| + base::MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), |
| + base::TimeDelta::FromMilliseconds(kProcessInterval)); |
| } |
| -GPUTracer::GPUTracer() {} |
| +bool Trace::IsProcessable() { return true; } |
| -GPUTracer::~GPUTracer() {} |
| +const std::string& Trace::name() { return name_; } |
| -scoped_ptr<GPUTracer> GPUTracer::Create(gles2::GLES2Decoder* decoder) { |
| - if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
| - return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery(decoder)); |
| - } |
| - return scoped_ptr<GPUTracer>(new GPUTracerImpl()); |
| +GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter, |
| + const std::string& name, |
| + int64 offset) |
| + : Trace(name), |
| + outputter_(outputter), |
| + offset_(offset), |
| + start_time_(0), |
| + end_time_(0), |
| + end_requested_(false) { |
| + glGenQueries(2, queries_); |
| +} |
| + |
| +GLARBTimerTrace::~GLARBTimerTrace() { glDeleteQueries(2, queries_); } |
| + |
| +void GLARBTimerTrace::Start() { |
| + TRACE_EVENT_COPY_ASYNC_BEGIN0( |
| + TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
| + glQueryCounter(queries_[0], GL_TIMESTAMP); |
| +} |
| + |
| +void GLARBTimerTrace::End() { |
| + glQueryCounter(queries_[1], GL_TIMESTAMP); |
| + end_requested_ = true; |
| + TRACE_EVENT_COPY_ASYNC_END0( |
| + TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
| +} |
| + |
| +bool GLARBTimerTrace::IsAvailable() { |
| + if (!end_requested_) |
| + return false; |
| + |
| + GLint done = 0; |
| + glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
| + return !!done; |
| +} |
| + |
| +void GLARBTimerTrace::Process() { |
| + DCHECK(IsAvailable()); |
| + |
| + GLuint64 timestamp; |
| + |
| + // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
| + // We need to detect if the end is less then the start and correct for the |
| + // wrapping. |
| + glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); |
| + start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| + |
| + glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); |
| + end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| + |
| + glDeleteQueries(2, queries_); |
| + outputter_->Trace(name(), start_time_, end_time_); |
| } |
| } // namespace gles2 |