Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(334)

Side by Side Diff: gpu/command_buffer/service/gpu_tracer.cc

Issue 419073008: Simplified GPU Tracer by removing parent base class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 virtual bool IsAvailable() OVERRIDE { return true; } 67 virtual bool IsAvailable() OVERRIDE { return true; }
68 virtual bool IsProcessable() OVERRIDE { return false; } 68 virtual bool IsProcessable() OVERRIDE { return false; }
69 virtual void Process() OVERRIDE {} 69 virtual void Process() OVERRIDE {}
70 70
71 private: 71 private:
72 virtual ~NoopTrace() {} 72 virtual ~NoopTrace() {}
73 73
74 DISALLOW_COPY_AND_ASSIGN(NoopTrace); 74 DISALLOW_COPY_AND_ASSIGN(NoopTrace);
75 }; 75 };
76 76
77 struct TraceMarker { 77 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder)
78 TraceMarker(const std::string& name, GpuTracerSource source) 78 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
79 : name_(name), source_(source) {} 79 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
80 80 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
81 std::string name_; 81 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
82 GpuTracerSource source_; 82 decoder_(decoder),
83 scoped_refptr<Trace> trace_; 83 timer_offset_(0),
84 }; 84 last_tracer_source_(kTraceGroupInvalid),
85 85 enabled_(false),
86 class GPUTracerImpl 86 gpu_timing_synced_(false),
87 : public GPUTracer, 87 gpu_executing_(false),
88 public base::SupportsWeakPtr<GPUTracerImpl> { 88 process_posted_(false) {
89 public: 89 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) {
90 GPUTracerImpl() 90 outputter_ = TraceOutputter::Create("GL_ARB_timer_query");
91 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( 91 enabled_ = true;
92 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
93 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
94 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
95 gpu_executing_(false),
96 process_posted_(false) {}
97 virtual ~GPUTracerImpl() {}
98
99 // Implementation of gpu::gles2::GPUTracer
100 virtual bool BeginDecoding() OVERRIDE;
101 virtual bool EndDecoding() OVERRIDE;
102 virtual bool Begin(const std::string& name, GpuTracerSource source) OVERRIDE;
103 virtual bool End(GpuTracerSource source) OVERRIDE;
104 virtual const std::string& CurrentName() const OVERRIDE;
105 virtual bool IsTracing() OVERRIDE {
106 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0);
107 } 92 }
108 virtual void CalculateTimerOffset() {}
109
110 // Process any completed traces.
111 virtual void Process();
112 virtual void ProcessTraces();
113
114 protected:
115 // Create a new trace.
116 virtual scoped_refptr<Trace> CreateTrace(const std::string& name);
117
118 const unsigned char* gpu_trace_srv_category;
119 const unsigned char* gpu_trace_dev_category;
120
121 protected:
122 void IssueProcessTask();
123
124 std::vector<TraceMarker> markers_;
125 std::deque<scoped_refptr<Trace> > traces_;
126
127 bool gpu_executing_;
128 bool process_posted_;
129
130 DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl);
131 };
132
133 class GPUTracerARBTimerQuery : public GPUTracerImpl {
134 public:
135 explicit GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder);
136 virtual ~GPUTracerARBTimerQuery();
137
138 // Implementation of GPUTracerImpl
139 virtual void ProcessTraces() OVERRIDE;
140
141 protected:
142 // Implementation of GPUTracerImpl.
143 virtual bool BeginDecoding() OVERRIDE;
144 virtual bool EndDecoding() OVERRIDE;
145 virtual scoped_refptr<Trace> CreateTrace(const std::string& name) OVERRIDE;
146 virtual void CalculateTimerOffset() OVERRIDE;
147
148 scoped_refptr<Outputter> outputter_;
149
150 bool gpu_timing_synced_;
151 int64 timer_offset_;
152
153 gles2::GLES2Decoder* decoder_;
154
155 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery);
156 };
157
158 bool Trace::IsProcessable() { return true; }
159
160 const std::string& Trace::name() { return name_; }
161
162 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter,
163 const std::string& name,
164 int64 offset)
165 : Trace(name),
166 outputter_(outputter),
167 offset_(offset),
168 start_time_(0),
169 end_time_(0),
170 end_requested_(false) {
171 glGenQueries(2, queries_);
172 } 93 }
173 94
174 GLARBTimerTrace::~GLARBTimerTrace() { glDeleteQueries(2, queries_); } 95 GPUTracer::~GPUTracer() {
175
176 void GLARBTimerTrace::Start() {
177 TRACE_EVENT_COPY_ASYNC_BEGIN0(
178 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this);
179 glQueryCounter(queries_[0], GL_TIMESTAMP);
180 } 96 }
181 97
182 void GLARBTimerTrace::End() { 98 bool GPUTracer::BeginDecoding() {
183 glQueryCounter(queries_[1], GL_TIMESTAMP); 99 if (enabled_) {
184 end_requested_ = true; 100 if (*gpu_trace_dev_category) {
185 TRACE_EVENT_COPY_ASYNC_END0( 101 // Make sure timing is synced before tracing
186 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); 102 if (!gpu_timing_synced_) {
187 } 103 CalculateTimerOffset();
104 gpu_timing_synced_ = true;
105 }
106 } else {
107 // If GPU device category is off, invalidate timing sync
108 gpu_timing_synced_ = false;
109 }
110 }
188 111
189 bool GLARBTimerTrace::IsAvailable() {
190 if (!end_requested_)
191 return false;
192
193 GLint done = 0;
194 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
195 return !!done;
196 }
197
198 void GLARBTimerTrace::Process() {
199 DCHECK(IsAvailable());
200
201 GLuint64 timestamp;
202
203 // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
204 // We need to detect if the end is less then the start and correct for the
205 // wrapping.
206 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &timestamp);
207 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
208
209 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &timestamp);
210 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
211
212 glDeleteQueries(2, queries_);
213 outputter_->Trace(name(), start_time_, end_time_);
214 }
215
216 bool GPUTracerImpl::BeginDecoding() {
217 if (gpu_executing_) 112 if (gpu_executing_)
218 return false; 113 return false;
219 114
220 gpu_executing_ = true; 115 gpu_executing_ = true;
221 116
222 if (IsTracing()) { 117 if (IsTracing()) {
223 // Begin a Trace for all active markers 118 // Begin a Trace for all active markers
224 for (size_t i = 0; i < markers_.size(); i++) { 119 for (int n = 0; n < NUM_TRACER_SOURCES; n++) {
225 markers_[i].trace_ = CreateTrace(markers_[i].name_); 120 for (size_t i = 0; i < markers_[n].size(); i++) {
226 markers_[i].trace_->Start(); 121 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_);
122 markers_[n][i].trace_->Start();
123 }
227 } 124 }
228 } 125 }
229 return true; 126 return true;
230 } 127 }
231 128
232 bool GPUTracerImpl::EndDecoding() { 129 bool GPUTracer::EndDecoding() {
233 if (!gpu_executing_) 130 if (!gpu_executing_)
234 return false; 131 return false;
235 132
236 // End Trace for all active markers 133 // End Trace for all active markers
237 if (IsTracing()) { 134 if (IsTracing()) {
238 for (size_t i = 0; i < markers_.size(); i++) { 135 for (int n = 0; n < NUM_TRACER_SOURCES; n++) {
239 if (markers_[i].trace_) { 136 for (size_t i = 0; i < markers_[n].size(); i++) {
240 markers_[i].trace_->End(); 137 if (markers_[n][i].trace_) {
241 if (markers_[i].trace_->IsProcessable()) 138 markers_[n][i].trace_->End();
242 traces_.push_back(markers_[i].trace_); 139 if (markers_[n][i].trace_->IsProcessable())
243 markers_[i].trace_ = 0; 140 traces_.push_back(markers_[n][i].trace_);
141 markers_[n][i].trace_ = 0;
142 }
244 } 143 }
245 } 144 }
246 IssueProcessTask(); 145 IssueProcessTask();
247 } 146 }
248 147
249 gpu_executing_ = false; 148 gpu_executing_ = false;
149
150 // NOTE(vmiura_: glFlush() here can help give better trace results,
vmiura 2014/07/29 23:45:30 nit: NOTE(vmiura)
David Yen 2014/08/04 22:20:05 Done.
151 // but it distorts the normal device behavior.
250 return true; 152 return true;
251 } 153 }
252 154
253 bool GPUTracerImpl::Begin(const std::string& name, GpuTracerSource source) { 155 bool GPUTracer::Begin(const std::string& name, GpuTracerSource source) {
254 if (!gpu_executing_) 156 if (!gpu_executing_)
255 return false; 157 return false;
256 158
159 assert(source >= 0 && source < NUM_TRACER_SOURCES);
vmiura 2014/07/29 23:45:30 Please use DCHECK instead of assert here and below
David Yen 2014/08/04 22:20:05 Done.
160
257 // Push new marker from given 'source' 161 // Push new marker from given 'source'
258 markers_.push_back(TraceMarker(name, source)); 162 last_tracer_source_ = source;
163 markers_[source].push_back(TraceMarker(name));
259 164
260 // Create trace 165 // Create trace
261 if (IsTracing()) { 166 if (IsTracing()) {
262 scoped_refptr<Trace> trace = CreateTrace(name); 167 scoped_refptr<Trace> trace = CreateTrace(name);
263 trace->Start(); 168 trace->Start();
264 markers_.back().trace_ = trace; 169 markers_[source].back().trace_ = trace;
265 } 170 }
171
266 return true; 172 return true;
267 } 173 }
268 174
269 bool GPUTracerImpl::End(GpuTracerSource source) { 175 bool GPUTracer::End(GpuTracerSource source) {
270 if (!gpu_executing_) 176 if (!gpu_executing_)
271 return false; 177 return false;
272 178
179 assert(source >= 0 && source < NUM_TRACER_SOURCES);
180
273 // Pop last marker with matching 'source' 181 // Pop last marker with matching 'source'
274 for (int i = markers_.size() - 1; i >= 0; i--) { 182 if (!markers_[source].empty()) {
275 if (markers_[i].source_ == source) { 183 if (IsTracing()) {
276 // End trace 184 scoped_refptr<Trace> trace = markers_[source].back().trace_;
277 if (IsTracing()) { 185 if (trace) {
278 scoped_refptr<Trace> trace = markers_[i].trace_; 186 trace->End();
279 if (trace) { 187 if (trace->IsProcessable())
280 trace->End(); 188 traces_.push_back(trace);
281 if (trace->IsProcessable()) 189 IssueProcessTask();
282 traces_.push_back(trace);
283 IssueProcessTask();
284 }
285 } 190 }
191 }
286 192
287 markers_.erase(markers_.begin() + i); 193 markers_[source].pop_back();
288 return true; 194 return true;
289 }
290 } 195 }
291 return false; 196 return false;
292 } 197 }
293 198
294 void GPUTracerImpl::Process() { 199 bool GPUTracer::IsTracing() {
200 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0);
201 }
202
203 const std::string& GPUTracer::CurrentName() const {
204 if (last_tracer_source_ >= 0 &&
205 last_tracer_source_ < NUM_TRACER_SOURCES &&
206 !markers_[last_tracer_source_].empty()) {
207 return markers_[last_tracer_source_].back().name_;
208 }
209 return base::EmptyString();
210 }
211
212 void GPUTracer::CalculateTimerOffset() {
213 if (enabled_) {
214 TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset");
215
216 // NOTE(vmiura): It would be better to use glGetInteger64v, however
217 // it's not available everywhere.
218 GLuint64 gl_now = 0;
219 GLuint query;
220 glFinish();
221 glGenQueries(1, &query);
222 glQueryCounter(query, GL_TIMESTAMP);
223 glFinish();
224 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now);
225 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime();
226
227 gl_now /= base::Time::kNanosecondsPerMicrosecond;
228 timer_offset_ = system_now.ToInternalValue() - gl_now;
229 glDeleteQueries(1, &query);
230 }
231 }
232
233 scoped_refptr<Trace> GPUTracer::CreateTrace(const std::string& name) {
234 if (enabled_) {
235 if (*gpu_trace_dev_category)
236 return new GLARBTimerTrace(outputter_, name, timer_offset_);
237 }
238 return new NoopTrace(name);
239 }
240
241 void GPUTracer::Process() {
295 process_posted_ = false; 242 process_posted_ = false;
296 ProcessTraces(); 243 ProcessTraces();
297 IssueProcessTask(); 244 IssueProcessTask();
298 } 245 }
299 246
300 void GPUTracerImpl::ProcessTraces() { 247 void GPUTracer::ProcessTraces() {
301 while (!traces_.empty() && traces_.front()->IsAvailable()) { 248 if (!enabled_) {
302 traces_.front()->Process(); 249 while (!traces_.empty() && traces_.front()->IsAvailable()) {
303 traces_.pop_front(); 250 traces_.front()->Process();
304 } 251 traces_.pop_front();
305 } 252 }
306
307 const std::string& GPUTracerImpl::CurrentName() const {
308 if (markers_.empty())
309 return base::EmptyString();
310 return markers_.back().name_;
311 }
312
313 scoped_refptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) {
314 return new NoopTrace(name);
315 }
316
317 void GPUTracerImpl::IssueProcessTask() {
318 if (traces_.empty() || process_posted_)
319 return; 253 return;
320
321 process_posted_ = true;
322 base::MessageLoop::current()->PostDelayedTask(
323 FROM_HERE,
324 base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)),
325 base::TimeDelta::FromMilliseconds(kProcessInterval));
326 }
327
328 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder)
329 : timer_offset_(0), decoder_(decoder) {
330 outputter_ = TraceOutputter::Create("GL_ARB_timer_query");
331 }
332
333 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() {
334 }
335
336 scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace(
337 const std::string& name) {
338 if (*gpu_trace_dev_category)
339 return new GLARBTimerTrace(outputter_, name, timer_offset_);
340 return GPUTracerImpl::CreateTrace(name);
341 }
342
343 bool GPUTracerARBTimerQuery::BeginDecoding() {
344 if (*gpu_trace_dev_category) {
345 // Make sure timing is synced before tracing
346 if (!gpu_timing_synced_) {
347 CalculateTimerOffset();
348 gpu_timing_synced_ = true;
349 }
350 } else {
351 // If GPU device category is off, invalidate timing sync
352 gpu_timing_synced_ = false;
353 } 254 }
354 255
355 return GPUTracerImpl::BeginDecoding(); 256 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces");
356 }
357
358 bool GPUTracerARBTimerQuery::EndDecoding() {
359 bool ret = GPUTracerImpl::EndDecoding();
360
361 // NOTE(vmiura_: glFlush() here can help give better trace results,
362 // but it distorts the normal device behavior.
363 return ret;
364 }
365
366 void GPUTracerARBTimerQuery::ProcessTraces() {
367 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::ProcessTraces");
368 257
369 // Make owning decoder's GL context current 258 // Make owning decoder's GL context current
370 if (!decoder_->MakeCurrent()) { 259 if (!decoder_->MakeCurrent()) {
371 // Skip subsequent GL calls if MakeCurrent fails 260 // Skip subsequent GL calls if MakeCurrent fails
372 traces_.clear(); 261 traces_.clear();
373 return; 262 return;
374 } 263 }
375 264
376 while (!traces_.empty() && traces_.front()->IsAvailable()) { 265 while (!traces_.empty() && traces_.front()->IsAvailable()) {
377 traces_.front()->Process(); 266 traces_.front()->Process();
378 traces_.pop_front(); 267 traces_.pop_front();
379 } 268 }
380 269
381 // Clear pending traces if there were are any errors 270 // Clear pending traces if there were are any errors
382 GLenum err = glGetError(); 271 GLenum err = glGetError();
383 if (err != GL_NO_ERROR) 272 if (err != GL_NO_ERROR)
384 traces_.clear(); 273 traces_.clear();
385 } 274 }
386 275
387 void GPUTracerARBTimerQuery::CalculateTimerOffset() { 276 void GPUTracer::IssueProcessTask() {
388 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::CalculateTimerOffset"); 277 if (traces_.empty() || process_posted_)
278 return;
389 279
390 // NOTE(vmiura): It would be better to use glGetInteger64v, however 280 process_posted_ = true;
391 // it's not available everywhere. 281 base::MessageLoop::current()->PostDelayedTask(
392 GLuint64 gl_now = 0; 282 FROM_HERE,
393 GLuint query; 283 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)),
394 glFinish(); 284 base::TimeDelta::FromMilliseconds(kProcessInterval));
395 glGenQueries(1, &query);
396 glQueryCounter(query, GL_TIMESTAMP);
397 glFinish();
398 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now);
399 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime();
400
401 gl_now /= base::Time::kNanosecondsPerMicrosecond;
402 timer_offset_ = system_now.ToInternalValue() - gl_now;
403 glDeleteQueries(1, &query);
404 } 285 }
405 286
406 GPUTracer::GPUTracer() {} 287 bool Trace::IsProcessable() { return true; }
407 288
408 GPUTracer::~GPUTracer() {} 289 const std::string& Trace::name() { return name_; }
409 290
410 scoped_ptr<GPUTracer> GPUTracer::Create(gles2::GLES2Decoder* decoder) { 291 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter,
411 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { 292 const std::string& name,
412 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery(decoder)); 293 int64 offset)
413 } 294 : Trace(name),
414 return scoped_ptr<GPUTracer>(new GPUTracerImpl()); 295 outputter_(outputter),
296 offset_(offset),
297 start_time_(0),
298 end_time_(0),
299 end_requested_(false) {
300 glGenQueries(2, queries_);
301 }
302
303 GLARBTimerTrace::~GLARBTimerTrace() { glDeleteQueries(2, queries_); }
304
305 void GLARBTimerTrace::Start() {
306 TRACE_EVENT_COPY_ASYNC_BEGIN0(
307 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this);
308 glQueryCounter(queries_[0], GL_TIMESTAMP);
309 }
310
311 void GLARBTimerTrace::End() {
312 glQueryCounter(queries_[1], GL_TIMESTAMP);
313 end_requested_ = true;
314 TRACE_EVENT_COPY_ASYNC_END0(
315 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this);
316 }
317
318 bool GLARBTimerTrace::IsAvailable() {
319 if (!end_requested_)
320 return false;
321
322 GLint done = 0;
323 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
324 return !!done;
325 }
326
327 void GLARBTimerTrace::Process() {
328 DCHECK(IsAvailable());
329
330 GLuint64 timestamp;
331
332 // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
333 // We need to detect if the end is less then the start and correct for the
334 // wrapping.
335 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &timestamp);
336 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
337
338 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &timestamp);
339 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
340
341 glDeleteQueries(2, queries_);
342 outputter_->Trace(name(), start_time_, end_time_);
415 } 343 }
416 344
417 } // namespace gles2 345 } // namespace gles2
418 } // namespace gpu 346 } // namespace gpu
OLDNEW
« gpu/command_buffer/service/gpu_tracer.h ('K') | « gpu/command_buffer/service/gpu_tracer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698