OLD | NEW |
(Empty) | |
| 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/string_util.h" |
| 13 #include "base/threading/thread.h" |
| 14 #include "base/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 ~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 ~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_(TRACE_EVENT_API_GET_CATEGORY_ENABLED("gpu")), |
| 132 process_posted_(false) { |
| 133 } |
| 134 virtual ~GPUTracerImpl() {} |
| 135 |
| 136 // Implementation of gpu::gles2::GPUTracer |
| 137 virtual bool Begin(const std::string& name) OVERRIDE; |
| 138 virtual bool End() OVERRIDE; |
| 139 virtual const std::string& CurrentName() const OVERRIDE; |
| 140 |
| 141 // Process any completed traces. |
| 142 virtual void Process(); |
| 143 |
| 144 protected: |
| 145 // Create a new trace. |
| 146 virtual scoped_refptr<Trace> CreateTrace(const std::string& name); |
| 147 |
| 148 const unsigned char* gpu_category_enabled_; |
| 149 |
| 150 private: |
| 151 void IssueProcessTask(); |
| 152 |
| 153 scoped_refptr<Trace> current_trace_; |
| 154 std::deque<scoped_refptr<Trace> > traces_; |
| 155 |
| 156 bool process_posted_; |
| 157 |
| 158 DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl); |
| 159 }; |
| 160 |
| 161 class GPUTracerARBTimerQuery : public GPUTracerImpl { |
| 162 public: |
| 163 GPUTracerARBTimerQuery(); |
| 164 virtual ~GPUTracerARBTimerQuery(); |
| 165 |
| 166 // Implementation of GPUTracerImpl |
| 167 virtual void Process() OVERRIDE; |
| 168 |
| 169 private: |
| 170 // Implementation of GPUTracerImpl. |
| 171 virtual scoped_refptr<Trace> CreateTrace(const std::string& name) OVERRIDE; |
| 172 |
| 173 void CalculateTimerOffset(); |
| 174 |
| 175 scoped_refptr<Outputter> outputter_; |
| 176 |
| 177 int64 timer_offset_; |
| 178 int64 last_offset_check_; |
| 179 |
| 180 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); |
| 181 }; |
| 182 |
| 183 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter, |
| 184 const std::string& name, int64 offset) |
| 185 : Trace(name), |
| 186 outputter_(outputter), |
| 187 offset_(offset), |
| 188 start_time_(0), |
| 189 end_time_(0), |
| 190 end_requested_(false) { |
| 191 glGenQueries(2, queries_); |
| 192 } |
| 193 |
| 194 GLARBTimerTrace::~GLARBTimerTrace() { |
| 195 } |
| 196 |
| 197 void GLARBTimerTrace::Start() { |
| 198 glQueryCounter(queries_[0], GL_TIMESTAMP); |
| 199 } |
| 200 |
| 201 void GLARBTimerTrace::End() { |
| 202 glQueryCounter(queries_[1], GL_TIMESTAMP); |
| 203 end_requested_ = true; |
| 204 } |
| 205 |
| 206 bool GLARBTimerTrace::IsAvailable() { |
| 207 if (!end_requested_) |
| 208 return false; |
| 209 |
| 210 GLint done = 0; |
| 211 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
| 212 return !!done; |
| 213 } |
| 214 |
| 215 void GLARBTimerTrace::Process() { |
| 216 DCHECK(IsAvailable()); |
| 217 |
| 218 GLint64 timestamp; |
| 219 |
| 220 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
| 221 // We need to detect if the end is less then the start and correct for the |
| 222 // wrapping. |
| 223 glGetQueryObjecti64v(queries_[0], GL_QUERY_RESULT, ×tamp); |
| 224 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| 225 |
| 226 glGetQueryObjecti64v(queries_[1], GL_QUERY_RESULT, ×tamp); |
| 227 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| 228 |
| 229 glDeleteQueries(2, queries_); |
| 230 |
| 231 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("gpu", name().c_str(), |
| 232 this, outputter_->Id(), start_time_); |
| 233 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("gpu", name().c_str(), |
| 234 this, outputter_->Id(), end_time_); |
| 235 } |
| 236 |
| 237 bool GPUTracerImpl::Begin(const std::string& name) { |
| 238 // Make sure we are not nesting trace commands. |
| 239 if (current_trace_) |
| 240 return false; |
| 241 |
| 242 current_trace_ = CreateTrace(name); |
| 243 current_trace_->Start(); |
| 244 return true; |
| 245 } |
| 246 |
| 247 bool GPUTracerImpl::End() { |
| 248 if (!current_trace_) |
| 249 return false; |
| 250 |
| 251 current_trace_->End(); |
| 252 if (current_trace_->IsProcessable()) |
| 253 traces_.push_back(current_trace_); |
| 254 current_trace_ = NULL; |
| 255 |
| 256 IssueProcessTask(); |
| 257 return true; |
| 258 } |
| 259 |
| 260 void GPUTracerImpl::Process() { |
| 261 process_posted_ = false; |
| 262 |
| 263 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
| 264 traces_.front()->Process(); |
| 265 traces_.pop_front(); |
| 266 } |
| 267 |
| 268 IssueProcessTask(); |
| 269 } |
| 270 |
| 271 const std::string& GPUTracerImpl::CurrentName() const { |
| 272 if (!current_trace_) |
| 273 return EmptyString(); |
| 274 return current_trace_->name(); |
| 275 } |
| 276 |
| 277 scoped_refptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) { |
| 278 return new NoopTrace(name); |
| 279 } |
| 280 |
| 281 void GPUTracerImpl::IssueProcessTask() { |
| 282 if (traces_.empty() || process_posted_) |
| 283 return; |
| 284 |
| 285 process_posted_ = true; |
| 286 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 287 base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)), |
| 288 base::TimeDelta::FromMilliseconds(kProcessInterval)); |
| 289 } |
| 290 |
| 291 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery() |
| 292 : GPUTracerImpl(), |
| 293 timer_offset_(0), |
| 294 last_offset_check_(0) { |
| 295 CalculateTimerOffset(); |
| 296 outputter_ = Outputter::Create("GL_ARB_timer_query"); |
| 297 } |
| 298 |
| 299 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { |
| 300 } |
| 301 |
| 302 scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace( |
| 303 const std::string& name) { |
| 304 if (*gpu_category_enabled_) |
| 305 return new GLARBTimerTrace(outputter_, name, timer_offset_); |
| 306 return GPUTracerImpl::CreateTrace(name); |
| 307 } |
| 308 |
| 309 void GPUTracerARBTimerQuery::Process() { |
| 310 GPUTracerImpl::Process(); |
| 311 |
| 312 if (*gpu_category_enabled_ && |
| 313 (last_offset_check_ + base::Time::kMicrosecondsPerSecond) < |
| 314 base::TimeTicks::NowFromSystemTraceTime().ToInternalValue()) |
| 315 CalculateTimerOffset(); |
| 316 } |
| 317 |
| 318 void GPUTracerARBTimerQuery::CalculateTimerOffset() { |
| 319 TRACE_EVENT0("gpu", "CalculateTimerOffset"); |
| 320 // TODO(dsinclair): Change to glGetInteger64v. |
| 321 GLuint64 gl_now = 0; |
| 322 GLuint query; |
| 323 glGenQueries(1, &query); |
| 324 |
| 325 glQueryCounter(query, GL_TIMESTAMP); |
| 326 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
| 327 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
| 328 |
| 329 gl_now /= base::Time::kNanosecondsPerMicrosecond; |
| 330 timer_offset_ = system_now.ToInternalValue() - gl_now; |
| 331 glDeleteQueries(1, &query); |
| 332 |
| 333 last_offset_check_ = system_now.ToInternalValue(); |
| 334 } |
| 335 |
| 336 } // namespace |
| 337 |
| 338 scoped_ptr<GPUTracer> GPUTracer::Create() { |
| 339 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) |
| 340 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery()); |
| 341 return scoped_ptr<GPUTracer>(new GPUTracerImpl()); |
| 342 } |
| 343 |
| 344 } // namespace gles2 |
| 345 } // namespace gpu |
OLD | NEW |