Index: gpu/command_buffer/service/gpu_tracer.cc |
diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3316c82fffc6ec4a853fbdd835607298a212296b |
--- /dev/null |
+++ b/gpu/command_buffer/service/gpu_tracer.cc |
@@ -0,0 +1,361 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "gpu/command_buffer/service/gpu_tracer.h" |
+ |
+#include "base/threading/non_thread_safe.h" |
+#include "base/threading/thread.h" |
+#include "base/time.h" |
+#include "ui/gl/gl_bindings.h" |
+ |
+namespace gpu { |
+namespace gles2 { |
+ |
+class GPUTracer::Trace { |
+ public: |
+ virtual ~Trace() {}; |
+ |
+ virtual void Start() = 0; |
+ virtual void End() = 0; |
+ |
+ // True if the the results of this query are available. |
+ virtual bool IsAvailable() = 0; |
+ |
+ const char* name() { |
+ return name_.c_str(); |
+ } |
+ |
+ protected: |
+ explicit Trace(const std::string& name) : name_(name) {} |
+ |
+ virtual int64 start_time() = 0; |
+ virtual int64 end_time() = 0; |
+ |
+ private: |
+ friend GPUTracer::Outputter; |
jonathan.backer
2012/11/23 18:55:41
Why friend? To read the name? You could hide the T
dsinclair
2012/11/23 21:13:56
Friend'd to give access to the start_time and end_
|
+ |
+ std::string name_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Trace); |
+}; |
+ |
+class GPUTracer::Outputter |
+ : public base::Thread, |
+ public base::NonThreadSafe { |
jonathan.backer
2012/11/23 18:55:41
base::NonThreadSafe is for sanity checking that yo
dsinclair
2012/11/23 21:13:56
copy-paste. Removed.
|
+ public: |
+ static linked_ptr<GPUTracer::Outputter> Create(const std::string& name) { |
jonathan.backer
2012/11/23 18:55:41
Why a linked_ptr? And why a factory?
dsinclair
2012/11/23 21:13:56
Was half an implementation of something else. Chan
|
+ linked_ptr<GPUTracer::Outputter> out = linked_ptr<GPUTracer::Outputter>( |
+ new GPUTracer::Outputter(name)); |
+ |
+ // We need to start/stop the thread in order to get a thread_id. |
+ out->Start(); |
+ out->Stop(); |
+ return out; |
+ } |
+ |
+ virtual ~Outputter() {} |
+ |
+ virtual void Output(GPUTracer::Trace* trace) { |
+ // TODO(dsinclair): Change to TRACE_EVENT |
+ LOG(INFO) << "Thread " << thread_id() << ": " |
+ << thread_name() << ": " |
+ << trace->name() << ": " |
+ << trace_start_time(trace) << " " |
+ << trace_end_time(trace); |
+ } |
+ |
+ protected: |
+ explicit Outputter(const std::string& name) : base::Thread(name.c_str()) { |
+ } |
+ |
+ |
+ int64 trace_start_time(GPUTracer::Trace* trace) { |
+ return trace->start_time(); |
+ } |
+ |
+ int64 trace_end_time(GPUTracer::Trace* trace) { |
+ return trace->end_time(); |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(Outputter); |
+}; |
+ |
+namespace { |
+ |
+static const unsigned int kGPUTraceMaxQueueSize = 1024; |
+ |
+class GPUTracerSystemTime : public GPUTracer { |
+ public: |
+ GPUTracerSystemTime(); |
+ ~GPUTracerSystemTime(); |
+ |
+ linked_ptr<GPUTracer::Trace> CreateTrace(const std::string& name) OVERRIDE; |
+ |
+ private: |
+ class Trace : public GPUTracer::Trace { |
+ public: |
+ explicit Trace(const std::string& name); |
+ ~Trace() OVERRIDE; |
+ |
+ void Start() OVERRIDE; |
+ void End() OVERRIDE; |
+ bool IsAvailable() OVERRIDE; |
+ |
+ protected: |
+ int64 start_time() OVERRIDE; |
+ int64 end_time() OVERRIDE; |
+ |
+ private: |
+ bool has_ended_; |
+ base::TimeTicks start_time_; |
+ base::TimeTicks end_time_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Trace); |
+ }; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GPUTracerSystemTime); |
+}; |
+ |
+class GPUTracerARBTimerQuery : public GPUTracer { |
+ public: |
+ GPUTracerARBTimerQuery(); |
+ ~GPUTracerARBTimerQuery(); |
+ |
+ linked_ptr<GPUTracer::Trace> CreateTrace(const std::string& name) OVERRIDE; |
+ |
+ private: |
+ class Trace : public GPUTracer::Trace { |
+ public: |
+ explicit Trace(const std::string& name); |
+ ~Trace() OVERRIDE; |
+ |
+ void Start() OVERRIDE; |
+ void End() OVERRIDE; |
+ bool IsAvailable() OVERRIDE; |
+ |
+ protected: |
+ int64 start_time() OVERRIDE; |
+ int64 end_time() OVERRIDE; |
+ |
+ private: |
+ unsigned int start_timer_; |
+ unsigned int end_timer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Trace); |
+ }; |
+ |
+ class Outputter : public GPUTracer::Outputter { |
+ public: |
+ static linked_ptr<GPUTracer::Outputter> Create(const std::string& name, |
+ int64 timer_offset) { |
+ linked_ptr<GPUTracer::Outputter> out = linked_ptr<GPUTracer::Outputter>( |
+ new GPUTracerARBTimerQuery::Outputter(name, timer_offset)); |
+ |
+ // We need to start/stop the thread in order to get a thread_id. |
+ out->Start(); |
+ out->Stop(); |
+ return out; |
+ } |
+ |
+ ~Outputter() {} |
+ |
+ void Output(GPUTracer::Trace* trace) OVERRIDE { |
+ // TODO(dsinclair): Change to TRACE_EVENT |
+ LOG(INFO) << "Thread " << thread_id() << ": " |
+ << thread_name() << ": " |
+ << trace->name() << ": " |
+ << trace_start_time(trace) << " " |
+ << trace_end_time(trace); |
+ } |
+ |
+ protected: |
+ explicit Outputter(const std::string& name, int64 timer_offset) |
+ : GPUTracer::Outputter(name.c_str()), |
+ timer_offset_(timer_offset) { |
+ } |
+ |
+ int64 trace_start_time(GPUTracer::Trace* trace) { |
+ return GPUTracer::Outputter::trace_start_time(trace) + timer_offset_; |
+ } |
+ |
+ int64 trace_end_time(GPUTracer::Trace* trace) { |
+ return GPUTracer::Outputter::trace_end_time(trace) + timer_offset_; |
+ } |
+ |
+ private: |
+ int64 timer_offset_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Outputter); |
+ }; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); |
+}; |
+ |
+GPUTracerSystemTime::GPUTracerSystemTime() : GPUTracer() { |
+ output_ = linked_ptr<GPUTracer::Outputter>( |
+ GPUTracer::Outputter::Create("SystemTime")); |
+} |
+ |
+GPUTracerSystemTime::~GPUTracerSystemTime() { |
+} |
+ |
+linked_ptr<GPUTracer::Trace> GPUTracerSystemTime::CreateTrace( |
+ const std::string& name) { |
+ return linked_ptr<GPUTracer::Trace>(new GPUTracerSystemTime::Trace(name)); |
+} |
+ |
+GPUTracerSystemTime::Trace::Trace(const std::string& name) : |
+ GPUTracer::Trace(name), |
+ has_ended_(false), |
+ start_time_(), |
+ end_time_() { |
+} |
+ |
+GPUTracerSystemTime::Trace::~Trace() { |
+} |
+ |
+void GPUTracerSystemTime::Trace::Start() { |
+ start_time_ = base::TimeTicks::NowFromSystemTraceTime(); |
+} |
+ |
+int64 GPUTracerSystemTime::Trace::start_time() { |
+ return start_time_.ToInternalValue(); |
+} |
+ |
+void GPUTracerSystemTime::Trace::End() { |
+ end_time_ = base::TimeTicks::NowFromSystemTraceTime(); |
+ has_ended_ = true; |
+} |
+ |
+int64 GPUTracerSystemTime::Trace::end_time() { |
+ return end_time_.ToInternalValue(); |
+} |
+ |
+bool GPUTracerSystemTime::Trace::IsAvailable() { |
+ return has_ended_; |
+} |
+ |
+GPUTracerARBTimerQuery::GPUTracerARBTimerQuery() : GPUTracer() { |
+ // TODO(dsinclair): Change to glGetInteger64v. |
+ GLuint64 gl_now = 0; |
+ GLuint query; |
+ glGenQueries(1, &query); |
+ |
+ // Flush the pipeline so our query is more accurate. |
+ glFinish(); |
+ |
+ glQueryCounter(query, GL_TIMESTAMP); |
+ glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
+ glDeleteQueries(1, &query); |
+ |
+ gl_now /= base::Time::kNanosecondsPerMicrosecond; |
+ |
+ base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
+ |
+ int64 time_offset = system_now.ToInternalValue() - gl_now; |
+ output_ = linked_ptr<GPUTracer::Outputter>( |
+ GPUTracerARBTimerQuery::Outputter::Create("GL_ARB_timer_query", |
+ time_offset)); |
+} |
+ |
+GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { |
+} |
+ |
+linked_ptr<GPUTracer::Trace> GPUTracerARBTimerQuery::CreateTrace( |
+ const std::string& name) { |
+ return linked_ptr<GPUTracer::Trace>(new GPUTracerARBTimerQuery::Trace(name)); |
+} |
+ |
+GPUTracerARBTimerQuery::Trace::Trace(const std::string& name) : |
+ GPUTracer::Trace(name), |
+ start_timer_(0), |
+ end_timer_(0) { |
+ GLuint queries[2]; |
+ glGenQueries(2, queries); |
+ |
+ start_timer_ = queries[0]; |
+ end_timer_ = queries[1]; |
+} |
+ |
+GPUTracerARBTimerQuery::Trace::~Trace() { |
+ GLuint queries[] = {start_timer_, end_timer_}; |
+ glDeleteQueries(2, queries); |
+} |
+ |
+void GPUTracerARBTimerQuery::Trace::Start() { |
+ glQueryCounter(start_timer_, GL_TIMESTAMP); |
+} |
+ |
+int64 GPUTracerARBTimerQuery::Trace::start_time() { |
+ GLint64 timestamp; |
+ glGetQueryObjecti64v(start_timer_, GL_QUERY_RESULT, ×tamp); |
+ return timestamp / base::Time::kNanosecondsPerMicrosecond; |
+} |
+ |
+void GPUTracerARBTimerQuery::Trace::End() { |
+ glQueryCounter(end_timer_, GL_TIMESTAMP); |
+} |
+ |
+int64 GPUTracerARBTimerQuery::Trace::end_time() { |
+ GLint64 timestamp; |
+ glGetQueryObjecti64v(end_timer_, GL_QUERY_RESULT, ×tamp); |
+ return timestamp / base::Time::kNanosecondsPerMicrosecond; |
+} |
+ |
+bool GPUTracerARBTimerQuery::Trace::IsAvailable() { |
+ GLint done = 0; |
+ glGetQueryObjectiv(end_timer_, GL_QUERY_RESULT_AVAILABLE, &done); |
+ return !!done; |
+} |
+ |
+} // namespace |
+ |
+scoped_ptr<GPUTracer> GPUTracer::create() { |
+ if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) |
+ return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery()); |
+ |
+ return scoped_ptr<GPUTracer>(new GPUTracerSystemTime()); |
+} |
+ |
+GPUTracer::GPUTracer() { |
+} |
+ |
+GPUTracer::~GPUTracer() { |
+} |
+ |
+bool GPUTracer::Begin(const std::string& name) { |
+ // Make sure we are not nesting trace commands. |
+ if (current_trace_.get() != NULL) |
+ return false; |
+ |
+ current_trace_ = CreateTrace(name); |
+ current_trace_->Start(); |
+ return true; |
+} |
+ |
+bool GPUTracer::End() { |
+ if (current_trace_.get() == NULL) { |
+ return false; |
+ } |
+ |
+ current_trace_->End(); |
+ traces_.push_back(current_trace_); |
+ current_trace_ = linked_ptr<GPUTracer::Trace>(NULL); |
jonathan.backer
2012/11/23 18:55:41
I think that you can just call .reset() here.
dsinclair
2012/11/23 21:13:56
Done.
|
+ |
+ if (traces_.size() > kGPUTraceMaxQueueSize) |
+ Process(); |
+ |
+ return true; |
+} |
+ |
+void GPUTracer::Process() { |
+ while (!traces_.empty() && traces_.front()->IsAvailable()) { |
+ output_->Output(traces_.front().get()); |
+ traces_.pop_front(); |
+ } |
+} |
+ |
+} // namespace gles2 |
+} // namespace gpu |