Home | History | Annotate | Download | only in service
      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:
     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 
     39   uint64 Id() { return thread_id(); }
     40 
     41  private:
     42   friend class base::RefCounted<Outputter>;
     43 
     44   explicit Outputter(const std::string& name) : base::Thread(name.c_str()) {}
     45 
     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:
     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 
     63   virtual bool IsProcessable() { return true; }
     64   virtual void Process() = 0;
     65 
     66   virtual const std::string& name() {
     67     return name_;
     68   }
     69 
     70  protected:
     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:
    111   explicit NoopTrace(const std::string& name) : Trace(name) {}
    112 
    113   // Implementation of Tracer
    114   virtual void Start() OVERRIDE {}
    115   virtual void End() OVERRIDE {}
    116   virtual bool IsAvailable() OVERRIDE { return true; }
    117   virtual bool IsProcessable() OVERRIDE { return false; }
    118   virtual void Process() OVERRIDE {}
    119 
    120  private:
    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:
    130   GPUTracerImpl()
    131       : gpu_category_enabled_(
    132         TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("gpu")),
    133         process_posted_(false) {
    134   }
    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 
    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 
    195 GLARBTimerTrace::~GLARBTimerTrace() {
    196 }
    197 
    198 void GLARBTimerTrace::Start() {
    199   glQueryCounter(queries_[0], GL_TIMESTAMP);
    200 }
    201 
    202 void GLARBTimerTrace::End() {
    203   glQueryCounter(queries_[1], GL_TIMESTAMP);
    204   end_requested_ = true;
    205 }
    206 
    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 
    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 
    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 
    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 
    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 
    272 const std::string& GPUTracerImpl::CurrentName() const {
    273   if (!current_trace_.get())
    274     return EmptyString();
    275   return current_trace_->name();
    276 }
    277 
    278 scoped_refptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) {
    279   return new NoopTrace(name);
    280 }
    281 
    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 
    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 
    301 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() {
    302 }
    303 
    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 
    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 
    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 
    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