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 #include <stack> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/debug/trace_event.h" | |
12 #include "base/memory/linked_ptr.h" | |
13 #include "base/threading/non_thread_safe.h" | |
14 #include "base/threading/thread.h" | |
15 #include "base/time.h" | |
16 #include "ui/gl/gl_bindings.h" | |
17 | |
18 namespace gpu { | |
19 namespace gles2 { | |
20 namespace { | |
21 | |
22 static const unsigned int kGPUTraceMaxQueueSize = 1024; | |
23 | |
24 class Trace { | |
25 public: | |
26 virtual ~Trace() {}; | |
27 | |
28 virtual void Start() = 0; | |
29 virtual int64 start_time() = 0; | |
30 virtual void End() = 0; | |
31 virtual int64 end_time() = 0; | |
32 | |
33 // True if the the results of this query are available. | |
34 virtual bool IsAvailable() = 0; | |
35 virtual bool Discard() { return false; } | |
36 | |
37 const char* name() { | |
38 return name_.c_str(); | |
39 } | |
40 | |
41 protected: | |
42 explicit Trace(const std::string& name) : name_(name) {} | |
43 | |
44 private: | |
45 std::string name_; | |
46 | |
47 DISALLOW_COPY_AND_ASSIGN(Trace); | |
48 }; | |
49 | |
50 class GLARBTimerTrace : public Trace { | |
51 public: | |
52 explicit GLARBTimerTrace(const std::string& name); | |
53 ~GLARBTimerTrace() OVERRIDE; | |
54 | |
55 void Start() OVERRIDE; | |
56 int64 start_time() OVERRIDE; | |
57 void End() OVERRIDE; | |
58 int64 end_time() OVERRIDE; | |
59 bool IsAvailable() OVERRIDE; | |
60 | |
61 private: | |
62 unsigned int start_timer_; | |
63 unsigned int end_timer_; | |
64 | |
65 DISALLOW_COPY_AND_ASSIGN(GLARBTimerTrace); | |
66 }; | |
67 | |
68 class NoopTrace : public Trace { | |
69 public: | |
70 NoopTrace(const std::string& name) : Trace(name) {} | |
71 ~NoopTrace() {} | |
72 | |
73 void Start() {} | |
74 int64 start_time() { return 0; } | |
75 void End() {} | |
76 int64 end_time() { return 0; } | |
77 | |
78 bool IsAvailable() { return true; } | |
79 bool Discard() { return true; } | |
80 | |
81 private: | |
82 DISALLOW_COPY_AND_ASSIGN(NoopTrace); | |
83 }; | |
84 | |
85 class Outputter | |
86 : public base::Thread, | |
87 public base::RefCounted<Outputter> { | |
88 public: | |
89 static scoped_refptr<Outputter> Create(const std::string& name) { | |
90 if (!g_outputter_thread) { | |
91 g_outputter_thread = new Outputter(name); | |
92 g_outputter_thread->Start(); | |
93 } | |
94 return g_outputter_thread; | |
95 } | |
96 | |
97 void GLARBTimerQueryOutput(const char* name, int64 start, int64 end) { | |
98 // TODO(dsinclair): Change to TRACE_EVENT | |
99 LOG(ERROR) << "Thread " << thread_id() << ": " | |
100 << thread_name() << ": " | |
101 << name << ": " | |
102 << start << " " | |
103 << end; | |
104 } | |
105 | |
106 protected: | |
107 explicit Outputter(const std::string& name) | |
108 : base::Thread(name.c_str()), | |
109 current_id_(0) { | |
110 } | |
111 | |
112 virtual ~Outputter() { | |
113 g_outputter_thread->Stop(); | |
114 g_outputter_thread = NULL; | |
115 } | |
116 | |
117 static Outputter* g_outputter_thread; | |
118 | |
119 private: | |
120 friend class base::RefCounted<Outputter>; | |
121 | |
122 int64 current_id_; | |
123 | |
124 DISALLOW_COPY_AND_ASSIGN(Outputter); | |
125 }; | |
126 Outputter* Outputter::g_outputter_thread = NULL; | |
127 | |
128 class GPUTracerImpl : public GPUTracer { | |
129 public: | |
130 GPUTracerImpl() | |
131 : gpu_category_enabled_(TRACE_EVENT_API_GET_CATEGORY_ENABLED("gpu")) { | |
132 } | |
133 virtual ~GPUTracerImpl() {} | |
134 | |
135 // Begin a trace. | |
136 virtual bool Begin(const std::string& name) OVERRIDE; | |
137 | |
138 // End the last started trace. | |
139 virtual bool End() OVERRIDE; | |
140 | |
141 // Process any completed traces. | |
142 virtual void Process() OVERRIDE; | |
143 | |
144 protected: | |
145 // Create a new trace. | |
146 virtual linked_ptr<Trace> CreateTrace(const std::string& name); | |
147 | |
148 virtual void ProcessTrace(linked_ptr<Trace> trace) = 0; | |
149 | |
150 scoped_refptr<Outputter> output_; | |
151 | |
152 const unsigned char* gpu_category_enabled_; | |
153 | |
154 private: | |
155 linked_ptr<Trace> current_trace_; | |
156 std::deque<linked_ptr<Trace> > traces_; | |
157 | |
158 DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl); | |
159 }; | |
160 | |
161 class GPUTracerARBTimerQuery : public GPUTracerImpl { | |
162 public: | |
163 GPUTracerARBTimerQuery(); | |
164 ~GPUTracerARBTimerQuery(); | |
165 | |
166 linked_ptr<Trace> CreateTrace(const std::string& name); | |
167 | |
168 protected: | |
169 virtual void ProcessTrace(linked_ptr<Trace> trace); | |
170 | |
171 private: | |
172 int64 timer_offset_; | |
173 | |
174 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); | |
175 }; | |
176 | |
177 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery() : GPUTracerImpl() { | |
178 // TODO(dsinclair): Change to glGetInteger64v. | |
179 GLuint64 gl_now = 0; | |
180 GLuint query; | |
181 glGenQueries(1, &query); | |
182 | |
183 // Flush the pipeline so our query is more accurate. | |
184 glFinish(); | |
185 | |
186 glQueryCounter(query, GL_TIMESTAMP); | |
187 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | |
188 glDeleteQueries(1, &query); | |
189 | |
190 gl_now /= base::Time::kNanosecondsPerMicrosecond; | |
191 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | |
192 timer_offset_ = system_now.ToInternalValue() - gl_now; | |
193 | |
194 output_ = Outputter::Create("GL_ARB_timer_query"); | |
195 } | |
196 | |
197 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { | |
198 } | |
199 | |
200 linked_ptr<Trace> GPUTracerARBTimerQuery::CreateTrace( | |
201 const std::string& name) { | |
202 if (*gpu_category_enabled_) | |
203 return linked_ptr<Trace>(new GLARBTimerTrace(name)); | |
204 return GPUTracerImpl::CreateTrace(name); | |
205 } | |
206 | |
207 void GPUTracerARBTimerQuery::ProcessTrace(linked_ptr<Trace> trace) { | |
208 output_->message_loop()->PostTask(FROM_HERE, | |
209 base::Bind(&Outputter::GLARBTimerQueryOutput, output_, | |
210 base::Owned(strdup(trace->name())), | |
211 trace->start_time() + timer_offset_, | |
212 trace->end_time() + timer_offset_)); | |
jonathan.backer
2012/11/30 17:59:04
Can't we have the |trace| do this? Then we can dit
dsinclair
2012/11/30 19:45:15
Done.
| |
213 } | |
214 | |
215 GLARBTimerTrace::GLARBTimerTrace(const std::string& name) | |
216 : Trace(name), | |
217 start_timer_(0), | |
218 end_timer_(0) { | |
219 GLuint queries[2]; | |
220 glGenQueries(2, queries); | |
221 | |
222 start_timer_ = queries[0]; | |
223 end_timer_ = queries[1]; | |
224 } | |
225 | |
226 GLARBTimerTrace::~GLARBTimerTrace() { | |
227 GLuint queries[] = {start_timer_, end_timer_}; | |
228 glDeleteQueries(2, queries); | |
229 } | |
230 | |
231 void GLARBTimerTrace::Start() { | |
232 glQueryCounter(start_timer_, GL_TIMESTAMP); | |
233 } | |
234 | |
235 int64 GLARBTimerTrace::start_time() { | |
236 GLint64 timestamp; | |
237 glGetQueryObjecti64v(start_timer_, GL_QUERY_RESULT, ×tamp); | |
238 return timestamp / base::Time::kNanosecondsPerMicrosecond; | |
239 } | |
240 | |
241 void GLARBTimerTrace::End() { | |
242 glQueryCounter(end_timer_, GL_TIMESTAMP); | |
243 } | |
244 | |
245 int64 GLARBTimerTrace::end_time() { | |
246 GLint64 timestamp; | |
247 glGetQueryObjecti64v(end_timer_, GL_QUERY_RESULT, ×tamp); | |
248 return timestamp / base::Time::kNanosecondsPerMicrosecond; | |
249 } | |
250 | |
251 bool GLARBTimerTrace::IsAvailable() { | |
252 GLint done = 0; | |
253 glGetQueryObjectiv(end_timer_, GL_QUERY_RESULT_AVAILABLE, &done); | |
254 return !!done; | |
255 } | |
256 | |
257 bool GPUTracerImpl::Begin(const std::string& name) { | |
258 if (!*gpu_category_enabled_) | |
259 return true; | |
260 | |
261 // Make sure we are not nesting trace commands. | |
262 if (current_trace_.get() != NULL) | |
263 return false; | |
264 | |
265 current_trace_ = CreateTrace(name); | |
266 current_trace_->Start(); | |
267 return true; | |
268 } | |
269 | |
270 bool GPUTracerImpl::End() { | |
271 if (!*gpu_category_enabled_) { | |
272 current_trace_.reset(); | |
273 traces_.clear(); | |
274 return true; | |
275 } | |
276 | |
277 if (current_trace_.get() == NULL) { | |
278 return false; | |
279 } | |
280 | |
281 current_trace_->End(); | |
282 if (!current_trace_->Discard()) | |
283 traces_.push_back(current_trace_); | |
284 current_trace_.reset(); | |
285 | |
286 if (traces_.size() > kGPUTraceMaxQueueSize) | |
287 Process(); | |
288 | |
289 return true; | |
290 } | |
291 | |
292 void GPUTracerImpl::Process() { | |
293 while (!traces_.empty() && traces_.front()->IsAvailable()) { | |
294 ProcessTrace(traces_.front()); | |
295 traces_.pop_front(); | |
296 } | |
297 } | |
298 | |
299 linked_ptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) { | |
300 return linked_ptr<Trace>(new NoopTrace(name)); | |
301 } | |
302 | |
303 } // namespace | |
304 | |
305 scoped_ptr<GPUTracer> GPUTracer::Create() { | |
306 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) | |
307 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery()); | |
308 | |
309 return scoped_ptr<GPUTracer>(NULL); | |
310 } | |
311 | |
312 } // namespace gles2 | |
313 } // namespace gpu | |
OLD | NEW |