X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fgpu%2Fcommand_buffer%2Fservice%2Fgpu_tracer.cc;h=024e4b6c5b247acc24457ea5e1a654ee729cf373;hb=3545e9f2671f595d2a2f3ee75ca0393b01e35ef6;hp=00f7e137a902323d56db6cf93224101da6197851;hpb=7d210d4c7e9ba36e635eabc5b5780495f8a63292;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/gpu/command_buffer/service/gpu_tracer.cc b/src/gpu/command_buffer/service/gpu_tracer.cc index 00f7e13..024e4b6 100644 --- a/src/gpu/command_buffer/service/gpu_tracer.cc +++ b/src/gpu/command_buffer/service/gpu_tracer.cc @@ -18,6 +18,14 @@ namespace gles2 { static const unsigned int kProcessInterval = 16; static TraceOutputter* g_outputter_thread = NULL; +TraceMarker::TraceMarker(const std::string& name) + : name_(name), + trace_(NULL) { +} + +TraceMarker::~TraceMarker() { +} + scoped_refptr TraceOutputter::Create(const std::string& name) { if (!g_outputter_thread) { g_outputter_thread = new TraceOutputter(name); @@ -51,45 +59,81 @@ void TraceOutputter::Trace(const std::string& name, ++local_trace_id_; } -GPUTrace::GPUTrace(const std::string& name) - : name_(name), - outputter_(NULL), - offset_(0), - end_time_(0), - end_requested_(false), - enabled_(false) { -} - GPUTrace::GPUTrace(scoped_refptr outputter, const std::string& name, - int64 offset) + int64 offset, + GpuTracerType tracer_type) : name_(name), outputter_(outputter), offset_(offset), start_time_(0), end_time_(0), - end_requested_(false), - enabled_(true) { - glGenQueries(2, queries_); + tracer_type_(tracer_type), + end_requested_(false) { + memset(queries_, 0, sizeof(queries_)); + switch (tracer_type_) { + case kTracerTypeARBTimer: + case kTracerTypeDisjointTimer: + glGenQueriesARB(2, queries_); + break; + + default: + tracer_type_ = kTracerTypeInvalid; + } } GPUTrace::~GPUTrace() { - if (enabled_) - glDeleteQueries(2, queries_); + switch (tracer_type_) { + case kTracerTypeInvalid: + break; + + case kTracerTypeARBTimer: + case kTracerTypeDisjointTimer: + glDeleteQueriesARB(2, queries_); + break; + } } void GPUTrace::Start() { TRACE_EVENT_COPY_ASYNC_BEGIN0( TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); - if (enabled_) { - glQueryCounter(queries_[0], GL_TIMESTAMP); + + switch (tracer_type_) { + case kTracerTypeInvalid: + break; + + case kTracerTypeDisjointTimer: + // For the disjoint timer, GPU idle time does not seem to increment the + // internal counter. We must calculate the offset before any query. The + // good news is any device that supports disjoint timer will also support + // glGetInteger64v, so we can query it directly unlike the ARBTimer case. + // The "offset_" variable will always be 0 during normal use cases, only + // under the unit tests will it be set to specific test values. + if (offset_ == 0) { + GLint64 gl_now = 0; + glGetInteger64v(GL_TIMESTAMP, &gl_now); + offset_ = base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() - + gl_now / base::Time::kNanosecondsPerMicrosecond; + } + // Intentionally fall through to kTracerTypeARBTimer case.xs + case kTracerTypeARBTimer: + // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. + glQueryCounter(queries_[0], GL_TIMESTAMP); + break; } } void GPUTrace::End() { - if (enabled_) { - glQueryCounter(queries_[1], GL_TIMESTAMP); - end_requested_ = true; + end_requested_ = true; + switch (tracer_type_) { + case kTracerTypeInvalid: + break; + + case kTracerTypeARBTimer: + case kTracerTypeDisjointTimer: + // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. + glQueryCounter(queries_[1], GL_TIMESTAMP); + break; } TRACE_EVENT_COPY_ASYNC_END0( @@ -97,271 +141,191 @@ void GPUTrace::End() { } bool GPUTrace::IsAvailable() { - if (!enabled_) - return true; - else if (!end_requested_) - return false; + if (tracer_type_ != kTracerTypeInvalid) { + if (!end_requested_) + return false; + + GLint done = 0; + glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); + return !!done; + } - GLint done = 0; - glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); - return !!done; + return true; } void GPUTrace::Process() { - if (!enabled_) + if (tracer_type_ == kTracerTypeInvalid) return; DCHECK(IsAvailable()); - GLuint64 timestamp; + GLuint64 begin_stamp = 0; + GLuint64 end_stamp = 0; // 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_; + glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); + glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); - glDeleteQueries(2, queries_); + start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + + offset_; + end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; outputter_->Trace(name(), start_time_, end_time_); } -struct TraceMarker { - TraceMarker(const std::string& name, GpuTracerSource source) - : name_(name), source_(source) {} - - std::string name_; - GpuTracerSource source_; - scoped_refptr trace_; -}; - -class GPUTracerImpl - : public GPUTracer, - public base::SupportsWeakPtr { - 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), + tracer_type_(kTracerTypeInvalid), + gpu_timing_synced_(false), + gpu_executing_(false), + process_posted_(false) { + if (gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { + tracer_type_ = kTracerTypeDisjointTimer; + outputter_ = TraceOutputter::Create("GL_EXT_disjoint_timer_query"); + } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { + tracer_type_ = kTracerTypeARBTimer; + outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); } - virtual void CalculateTimerOffset() {} - - // Process any completed traces. - virtual void Process(); - virtual void ProcessTraces(); - - protected: - // Create a new trace. - virtual scoped_refptr CreateTrace(const std::string& name); - - const unsigned char* gpu_trace_srv_category; - const unsigned char* gpu_trace_dev_category; - - protected: - void IssueProcessTask(); - - std::vector markers_; - std::deque > 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 CreateTrace(const std::string& name) OVERRIDE; - virtual void CalculateTimerOffset() OVERRIDE; - - scoped_refptr outputter_; - - bool gpu_timing_synced_; - int64 timer_offset_; - - gles2::GLES2Decoder* decoder_; +} - DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); -}; +GPUTracer::~GPUTracer() { +} -bool GPUTracerImpl::BeginDecoding() { +bool GPUTracer::BeginDecoding() { if (gpu_executing_) return false; + CalculateTimerOffset(); gpu_executing_ = true; if (IsTracing()) { + // Reset disjoint bit for the disjoint timer. + if (tracer_type_ == kTracerTypeDisjointTimer) { + GLint disjoint_value = 0; + glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); + } + // 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_->IsEnabled()) - 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_.get()) { + markers_[n][i].trace_->End(); + if (markers_[n][i].trace_->IsEnabled()) + 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, + // 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; + DCHECK(source >= 0 && source < NUM_TRACER_SOURCES); + // 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 = 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; + DCHECK(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 = markers_[i].trace_; - if (trace) { - trace->End(); - if (trace->IsEnabled()) - traces_.push_back(trace); - IssueProcessTask(); - } + if (!markers_[source].empty()) { + if (IsTracing()) { + scoped_refptr trace = markers_[source].back().trace_; + if (trace.get()) { + trace->End(); + if (trace->IsEnabled()) + 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_; -} +scoped_refptr GPUTracer::CreateTrace(const std::string& name) { + GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : + kTracerTypeInvalid; -scoped_refptr GPUTracerImpl::CreateTrace( - const std::string& name) { - return new GPUTrace(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)); + return new GPUTrace(outputter_, name, timer_offset_, tracer_type); } -GPUTracerARBTimerQuery::GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder) - : timer_offset_(0), decoder_(decoder) { - outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); -} - -GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { -} - -scoped_refptr GPUTracerARBTimerQuery::CreateTrace( - const std::string& name) { - if (*gpu_trace_dev_category) - return new GPUTrace(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; - } - } else { - // If GPU device category is off, invalidate timing sync - gpu_timing_synced_ = false; +void GPUTracer::ProcessTraces() { + if (tracer_type_ == kTracerTypeInvalid) { + traces_.clear(); + 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()) { @@ -370,6 +334,14 @@ void GPUTracerARBTimerQuery::ProcessTraces() { return; } + // Check if disjoint operation has occurred, discard ongoing traces if so. + if (tracer_type_ == kTracerTypeDisjointTimer) { + GLint disjoint_value = 0; + glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); + if (disjoint_value) + traces_.clear(); + } + while (!traces_.empty() && traces_.front()->IsAvailable()) { traces_.front()->Process(); traces_.pop_front(); @@ -381,34 +353,54 @@ 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::CalculateTimerOffset() { + if (tracer_type_ != kTracerTypeInvalid) { + if (*gpu_trace_dev_category == '\0') { + // If GPU device category is off, invalidate timing sync. + gpu_timing_synced_ = false; + return; + } else if (tracer_type_ == kTracerTypeDisjointTimer) { + // Disjoint timers offsets should be calculated before every query. + gpu_timing_synced_ = true; + timer_offset_ = 0; + } + + if (gpu_timing_synced_) + return; + + TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); -GPUTracer::GPUTracer() {} + // NOTE(vmiura): It would be better to use glGetInteger64v, however + // it's not available everywhere. + GLuint64 gl_now = 0; + GLuint query; -GPUTracer::~GPUTracer() {} + glGenQueriesARB(1, &query); -scoped_ptr GPUTracer::Create(gles2::GLES2Decoder* decoder) { - if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { - return scoped_ptr(new GPUTracerARBTimerQuery(decoder)); + glFinish(); + glQueryCounter(query, GL_TIMESTAMP); + glFinish(); + + glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); + glDeleteQueriesARB(1, &query); + + base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); + + gl_now /= base::Time::kNanosecondsPerMicrosecond; + timer_offset_ = system_now.ToInternalValue() - gl_now; + gpu_timing_synced_ = true; } - return scoped_ptr(new GPUTracerImpl()); +} + +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)); } } // namespace gles2