OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gpu/command_buffer/service/gpu_tracer.h" | 5 #include "gpu/command_buffer/service/gpu_tracer.h" |
6 | 6 |
7 #include <deque> | 7 #include <deque> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
11 #include "base/memory/weak_ptr.h" | |
12 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
13 #include "base/threading/thread.h" | |
14 #include "base/time/time.h" | 12 #include "base/time/time.h" |
15 #include "ui/gl/gl_bindings.h" | |
16 | 13 |
17 namespace gpu { | 14 namespace gpu { |
18 namespace gles2 { | 15 namespace gles2 { |
19 namespace { | |
20 | |
21 class Outputter; | |
22 | 16 |
23 static const unsigned int kProcessInterval = 16; | 17 static const unsigned int kProcessInterval = 16; |
24 static Outputter* g_outputter_thread = NULL; | 18 static TraceOutputter* g_outputter_thread = NULL; |
25 | 19 |
26 class Outputter | 20 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) { |
27 : private base::Thread, | 21 if (!g_outputter_thread) { |
28 public base::RefCounted<Outputter> { | 22 g_outputter_thread = new TraceOutputter(name); |
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 } | 23 } |
| 24 return g_outputter_thread; |
| 25 } |
38 | 26 |
39 uint64 Id() { return thread_id(); } | 27 TraceOutputter::TraceOutputter(const std::string& name) |
| 28 : named_thread_(name.c_str()), local_trace_id_(0) { |
| 29 named_thread_.Start(); |
| 30 named_thread_.Stop(); |
| 31 } |
40 | 32 |
41 private: | 33 TraceOutputter::~TraceOutputter() { g_outputter_thread = NULL; } |
42 friend class base::RefCounted<Outputter>; | |
43 | 34 |
44 explicit Outputter(const std::string& name) : base::Thread(name.c_str()) {} | 35 void TraceOutputter::Trace(const std::string& name, |
45 | 36 int64 start_time, |
46 virtual ~Outputter() { | 37 int64 end_time) { |
47 g_outputter_thread = NULL; | 38 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("gpu", |
48 } | 39 name.c_str(), |
49 | 40 local_trace_id_, |
50 DISALLOW_COPY_AND_ASSIGN(Outputter); | 41 named_thread_.thread_id(), |
51 }; | 42 start_time); |
52 | 43 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("gpu", |
53 class Trace : public base::RefCounted<Trace> { | 44 name.c_str(), |
54 public: | 45 local_trace_id_, |
55 explicit Trace(const std::string& name) : name_(name) {} | 46 named_thread_.thread_id(), |
56 | 47 end_time); |
57 virtual void Start() = 0; | 48 ++local_trace_id_; |
58 virtual void End() = 0; | 49 } |
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 | 50 |
109 class NoopTrace : public Trace { | 51 class NoopTrace : public Trace { |
110 public: | 52 public: |
111 explicit NoopTrace(const std::string& name) : Trace(name) {} | 53 explicit NoopTrace(const std::string& name) : Trace(name) {} |
112 | 54 |
113 // Implementation of Tracer | 55 // Implementation of Tracer |
114 virtual void Start() OVERRIDE {} | 56 virtual void Start() OVERRIDE {} |
115 virtual void End() OVERRIDE {} | 57 virtual void End() OVERRIDE {} |
116 virtual bool IsAvailable() OVERRIDE { return true; } | 58 virtual bool IsAvailable() OVERRIDE { return true; } |
117 virtual bool IsProcessable() OVERRIDE { return false; } | 59 virtual bool IsProcessable() OVERRIDE { return false; } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 void CalculateTimerOffset(); | 116 void CalculateTimerOffset(); |
175 | 117 |
176 scoped_refptr<Outputter> outputter_; | 118 scoped_refptr<Outputter> outputter_; |
177 | 119 |
178 int64 timer_offset_; | 120 int64 timer_offset_; |
179 int64 last_offset_check_; | 121 int64 last_offset_check_; |
180 | 122 |
181 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); | 123 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); |
182 }; | 124 }; |
183 | 125 |
| 126 bool Trace::IsProcessable() { return true; } |
| 127 |
| 128 const std::string& Trace::name() { return name_; } |
| 129 |
184 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter, | 130 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter, |
185 const std::string& name, int64 offset) | 131 const std::string& name, |
| 132 int64 offset) |
186 : Trace(name), | 133 : Trace(name), |
187 outputter_(outputter), | 134 outputter_(outputter), |
188 offset_(offset), | 135 offset_(offset), |
189 start_time_(0), | 136 start_time_(0), |
190 end_time_(0), | 137 end_time_(0), |
191 end_requested_(false) { | 138 end_requested_(false) { |
192 glGenQueries(2, queries_); | 139 glGenQueries(2, queries_); |
193 } | 140 } |
194 | 141 |
195 GLARBTimerTrace::~GLARBTimerTrace() { | 142 GLARBTimerTrace::~GLARBTimerTrace() { |
(...skipping 13 matching lines...) Expand all Loading... |
209 return false; | 156 return false; |
210 | 157 |
211 GLint done = 0; | 158 GLint done = 0; |
212 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | 159 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
213 return !!done; | 160 return !!done; |
214 } | 161 } |
215 | 162 |
216 void GLARBTimerTrace::Process() { | 163 void GLARBTimerTrace::Process() { |
217 DCHECK(IsAvailable()); | 164 DCHECK(IsAvailable()); |
218 | 165 |
219 GLint64 timestamp; | 166 GLuint64 timestamp; |
220 | 167 |
221 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | 168 // 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 | 169 // We need to detect if the end is less then the start and correct for the |
223 // wrapping. | 170 // wrapping. |
224 glGetQueryObjecti64v(queries_[0], GL_QUERY_RESULT, ×tamp); | 171 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); |
225 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 172 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
226 | 173 |
227 glGetQueryObjecti64v(queries_[1], GL_QUERY_RESULT, ×tamp); | 174 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); |
228 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 175 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
229 | 176 |
230 glDeleteQueries(2, queries_); | 177 glDeleteQueries(2, queries_); |
231 | 178 outputter_->Trace(name(), start_time_, end_time_); |
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 } | 179 } |
237 | 180 |
238 bool GPUTracerImpl::Begin(const std::string& name) { | 181 bool GPUTracerImpl::Begin(const std::string& name) { |
239 // Make sure we are not nesting trace commands. | 182 // Make sure we are not nesting trace commands. |
240 if (current_trace_.get()) | 183 if (current_trace_.get()) |
241 return false; | 184 return false; |
242 | 185 |
243 current_trace_ = CreateTrace(name); | 186 current_trace_ = CreateTrace(name); |
244 current_trace_->Start(); | 187 current_trace_->Start(); |
245 return true; | 188 return true; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 FROM_HERE, | 231 FROM_HERE, |
289 base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)), | 232 base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)), |
290 base::TimeDelta::FromMilliseconds(kProcessInterval)); | 233 base::TimeDelta::FromMilliseconds(kProcessInterval)); |
291 } | 234 } |
292 | 235 |
293 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery() | 236 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery() |
294 : GPUTracerImpl(), | 237 : GPUTracerImpl(), |
295 timer_offset_(0), | 238 timer_offset_(0), |
296 last_offset_check_(0) { | 239 last_offset_check_(0) { |
297 CalculateTimerOffset(); | 240 CalculateTimerOffset(); |
298 outputter_ = Outputter::Create("GL_ARB_timer_query"); | 241 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
299 } | 242 } |
300 | 243 |
301 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { | 244 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { |
302 } | 245 } |
303 | 246 |
304 scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace( | 247 scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace( |
305 const std::string& name) { | 248 const std::string& name) { |
306 if (*gpu_category_enabled_) | 249 if (*gpu_category_enabled_) |
307 return new GLARBTimerTrace(outputter_, name, timer_offset_); | 250 return new GLARBTimerTrace(outputter_, name, timer_offset_); |
308 return GPUTracerImpl::CreateTrace(name); | 251 return GPUTracerImpl::CreateTrace(name); |
(...skipping 19 matching lines...) Expand all Loading... |
328 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | 271 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
329 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | 272 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
330 | 273 |
331 gl_now /= base::Time::kNanosecondsPerMicrosecond; | 274 gl_now /= base::Time::kNanosecondsPerMicrosecond; |
332 timer_offset_ = system_now.ToInternalValue() - gl_now; | 275 timer_offset_ = system_now.ToInternalValue() - gl_now; |
333 glDeleteQueries(1, &query); | 276 glDeleteQueries(1, &query); |
334 | 277 |
335 last_offset_check_ = system_now.ToInternalValue(); | 278 last_offset_check_ = system_now.ToInternalValue(); |
336 } | 279 } |
337 | 280 |
338 } // namespace | |
339 | |
340 scoped_ptr<GPUTracer> GPUTracer::Create() { | 281 scoped_ptr<GPUTracer> GPUTracer::Create() { |
341 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) | 282 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
342 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery()); | 283 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery()); |
| 284 } |
343 return scoped_ptr<GPUTracer>(new GPUTracerImpl()); | 285 return scoped_ptr<GPUTracer>(new GPUTracerImpl()); |
344 } | 286 } |
345 | 287 |
346 } // namespace gles2 | 288 } // namespace gles2 |
347 } // namespace gpu | 289 } // namespace gpu |
OLD | NEW |