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