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
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/service/gpu_tracer.h"
10 #include "base/debug/trace_event.h"
11 #include "base/strings/string_util.h"
12 #include "base/time/time.h"
13 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
18 static const unsigned int kProcessInterval = 16;
19 static TraceOutputter* g_outputter_thread = NULL;
21 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) {
22 if (!g_outputter_thread) {
23 g_outputter_thread = new TraceOutputter(name);
25 return g_outputter_thread;
28 TraceOutputter::TraceOutputter(const std::string& name)
29 : named_thread_(name.c_str()), local_trace_id_(0) {
30 named_thread_.Start();
34 TraceOutputter::~TraceOutputter() { g_outputter_thread = NULL; }
36 void TraceOutputter::Trace(const std::string& name,
39 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
40 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
43 named_thread_.thread_id(),
45 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0(
46 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
49 named_thread_.thread_id(),
54 GPUTrace::GPUTrace(const std::string& name)
59 end_requested_(false),
63 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter,
64 const std::string& name,
67 outputter_(outputter),
71 end_requested_(false),
73 glGenQueries(2, queries_);
76 GPUTrace::~GPUTrace() {
78 glDeleteQueries(2, queries_);
81 void GPUTrace::Start() {
82 TRACE_EVENT_COPY_ASYNC_BEGIN0(
83 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this);
85 glQueryCounter(queries_[0], GL_TIMESTAMP);
89 void GPUTrace::End() {
91 glQueryCounter(queries_[1], GL_TIMESTAMP);
92 end_requested_ = true;
95 TRACE_EVENT_COPY_ASYNC_END0(
96 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this);
99 bool GPUTrace::IsAvailable() {
102 else if (!end_requested_)
106 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
110 void GPUTrace::Process() {
114 DCHECK(IsAvailable());
118 // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
119 // We need to detect if the end is less then the start and correct for the
121 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp);
122 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
124 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp);
125 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
127 glDeleteQueries(2, queries_);
128 outputter_->Trace(name(), start_time_, end_time_);
132 TraceMarker(const std::string& name, GpuTracerSource source)
133 : name_(name), source_(source) {}
136 GpuTracerSource source_;
137 scoped_refptr<GPUTrace> trace_;
142 public base::SupportsWeakPtr<GPUTracerImpl> {
145 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
146 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
147 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
148 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
149 gpu_executing_(false),
150 process_posted_(false) {}
151 virtual ~GPUTracerImpl() {}
153 // Implementation of gpu::gles2::GPUTracer
154 virtual bool BeginDecoding() OVERRIDE;
155 virtual bool EndDecoding() OVERRIDE;
156 virtual bool Begin(const std::string& name, GpuTracerSource source) OVERRIDE;
157 virtual bool End(GpuTracerSource source) OVERRIDE;
158 virtual const std::string& CurrentName() const OVERRIDE;
159 virtual bool IsTracing() OVERRIDE {
160 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0);
162 virtual void CalculateTimerOffset() {}
164 // Process any completed traces.
165 virtual void Process();
166 virtual void ProcessTraces();
169 // Create a new trace.
170 virtual scoped_refptr<GPUTrace> CreateTrace(const std::string& name);
172 const unsigned char* gpu_trace_srv_category;
173 const unsigned char* gpu_trace_dev_category;
176 void IssueProcessTask();
178 std::vector<TraceMarker> markers_;
179 std::deque<scoped_refptr<GPUTrace> > traces_;
182 bool process_posted_;
184 DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl);
187 class GPUTracerARBTimerQuery : public GPUTracerImpl {
189 explicit GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder);
190 virtual ~GPUTracerARBTimerQuery();
192 // Implementation of GPUTracerImpl
193 virtual void ProcessTraces() OVERRIDE;
196 // Implementation of GPUTracerImpl.
197 virtual bool BeginDecoding() OVERRIDE;
198 virtual bool EndDecoding() OVERRIDE;
199 virtual scoped_refptr<GPUTrace> CreateTrace(const std::string& name) OVERRIDE;
200 virtual void CalculateTimerOffset() OVERRIDE;
202 scoped_refptr<Outputter> outputter_;
204 bool gpu_timing_synced_;
207 gles2::GLES2Decoder* decoder_;
209 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery);
212 bool GPUTracerImpl::BeginDecoding() {
216 gpu_executing_ = true;
219 // Begin a Trace for all active markers
220 for (size_t i = 0; i < markers_.size(); i++) {
221 markers_[i].trace_ = CreateTrace(markers_[i].name_);
222 markers_[i].trace_->Start();
228 bool GPUTracerImpl::EndDecoding() {
232 // End Trace for all active markers
234 for (size_t i = 0; i < markers_.size(); i++) {
235 if (markers_[i].trace_) {
236 markers_[i].trace_->End();
237 if (markers_[i].trace_->IsEnabled())
238 traces_.push_back(markers_[i].trace_);
239 markers_[i].trace_ = 0;
245 gpu_executing_ = false;
249 bool GPUTracerImpl::Begin(const std::string& name, GpuTracerSource source) {
253 // Push new marker from given 'source'
254 markers_.push_back(TraceMarker(name, source));
258 scoped_refptr<GPUTrace> trace = CreateTrace(name);
260 markers_.back().trace_ = trace;
265 bool GPUTracerImpl::End(GpuTracerSource source) {
269 // Pop last marker with matching 'source'
270 for (int i = markers_.size() - 1; i >= 0; i--) {
271 if (markers_[i].source_ == source) {
274 scoped_refptr<GPUTrace> trace = markers_[i].trace_;
277 if (trace->IsEnabled())
278 traces_.push_back(trace);
283 markers_.erase(markers_.begin() + i);
290 void GPUTracerImpl::Process() {
291 process_posted_ = false;
296 void GPUTracerImpl::ProcessTraces() {
297 while (!traces_.empty() && traces_.front()->IsAvailable()) {
298 traces_.front()->Process();
303 const std::string& GPUTracerImpl::CurrentName() const {
304 if (markers_.empty())
305 return base::EmptyString();
306 return markers_.back().name_;
309 scoped_refptr<GPUTrace> GPUTracerImpl::CreateTrace(
310 const std::string& name) {
311 return new GPUTrace(name);
314 void GPUTracerImpl::IssueProcessTask() {
315 if (traces_.empty() || process_posted_)
318 process_posted_ = true;
319 base::MessageLoop::current()->PostDelayedTask(
321 base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)),
322 base::TimeDelta::FromMilliseconds(kProcessInterval));
325 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder)
326 : timer_offset_(0), decoder_(decoder) {
327 outputter_ = TraceOutputter::Create("GL_ARB_timer_query");
330 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() {
333 scoped_refptr<GPUTrace> GPUTracerARBTimerQuery::CreateTrace(
334 const std::string& name) {
335 if (*gpu_trace_dev_category)
336 return new GPUTrace(outputter_, name, timer_offset_);
337 return GPUTracerImpl::CreateTrace(name);
340 bool GPUTracerARBTimerQuery::BeginDecoding() {
341 if (*gpu_trace_dev_category) {
342 // Make sure timing is synced before tracing
343 if (!gpu_timing_synced_) {
344 CalculateTimerOffset();
345 gpu_timing_synced_ = true;
348 // If GPU device category is off, invalidate timing sync
349 gpu_timing_synced_ = false;
352 return GPUTracerImpl::BeginDecoding();
355 bool GPUTracerARBTimerQuery::EndDecoding() {
356 bool ret = GPUTracerImpl::EndDecoding();
358 // NOTE(vmiura_: glFlush() here can help give better trace results,
359 // but it distorts the normal device behavior.
363 void GPUTracerARBTimerQuery::ProcessTraces() {
364 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::ProcessTraces");
366 // Make owning decoder's GL context current
367 if (!decoder_->MakeCurrent()) {
368 // Skip subsequent GL calls if MakeCurrent fails
373 while (!traces_.empty() && traces_.front()->IsAvailable()) {
374 traces_.front()->Process();
378 // Clear pending traces if there were are any errors
379 GLenum err = glGetError();
380 if (err != GL_NO_ERROR)
384 void GPUTracerARBTimerQuery::CalculateTimerOffset() {
385 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::CalculateTimerOffset");
387 // NOTE(vmiura): It would be better to use glGetInteger64v, however
388 // it's not available everywhere.
392 glGenQueries(1, &query);
393 glQueryCounter(query, GL_TIMESTAMP);
395 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now);
396 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime();
398 gl_now /= base::Time::kNanosecondsPerMicrosecond;
399 timer_offset_ = system_now.ToInternalValue() - gl_now;
400 glDeleteQueries(1, &query);
403 GPUTracer::GPUTracer() {}
405 GPUTracer::~GPUTracer() {}
407 scoped_ptr<GPUTracer> GPUTracer::Create(gles2::GLES2Decoder* decoder) {
408 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) {
409 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery(decoder));
411 return scoped_ptr<GPUTracer>(new GPUTracerImpl());