• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "gpu/command_buffer/service/gpu_tracer.h"
6 
7 #include <deque>
8 
9 #include "base/bind.h"
10 #include "base/debug/trace_event.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/strings/string_util.h"
13 #include "base/threading/thread.h"
14 #include "base/time/time.h"
15 #include "ui/gl/gl_bindings.h"
16 
17 namespace gpu {
18 namespace gles2 {
19 namespace {
20 
21 class Outputter;
22 
23 static const unsigned int kProcessInterval = 16;
24 static Outputter* g_outputter_thread = NULL;
25 
26 class Outputter
27     : private base::Thread,
28       public base::RefCounted<Outputter> {
29  public:
Create(const std::string & name)30   static scoped_refptr<Outputter> Create(const std::string& name) {
31     if (!g_outputter_thread) {
32       g_outputter_thread = new Outputter(name);
33       g_outputter_thread->Start();
34       g_outputter_thread->Stop();
35     }
36     return g_outputter_thread;
37   }
38 
Id()39   uint64 Id() { return thread_id(); }
40 
41  private:
42   friend class base::RefCounted<Outputter>;
43 
Outputter(const std::string & name)44   explicit Outputter(const std::string& name) : base::Thread(name.c_str()) {}
45 
~Outputter()46   virtual ~Outputter() {
47     g_outputter_thread = NULL;
48   }
49 
50   DISALLOW_COPY_AND_ASSIGN(Outputter);
51 };
52 
53 class Trace : public base::RefCounted<Trace> {
54  public:
Trace(const std::string & name)55   explicit Trace(const std::string& name) : name_(name) {}
56 
57   virtual void Start() = 0;
58   virtual void End() = 0;
59 
60   // True if the the results of this query are available.
61   virtual bool IsAvailable() = 0;
62 
IsProcessable()63   virtual bool IsProcessable() { return true; }
64   virtual void Process() = 0;
65 
name()66   virtual const std::string& name() {
67     return name_;
68   }
69 
70  protected:
~Trace()71   virtual ~Trace() {}
72 
73  private:
74   friend class base::RefCounted<Trace>;
75 
76   std::string name_;
77 
78   DISALLOW_COPY_AND_ASSIGN(Trace);
79 };
80 
81 class GLARBTimerTrace : public Trace {
82  public:
83   GLARBTimerTrace(scoped_refptr<Outputter> outputter, const std::string& name,
84                   int64 offset);
85 
86   // Implementation of Tracer
87   virtual void Start() OVERRIDE;
88   virtual void End() OVERRIDE;
89   virtual bool IsAvailable() OVERRIDE;
90   virtual void Process() OVERRIDE;
91 
92  private:
93   virtual ~GLARBTimerTrace();
94 
95   void Output();
96 
97   scoped_refptr<Outputter> outputter_;
98 
99   int64 offset_;
100   int64 start_time_;
101   int64 end_time_;
102   bool end_requested_;
103 
104   GLuint queries_[2];
105 
106   DISALLOW_COPY_AND_ASSIGN(GLARBTimerTrace);
107 };
108 
109 class NoopTrace : public Trace {
110  public:
NoopTrace(const std::string & name)111   explicit NoopTrace(const std::string& name) : Trace(name) {}
112 
113   // Implementation of Tracer
Start()114   virtual void Start() OVERRIDE {}
End()115   virtual void End() OVERRIDE {}
IsAvailable()116   virtual bool IsAvailable() OVERRIDE { return true; }
IsProcessable()117   virtual bool IsProcessable() OVERRIDE { return false; }
Process()118   virtual void Process() OVERRIDE {}
119 
120  private:
~NoopTrace()121   virtual ~NoopTrace() {}
122 
123   DISALLOW_COPY_AND_ASSIGN(NoopTrace);
124 };
125 
126 class GPUTracerImpl
127     : public GPUTracer,
128       public base::SupportsWeakPtr<GPUTracerImpl> {
129  public:
GPUTracerImpl()130   GPUTracerImpl()
131       : gpu_category_enabled_(
132         TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("gpu")),
133         process_posted_(false) {
134   }
~GPUTracerImpl()135   virtual ~GPUTracerImpl() {}
136 
137   // Implementation of gpu::gles2::GPUTracer
138   virtual bool Begin(const std::string& name) OVERRIDE;
139   virtual bool End() OVERRIDE;
140   virtual const std::string& CurrentName() const OVERRIDE;
141 
142   // Process any completed traces.
143   virtual void Process();
144 
145  protected:
146   // Create a new trace.
147   virtual scoped_refptr<Trace> CreateTrace(const std::string& name);
148 
149   const unsigned char* gpu_category_enabled_;
150 
151  private:
152   void IssueProcessTask();
153 
154   scoped_refptr<Trace> current_trace_;
155   std::deque<scoped_refptr<Trace> > traces_;
156 
157   bool process_posted_;
158 
159   DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl);
160 };
161 
162 class GPUTracerARBTimerQuery : public GPUTracerImpl {
163  public:
164   GPUTracerARBTimerQuery();
165   virtual ~GPUTracerARBTimerQuery();
166 
167   // Implementation of GPUTracerImpl
168   virtual void Process() OVERRIDE;
169 
170  private:
171   // Implementation of GPUTracerImpl.
172   virtual scoped_refptr<Trace> CreateTrace(const std::string& name) OVERRIDE;
173 
174   void CalculateTimerOffset();
175 
176   scoped_refptr<Outputter> outputter_;
177 
178   int64 timer_offset_;
179   int64 last_offset_check_;
180 
181   DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery);
182 };
183 
GLARBTimerTrace(scoped_refptr<Outputter> outputter,const std::string & name,int64 offset)184 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter,
185                                  const std::string& name, int64 offset)
186     : Trace(name),
187       outputter_(outputter),
188       offset_(offset),
189       start_time_(0),
190       end_time_(0),
191       end_requested_(false) {
192   glGenQueries(2, queries_);
193 }
194 
~GLARBTimerTrace()195 GLARBTimerTrace::~GLARBTimerTrace() {
196 }
197 
Start()198 void GLARBTimerTrace::Start() {
199   glQueryCounter(queries_[0], GL_TIMESTAMP);
200 }
201 
End()202 void GLARBTimerTrace::End() {
203   glQueryCounter(queries_[1], GL_TIMESTAMP);
204   end_requested_ = true;
205 }
206 
IsAvailable()207 bool GLARBTimerTrace::IsAvailable() {
208   if (!end_requested_)
209     return false;
210 
211   GLint done = 0;
212   glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
213   return !!done;
214 }
215 
Process()216 void GLARBTimerTrace::Process() {
217   DCHECK(IsAvailable());
218 
219   GLint64 timestamp;
220 
221   // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
222   // We need to detect if the end is less then the start and correct for the
223   // wrapping.
224   glGetQueryObjecti64v(queries_[0], GL_QUERY_RESULT, &timestamp);
225   start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
226 
227   glGetQueryObjecti64v(queries_[1], GL_QUERY_RESULT, &timestamp);
228   end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
229 
230   glDeleteQueries(2, queries_);
231 
232   TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("gpu", name().c_str(),
233                                    this, outputter_->Id(), start_time_);
234   TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("gpu", name().c_str(),
235                                    this, outputter_->Id(), end_time_);
236 }
237 
Begin(const std::string & name)238 bool GPUTracerImpl::Begin(const std::string& name) {
239   // Make sure we are not nesting trace commands.
240   if (current_trace_.get())
241     return false;
242 
243   current_trace_ = CreateTrace(name);
244   current_trace_->Start();
245   return true;
246 }
247 
End()248 bool GPUTracerImpl::End() {
249   if (!current_trace_.get())
250     return false;
251 
252   current_trace_->End();
253   if (current_trace_->IsProcessable())
254     traces_.push_back(current_trace_);
255   current_trace_ = NULL;
256 
257   IssueProcessTask();
258   return true;
259 }
260 
Process()261 void GPUTracerImpl::Process() {
262   process_posted_ = false;
263 
264   while (!traces_.empty() && traces_.front()->IsAvailable()) {
265     traces_.front()->Process();
266     traces_.pop_front();
267   }
268 
269   IssueProcessTask();
270 }
271 
CurrentName() const272 const std::string& GPUTracerImpl::CurrentName() const {
273   if (!current_trace_.get())
274     return base::EmptyString();
275   return current_trace_->name();
276 }
277 
CreateTrace(const std::string & name)278 scoped_refptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) {
279   return new NoopTrace(name);
280 }
281 
IssueProcessTask()282 void GPUTracerImpl::IssueProcessTask() {
283   if (traces_.empty() || process_posted_)
284     return;
285 
286   process_posted_ = true;
287   base::MessageLoop::current()->PostDelayedTask(
288       FROM_HERE,
289       base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)),
290       base::TimeDelta::FromMilliseconds(kProcessInterval));
291 }
292 
GPUTracerARBTimerQuery()293 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery()
294     : GPUTracerImpl(),
295       timer_offset_(0),
296       last_offset_check_(0) {
297   CalculateTimerOffset();
298   outputter_ = Outputter::Create("GL_ARB_timer_query");
299 }
300 
~GPUTracerARBTimerQuery()301 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() {
302 }
303 
CreateTrace(const std::string & name)304 scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace(
305     const std::string& name) {
306   if (*gpu_category_enabled_)
307     return new GLARBTimerTrace(outputter_, name, timer_offset_);
308   return GPUTracerImpl::CreateTrace(name);
309 }
310 
Process()311 void GPUTracerARBTimerQuery::Process() {
312   GPUTracerImpl::Process();
313 
314   if (*gpu_category_enabled_ &&
315       (last_offset_check_ + base::Time::kMicrosecondsPerSecond) <
316           base::TimeTicks::NowFromSystemTraceTime().ToInternalValue())
317     CalculateTimerOffset();
318 }
319 
CalculateTimerOffset()320 void GPUTracerARBTimerQuery::CalculateTimerOffset() {
321   TRACE_EVENT0("gpu", "CalculateTimerOffset");
322   // TODO(dsinclair): Change to glGetInteger64v.
323   GLuint64 gl_now = 0;
324   GLuint query;
325   glGenQueries(1, &query);
326 
327   glQueryCounter(query, GL_TIMESTAMP);
328   glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now);
329   base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime();
330 
331   gl_now /= base::Time::kNanosecondsPerMicrosecond;
332   timer_offset_ = system_now.ToInternalValue() - gl_now;
333   glDeleteQueries(1, &query);
334 
335   last_offset_check_ = system_now.ToInternalValue();
336 }
337 
338 }  // namespace
339 
Create()340 scoped_ptr<GPUTracer> GPUTracer::Create() {
341   if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query)
342     return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery());
343   return scoped_ptr<GPUTracer>(new GPUTracerImpl());
344 }
345 
346 }  // namespace gles2
347 }  // namespace gpu
348