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/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
13 #include "gpu/command_buffer/common/gles2_cmd_utils.h" | 13 #include "gpu/command_buffer/common/gles2_cmd_utils.h" |
14 | 14 |
15 namespace gpu { | 15 namespace gpu { |
16 namespace gles2 { | 16 namespace gles2 { |
17 | 17 |
18 static const unsigned int kProcessInterval = 16; | 18 static const unsigned int kProcessInterval = 16; |
19 static TraceOutputter* g_outputter_thread = NULL; | 19 static TraceOutputter* g_outputter_thread = NULL; |
20 | 20 |
| 21 TraceMarker::TraceMarker(const std::string& name) |
| 22 : name_(name), |
| 23 trace_(NULL) { |
| 24 } |
| 25 |
| 26 TraceMarker::~TraceMarker() { |
| 27 } |
| 28 |
21 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) { | 29 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) { |
22 if (!g_outputter_thread) { | 30 if (!g_outputter_thread) { |
23 g_outputter_thread = new TraceOutputter(name); | 31 g_outputter_thread = new TraceOutputter(name); |
24 } | 32 } |
25 return g_outputter_thread; | 33 return g_outputter_thread; |
26 } | 34 } |
27 | 35 |
28 TraceOutputter::TraceOutputter(const std::string& name) | 36 TraceOutputter::TraceOutputter(const std::string& name) |
29 : named_thread_(name.c_str()), local_trace_id_(0) { | 37 : named_thread_(name.c_str()), local_trace_id_(0) { |
30 named_thread_.Start(); | 38 named_thread_.Start(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); | 129 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); |
122 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 130 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
123 | 131 |
124 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); | 132 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); |
125 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 133 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
126 | 134 |
127 glDeleteQueries(2, queries_); | 135 glDeleteQueries(2, queries_); |
128 outputter_->Trace(name(), start_time_, end_time_); | 136 outputter_->Trace(name(), start_time_, end_time_); |
129 } | 137 } |
130 | 138 |
131 struct TraceMarker { | 139 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
132 TraceMarker(const std::string& name, GpuTracerSource source) | 140 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
133 : name_(name), source_(source) {} | 141 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
| 142 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| 143 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
| 144 decoder_(decoder), |
| 145 timer_offset_(0), |
| 146 last_tracer_source_(kTraceGroupInvalid), |
| 147 enabled_(false), |
| 148 gpu_timing_synced_(false), |
| 149 gpu_executing_(false), |
| 150 process_posted_(false) { |
| 151 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
| 152 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
| 153 enabled_ = true; |
| 154 } |
| 155 } |
134 | 156 |
135 std::string name_; | 157 GPUTracer::~GPUTracer() { |
136 GpuTracerSource source_; | 158 } |
137 scoped_refptr<GPUTrace> trace_; | |
138 }; | |
139 | 159 |
140 class GPUTracerImpl | 160 bool GPUTracer::BeginDecoding() { |
141 : public GPUTracer, | 161 if (enabled_) { |
142 public base::SupportsWeakPtr<GPUTracerImpl> { | 162 if (*gpu_trace_dev_category) { |
143 public: | 163 // Make sure timing is synced before tracing |
144 GPUTracerImpl() | 164 if (!gpu_timing_synced_) { |
145 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 165 CalculateTimerOffset(); |
146 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), | 166 gpu_timing_synced_ = true; |
147 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 167 } |
148 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), | 168 } else { |
149 gpu_executing_(false), | 169 // If GPU device category is off, invalidate timing sync |
150 process_posted_(false) {} | 170 gpu_timing_synced_ = false; |
151 virtual ~GPUTracerImpl() {} | 171 } |
| 172 } |
152 | 173 |
153 // Implementation of gpu::gles2::GPUTracer | |
154 virtual bool BeginDecoding() OVERRIDE; | |
155 virtual bool EndDecoding() OVERRIDE; | |
156 virtual bool Begin(const std::string& name, GpuTracerSource source) OVERRIDE; | |
157 virtual bool End(GpuTracerSource source) OVERRIDE; | |
158 virtual const std::string& CurrentName() const OVERRIDE; | |
159 virtual bool IsTracing() OVERRIDE { | |
160 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); | |
161 } | |
162 virtual void CalculateTimerOffset() {} | |
163 | |
164 // Process any completed traces. | |
165 virtual void Process(); | |
166 virtual void ProcessTraces(); | |
167 | |
168 protected: | |
169 // Create a new trace. | |
170 virtual scoped_refptr<GPUTrace> CreateTrace(const std::string& name); | |
171 | |
172 const unsigned char* gpu_trace_srv_category; | |
173 const unsigned char* gpu_trace_dev_category; | |
174 | |
175 protected: | |
176 void IssueProcessTask(); | |
177 | |
178 std::vector<TraceMarker> markers_; | |
179 std::deque<scoped_refptr<GPUTrace> > traces_; | |
180 | |
181 bool gpu_executing_; | |
182 bool process_posted_; | |
183 | |
184 DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl); | |
185 }; | |
186 | |
187 class GPUTracerARBTimerQuery : public GPUTracerImpl { | |
188 public: | |
189 explicit GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder); | |
190 virtual ~GPUTracerARBTimerQuery(); | |
191 | |
192 // Implementation of GPUTracerImpl | |
193 virtual void ProcessTraces() OVERRIDE; | |
194 | |
195 protected: | |
196 // Implementation of GPUTracerImpl. | |
197 virtual bool BeginDecoding() OVERRIDE; | |
198 virtual bool EndDecoding() OVERRIDE; | |
199 virtual scoped_refptr<GPUTrace> CreateTrace(const std::string& name) OVERRIDE; | |
200 virtual void CalculateTimerOffset() OVERRIDE; | |
201 | |
202 scoped_refptr<Outputter> outputter_; | |
203 | |
204 bool gpu_timing_synced_; | |
205 int64 timer_offset_; | |
206 | |
207 gles2::GLES2Decoder* decoder_; | |
208 | |
209 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); | |
210 }; | |
211 | |
212 bool GPUTracerImpl::BeginDecoding() { | |
213 if (gpu_executing_) | 174 if (gpu_executing_) |
214 return false; | 175 return false; |
215 | 176 |
216 gpu_executing_ = true; | 177 gpu_executing_ = true; |
217 | 178 |
218 if (IsTracing()) { | 179 if (IsTracing()) { |
219 // Begin a Trace for all active markers | 180 // Begin a Trace for all active markers |
220 for (size_t i = 0; i < markers_.size(); i++) { | 181 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
221 markers_[i].trace_ = CreateTrace(markers_[i].name_); | 182 for (size_t i = 0; i < markers_[n].size(); i++) { |
222 markers_[i].trace_->Start(); | 183 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); |
| 184 markers_[n][i].trace_->Start(); |
| 185 } |
223 } | 186 } |
224 } | 187 } |
225 return true; | 188 return true; |
226 } | 189 } |
227 | 190 |
228 bool GPUTracerImpl::EndDecoding() { | 191 bool GPUTracer::EndDecoding() { |
229 if (!gpu_executing_) | 192 if (!gpu_executing_) |
230 return false; | 193 return false; |
231 | 194 |
232 // End Trace for all active markers | 195 // End Trace for all active markers |
233 if (IsTracing()) { | 196 if (IsTracing()) { |
234 for (size_t i = 0; i < markers_.size(); i++) { | 197 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
235 if (markers_[i].trace_) { | 198 for (size_t i = 0; i < markers_[n].size(); i++) { |
236 markers_[i].trace_->End(); | 199 if (markers_[n][i].trace_) { |
237 if (markers_[i].trace_->IsEnabled()) | 200 markers_[n][i].trace_->End(); |
238 traces_.push_back(markers_[i].trace_); | 201 if (markers_[n][i].trace_->IsEnabled()) |
239 markers_[i].trace_ = 0; | 202 traces_.push_back(markers_[n][i].trace_); |
| 203 markers_[n][i].trace_ = 0; |
| 204 } |
240 } | 205 } |
241 } | 206 } |
242 IssueProcessTask(); | 207 IssueProcessTask(); |
243 } | 208 } |
244 | 209 |
245 gpu_executing_ = false; | 210 gpu_executing_ = false; |
| 211 |
| 212 // NOTE(vmiura): glFlush() here can help give better trace results, |
| 213 // but it distorts the normal device behavior. |
246 return true; | 214 return true; |
247 } | 215 } |
248 | 216 |
249 bool GPUTracerImpl::Begin(const std::string& name, GpuTracerSource source) { | 217 bool GPUTracer::Begin(const std::string& name, GpuTracerSource source) { |
250 if (!gpu_executing_) | 218 if (!gpu_executing_) |
251 return false; | 219 return false; |
252 | 220 |
| 221 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES); |
| 222 |
253 // Push new marker from given 'source' | 223 // Push new marker from given 'source' |
254 markers_.push_back(TraceMarker(name, source)); | 224 last_tracer_source_ = source; |
| 225 markers_[source].push_back(TraceMarker(name)); |
255 | 226 |
256 // Create trace | 227 // Create trace |
257 if (IsTracing()) { | 228 if (IsTracing()) { |
258 scoped_refptr<GPUTrace> trace = CreateTrace(name); | 229 scoped_refptr<GPUTrace> trace = CreateTrace(name); |
259 trace->Start(); | 230 trace->Start(); |
260 markers_.back().trace_ = trace; | 231 markers_[source].back().trace_ = trace; |
261 } | 232 } |
| 233 |
262 return true; | 234 return true; |
263 } | 235 } |
264 | 236 |
265 bool GPUTracerImpl::End(GpuTracerSource source) { | 237 bool GPUTracer::End(GpuTracerSource source) { |
266 if (!gpu_executing_) | 238 if (!gpu_executing_) |
267 return false; | 239 return false; |
268 | 240 |
| 241 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES); |
| 242 |
269 // Pop last marker with matching 'source' | 243 // Pop last marker with matching 'source' |
270 for (int i = markers_.size() - 1; i >= 0; i--) { | 244 if (!markers_[source].empty()) { |
271 if (markers_[i].source_ == source) { | 245 if (IsTracing()) { |
272 // End trace | 246 scoped_refptr<GPUTrace> trace = markers_[source].back().trace_; |
273 if (IsTracing()) { | 247 if (trace) { |
274 scoped_refptr<GPUTrace> trace = markers_[i].trace_; | 248 trace->End(); |
275 if (trace) { | 249 if (trace->IsEnabled()) |
276 trace->End(); | 250 traces_.push_back(trace); |
277 if (trace->IsEnabled()) | 251 IssueProcessTask(); |
278 traces_.push_back(trace); | |
279 IssueProcessTask(); | |
280 } | |
281 } | 252 } |
| 253 } |
282 | 254 |
283 markers_.erase(markers_.begin() + i); | 255 markers_[source].pop_back(); |
284 return true; | 256 return true; |
285 } | |
286 } | 257 } |
287 return false; | 258 return false; |
288 } | 259 } |
289 | 260 |
290 void GPUTracerImpl::Process() { | 261 bool GPUTracer::IsTracing() { |
| 262 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); |
| 263 } |
| 264 |
| 265 const std::string& GPUTracer::CurrentName() const { |
| 266 if (last_tracer_source_ >= 0 && |
| 267 last_tracer_source_ < NUM_TRACER_SOURCES && |
| 268 !markers_[last_tracer_source_].empty()) { |
| 269 return markers_[last_tracer_source_].back().name_; |
| 270 } |
| 271 return base::EmptyString(); |
| 272 } |
| 273 |
| 274 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& name) { |
| 275 if (enabled_ && *gpu_trace_dev_category) |
| 276 return new GPUTrace(outputter_, name, timer_offset_); |
| 277 else |
| 278 return new GPUTrace(name); |
| 279 } |
| 280 |
| 281 void GPUTracer::Process() { |
291 process_posted_ = false; | 282 process_posted_ = false; |
292 ProcessTraces(); | 283 ProcessTraces(); |
293 IssueProcessTask(); | 284 IssueProcessTask(); |
294 } | 285 } |
295 | 286 |
296 void GPUTracerImpl::ProcessTraces() { | 287 void GPUTracer::ProcessTraces() { |
297 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 288 if (!enabled_) { |
298 traces_.front()->Process(); | 289 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
299 traces_.pop_front(); | 290 traces_.front()->Process(); |
300 } | 291 traces_.pop_front(); |
301 } | 292 } |
302 | |
303 const std::string& GPUTracerImpl::CurrentName() const { | |
304 if (markers_.empty()) | |
305 return base::EmptyString(); | |
306 return markers_.back().name_; | |
307 } | |
308 | |
309 scoped_refptr<GPUTrace> GPUTracerImpl::CreateTrace( | |
310 const std::string& name) { | |
311 return new GPUTrace(name); | |
312 } | |
313 | |
314 void GPUTracerImpl::IssueProcessTask() { | |
315 if (traces_.empty() || process_posted_) | |
316 return; | 293 return; |
317 | |
318 process_posted_ = true; | |
319 base::MessageLoop::current()->PostDelayedTask( | |
320 FROM_HERE, | |
321 base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)), | |
322 base::TimeDelta::FromMilliseconds(kProcessInterval)); | |
323 } | |
324 | |
325 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder) | |
326 : timer_offset_(0), decoder_(decoder) { | |
327 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); | |
328 } | |
329 | |
330 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { | |
331 } | |
332 | |
333 scoped_refptr<GPUTrace> GPUTracerARBTimerQuery::CreateTrace( | |
334 const std::string& name) { | |
335 if (*gpu_trace_dev_category) | |
336 return new GPUTrace(outputter_, name, timer_offset_); | |
337 return GPUTracerImpl::CreateTrace(name); | |
338 } | |
339 | |
340 bool GPUTracerARBTimerQuery::BeginDecoding() { | |
341 if (*gpu_trace_dev_category) { | |
342 // Make sure timing is synced before tracing | |
343 if (!gpu_timing_synced_) { | |
344 CalculateTimerOffset(); | |
345 gpu_timing_synced_ = true; | |
346 } | |
347 } else { | |
348 // If GPU device category is off, invalidate timing sync | |
349 gpu_timing_synced_ = false; | |
350 } | 294 } |
351 | 295 |
352 return GPUTracerImpl::BeginDecoding(); | 296 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); |
353 } | |
354 | |
355 bool GPUTracerARBTimerQuery::EndDecoding() { | |
356 bool ret = GPUTracerImpl::EndDecoding(); | |
357 | |
358 // NOTE(vmiura_: glFlush() here can help give better trace results, | |
359 // but it distorts the normal device behavior. | |
360 return ret; | |
361 } | |
362 | |
363 void GPUTracerARBTimerQuery::ProcessTraces() { | |
364 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::ProcessTraces"); | |
365 | 297 |
366 // Make owning decoder's GL context current | 298 // Make owning decoder's GL context current |
367 if (!decoder_->MakeCurrent()) { | 299 if (!decoder_->MakeCurrent()) { |
368 // Skip subsequent GL calls if MakeCurrent fails | 300 // Skip subsequent GL calls if MakeCurrent fails |
369 traces_.clear(); | 301 traces_.clear(); |
370 return; | 302 return; |
371 } | 303 } |
372 | 304 |
373 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 305 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
374 traces_.front()->Process(); | 306 traces_.front()->Process(); |
375 traces_.pop_front(); | 307 traces_.pop_front(); |
376 } | 308 } |
377 | 309 |
378 // Clear pending traces if there were are any errors | 310 // Clear pending traces if there were are any errors |
379 GLenum err = glGetError(); | 311 GLenum err = glGetError(); |
380 if (err != GL_NO_ERROR) | 312 if (err != GL_NO_ERROR) |
381 traces_.clear(); | 313 traces_.clear(); |
382 } | 314 } |
383 | 315 |
384 void GPUTracerARBTimerQuery::CalculateTimerOffset() { | 316 void GPUTracer::CalculateTimerOffset() { |
385 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::CalculateTimerOffset"); | 317 if (enabled_) { |
| 318 TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); |
386 | 319 |
387 // NOTE(vmiura): It would be better to use glGetInteger64v, however | 320 // NOTE(vmiura): It would be better to use glGetInteger64v, however |
388 // it's not available everywhere. | 321 // it's not available everywhere. |
389 GLuint64 gl_now = 0; | 322 GLuint64 gl_now = 0; |
390 GLuint query; | 323 GLuint query; |
391 glFinish(); | 324 glFinish(); |
392 glGenQueries(1, &query); | 325 glGenQueries(1, &query); |
393 glQueryCounter(query, GL_TIMESTAMP); | 326 glQueryCounter(query, GL_TIMESTAMP); |
394 glFinish(); | 327 glFinish(); |
395 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | 328 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
396 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | 329 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
397 | 330 |
398 gl_now /= base::Time::kNanosecondsPerMicrosecond; | 331 gl_now /= base::Time::kNanosecondsPerMicrosecond; |
399 timer_offset_ = system_now.ToInternalValue() - gl_now; | 332 timer_offset_ = system_now.ToInternalValue() - gl_now; |
400 glDeleteQueries(1, &query); | 333 glDeleteQueries(1, &query); |
| 334 } |
401 } | 335 } |
402 | 336 |
403 GPUTracer::GPUTracer() {} | 337 void GPUTracer::IssueProcessTask() { |
| 338 if (traces_.empty() || process_posted_) |
| 339 return; |
404 | 340 |
405 GPUTracer::~GPUTracer() {} | 341 process_posted_ = true; |
406 | 342 base::MessageLoop::current()->PostDelayedTask( |
407 scoped_ptr<GPUTracer> GPUTracer::Create(gles2::GLES2Decoder* decoder) { | 343 FROM_HERE, |
408 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | 344 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), |
409 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery(decoder)); | 345 base::TimeDelta::FromMilliseconds(kProcessInterval)); |
410 } | |
411 return scoped_ptr<GPUTracer>(new GPUTracerImpl()); | |
412 } | 346 } |
413 | 347 |
414 } // namespace gles2 | 348 } // namespace gles2 |
415 } // namespace gpu | 349 } // namespace gpu |
OLD | NEW |