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 CPUTime::CPUTime() { | |
22 } | |
23 | |
24 int64 CPUTime::GetCurrentTime() { | |
25 return base::TimeTicks::NowFromSystemTraceTime().ToInternalValue(); | |
26 } | |
27 | |
28 CPUTime::~CPUTime() { | |
29 } | |
30 | |
21 TraceMarker::TraceMarker(const std::string& category, const std::string& name) | 31 TraceMarker::TraceMarker(const std::string& category, const std::string& name) |
22 : category_(category), | 32 : category_(category), |
23 name_(name), | 33 name_(name), |
24 trace_(NULL) { | 34 trace_(NULL) { |
25 } | 35 } |
26 | 36 |
27 TraceMarker::~TraceMarker() { | 37 TraceMarker::~TraceMarker() { |
28 } | 38 } |
29 | 39 |
30 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) { | 40 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) { |
31 if (!g_outputter_thread) { | 41 if (!g_outputter_thread) { |
32 g_outputter_thread = new TraceOutputter(name); | 42 g_outputter_thread = new TraceOutputter(name); |
33 } | 43 } |
34 return g_outputter_thread; | 44 return g_outputter_thread; |
35 } | 45 } |
36 | 46 |
37 TraceOutputter::TraceOutputter(const std::string& name) | 47 TraceOutputter::TraceOutputter(const std::string& name) |
38 : named_thread_(name.c_str()), local_trace_id_(0) { | 48 : named_thread_(name.c_str()), local_trace_id_(0) { |
39 named_thread_.Start(); | 49 named_thread_.Start(); |
40 named_thread_.Stop(); | 50 named_thread_.Stop(); |
41 } | 51 } |
42 | 52 |
43 TraceOutputter::~TraceOutputter() { g_outputter_thread = NULL; } | 53 TraceOutputter::~TraceOutputter() { g_outputter_thread = NULL; } |
44 | 54 |
45 void TraceOutputter::Trace(const std::string& category, | 55 void TraceOutputter::TraceDevice(const std::string& category, |
46 const std::string& name, | 56 const std::string& name, |
47 int64 start_time, | 57 int64 start_time, |
48 int64 end_time) { | 58 int64 end_time) { |
49 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category.c_str(), | 59 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category.c_str(), |
50 name.c_str(), | 60 name.c_str(), |
51 local_trace_id_, | 61 local_trace_id_, |
52 named_thread_.thread_id(), | 62 named_thread_.thread_id(), |
53 start_time); | 63 start_time); |
54 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0(category.c_str(), | 64 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0(category.c_str(), |
55 name.c_str(), | 65 name.c_str(), |
56 local_trace_id_, | 66 local_trace_id_, |
57 named_thread_.thread_id(), | 67 named_thread_.thread_id(), |
58 end_time); | 68 end_time); |
59 ++local_trace_id_; | 69 ++local_trace_id_; |
60 } | 70 } |
61 | 71 |
72 void TraceOutputter::TraceServiceBegin(const std::string& category, | |
73 const std::string& name, | |
74 void* id) { | |
75 TRACE_EVENT_COPY_ASYNC_BEGIN0(category.c_str(), name.c_str(), id); | |
vmiura
2015/01/07 00:40:56
Using dynamic category strings isn't working right
David Yen
2015/01/07 18:11:47
Yes, that change is still in the other CL where gl
| |
76 } | |
77 | |
78 void TraceOutputter::TraceServiceEnd(const std::string& category, | |
79 const std::string& name, | |
80 void* id) { | |
81 TRACE_EVENT_COPY_ASYNC_END0(category.c_str(), name.c_str(), id); | |
82 } | |
83 | |
62 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter, | 84 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter, |
85 scoped_refptr<CPUTime> cpu_time, | |
63 const std::string& category, | 86 const std::string& category, |
64 const std::string& name, | 87 const std::string& name, |
65 int64 offset, | 88 int64 offset, |
66 GpuTracerType tracer_type) | 89 GpuTracerType tracer_type) |
67 : category_(category), | 90 : category_(category), |
68 name_(name), | 91 name_(name), |
69 outputter_(outputter), | 92 outputter_(outputter), |
93 cpu_time_(cpu_time), | |
70 offset_(offset), | 94 offset_(offset), |
71 start_time_(0), | 95 start_time_(0), |
72 end_time_(0), | 96 end_time_(0), |
73 tracer_type_(tracer_type), | 97 tracer_type_(tracer_type), |
74 end_requested_(false) { | 98 end_requested_(false) { |
75 memset(queries_, 0, sizeof(queries_)); | 99 memset(queries_, 0, sizeof(queries_)); |
76 switch (tracer_type_) { | 100 switch (tracer_type_) { |
77 case kTracerTypeARBTimer: | 101 case kTracerTypeARBTimer: |
78 case kTracerTypeDisjointTimer: | 102 case kTracerTypeDisjointTimer: |
79 glGenQueriesARB(2, queries_); | 103 glGenQueriesARB(2, queries_); |
(...skipping 11 matching lines...) Expand all Loading... | |
91 | 115 |
92 case kTracerTypeARBTimer: | 116 case kTracerTypeARBTimer: |
93 case kTracerTypeDisjointTimer: | 117 case kTracerTypeDisjointTimer: |
94 glDeleteQueriesARB(2, queries_); | 118 glDeleteQueriesARB(2, queries_); |
95 break; | 119 break; |
96 } | 120 } |
97 } | 121 } |
98 | 122 |
99 void GPUTrace::Start(bool trace_service) { | 123 void GPUTrace::Start(bool trace_service) { |
100 if (trace_service) { | 124 if (trace_service) { |
101 TRACE_EVENT_COPY_ASYNC_BEGIN0(category().c_str(), name().c_str(), this); | 125 outputter_->TraceServiceBegin(category_, name_, this); |
102 } | 126 } |
103 | 127 |
104 switch (tracer_type_) { | 128 switch (tracer_type_) { |
105 case kTracerTypeInvalid: | 129 case kTracerTypeInvalid: |
106 break; | 130 break; |
107 | 131 |
108 case kTracerTypeDisjointTimer: | 132 case kTracerTypeDisjointTimer: |
109 // For the disjoint timer, GPU idle time does not seem to increment the | 133 // For the disjoint timer, GPU idle time does not seem to increment the |
110 // internal counter. We must calculate the offset before any query. The | 134 // internal counter. We must calculate the offset before any query. The |
111 // good news is any device that supports disjoint timer will also support | 135 // good news is any device that supports disjoint timer will also support |
112 // glGetInteger64v, so we can query it directly unlike the ARBTimer case. | 136 // glGetInteger64v, so we can query it directly unlike the ARBTimer case. |
113 // The "offset_" variable will always be 0 during normal use cases, only | 137 // The "offset_" variable will always be 0 during normal use cases, only |
114 // under the unit tests will it be set to specific test values. | 138 // under the unit tests will it be set to specific test values. |
115 if (offset_ == 0) { | 139 if (offset_ == 0) { |
116 GLint64 gl_now = 0; | 140 GLint64 gl_now = 0; |
117 glGetInteger64v(GL_TIMESTAMP, &gl_now); | 141 glGetInteger64v(GL_TIMESTAMP, &gl_now); |
118 offset_ = base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() - | 142 offset_ = cpu_time_->GetCurrentTime() - |
119 gl_now / base::Time::kNanosecondsPerMicrosecond; | 143 gl_now / base::Time::kNanosecondsPerMicrosecond; |
120 } | 144 } |
121 // Intentionally fall through to kTracerTypeARBTimer case.xs | 145 // Intentionally fall through to kTracerTypeARBTimer case.xs |
122 case kTracerTypeARBTimer: | 146 case kTracerTypeARBTimer: |
123 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. | 147 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. |
124 glQueryCounter(queries_[0], GL_TIMESTAMP); | 148 glQueryCounter(queries_[0], GL_TIMESTAMP); |
125 break; | 149 break; |
126 } | 150 } |
127 } | 151 } |
128 | 152 |
129 void GPUTrace::End(bool tracing_service) { | 153 void GPUTrace::End(bool tracing_service) { |
130 end_requested_ = true; | 154 end_requested_ = true; |
131 switch (tracer_type_) { | 155 switch (tracer_type_) { |
132 case kTracerTypeInvalid: | 156 case kTracerTypeInvalid: |
133 break; | 157 break; |
134 | 158 |
135 case kTracerTypeARBTimer: | 159 case kTracerTypeARBTimer: |
136 case kTracerTypeDisjointTimer: | 160 case kTracerTypeDisjointTimer: |
137 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. | 161 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. |
138 glQueryCounter(queries_[1], GL_TIMESTAMP); | 162 glQueryCounter(queries_[1], GL_TIMESTAMP); |
139 break; | 163 break; |
140 } | 164 } |
141 | 165 |
142 if (tracing_service) { | 166 if (tracing_service) { |
143 TRACE_EVENT_COPY_ASYNC_END0(category().c_str(), name().c_str(), this); | 167 outputter_->TraceServiceEnd(category_, name_, this); |
144 } | 168 } |
145 } | 169 } |
146 | 170 |
147 bool GPUTrace::IsAvailable() { | 171 bool GPUTrace::IsAvailable() { |
148 if (tracer_type_ != kTracerTypeInvalid) { | 172 if (tracer_type_ != kTracerTypeInvalid) { |
149 if (!end_requested_) | 173 if (!end_requested_) |
150 return false; | 174 return false; |
151 | 175 |
152 GLint done = 0; | 176 GLint done = 0; |
153 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | 177 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
(...skipping 14 matching lines...) Expand all Loading... | |
168 | 192 |
169 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | 193 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
170 // We need to detect if the end is less then the start and correct for the | 194 // We need to detect if the end is less then the start and correct for the |
171 // wrapping. | 195 // wrapping. |
172 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); | 196 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); |
173 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); | 197 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); |
174 | 198 |
175 start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + | 199 start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + |
176 offset_; | 200 offset_; |
177 end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 201 end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
178 outputter_->Trace(category(), name(), start_time_, end_time_); | 202 outputter_->TraceDevice(category(), name(), start_time_, end_time_); |
179 } | 203 } |
180 | 204 |
181 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) | 205 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
182 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 206 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
183 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), | 207 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
184 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 208 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
185 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), | 209 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
186 decoder_(decoder), | 210 decoder_(decoder), |
187 timer_offset_(0), | 211 timer_offset_(0), |
188 last_tracer_source_(kTraceGroupInvalid), | 212 last_tracer_source_(kTraceGroupInvalid), |
189 tracer_type_(kTracerTypeInvalid), | 213 tracer_type_(kTracerTypeInvalid), |
190 gpu_timing_synced_(false), | 214 gpu_timing_synced_(false), |
191 gpu_executing_(false), | 215 gpu_executing_(false), |
192 process_posted_(false) { | 216 process_posted_(false) { |
193 if (gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { | |
194 tracer_type_ = kTracerTypeDisjointTimer; | |
195 outputter_ = TraceOutputter::Create("GL_EXT_disjoint_timer_query"); | |
196 } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | |
197 tracer_type_ = kTracerTypeARBTimer; | |
198 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); | |
199 } | |
200 } | 217 } |
201 | 218 |
202 GPUTracer::~GPUTracer() { | 219 GPUTracer::~GPUTracer() { |
203 } | 220 } |
204 | 221 |
205 bool GPUTracer::BeginDecoding() { | 222 bool GPUTracer::BeginDecoding() { |
206 if (gpu_executing_) | 223 if (gpu_executing_) |
207 return false; | 224 return false; |
208 | 225 |
226 if (outputter_ == NULL) { | |
227 tracer_type_ = DetermineTracerType(); | |
228 const char* tracer_type_name = "Unknown"; | |
229 switch (tracer_type_) { | |
230 case kTracerTypeDisjointTimer: | |
231 tracer_type_name = "GL_EXT_disjoint_timer_query"; | |
232 break; | |
233 case kTracerTypeARBTimer: | |
234 tracer_type_name = "GL_ARB_timer_query"; | |
235 break; | |
236 | |
237 default: | |
238 break; | |
239 } | |
240 | |
241 outputter_ = CreateOutputter(tracer_type_name); | |
242 } | |
243 | |
244 if (cpu_time_ == NULL) { | |
245 cpu_time_ = CreateCPUTime(); | |
246 } | |
247 | |
209 CalculateTimerOffset(); | 248 CalculateTimerOffset(); |
210 gpu_executing_ = true; | 249 gpu_executing_ = true; |
211 | 250 |
212 if (IsTracing()) { | 251 if (IsTracing()) { |
213 // Reset disjoint bit for the disjoint timer. | 252 // Reset disjoint bit for the disjoint timer. |
214 if (tracer_type_ == kTracerTypeDisjointTimer) { | 253 if (tracer_type_ == kTracerTypeDisjointTimer) { |
215 GLint disjoint_value = 0; | 254 GLint disjoint_value = 0; |
216 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | 255 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
217 } | 256 } |
218 | 257 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 return markers_[last_tracer_source_].back().name_; | 359 return markers_[last_tracer_source_].back().name_; |
321 } | 360 } |
322 return base::EmptyString(); | 361 return base::EmptyString(); |
323 } | 362 } |
324 | 363 |
325 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& category, | 364 scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& category, |
326 const std::string& name) { | 365 const std::string& name) { |
327 GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : | 366 GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : |
328 kTracerTypeInvalid; | 367 kTracerTypeInvalid; |
329 | 368 |
330 return new GPUTrace(outputter_, category, name, timer_offset_, tracer_type); | 369 return new GPUTrace(outputter_, cpu_time_, category, name, |
370 timer_offset_, tracer_type); | |
371 } | |
372 | |
373 scoped_refptr<Outputter> GPUTracer::CreateOutputter(const std::string& name) { | |
374 return TraceOutputter::Create(name); | |
375 } | |
376 | |
377 scoped_refptr<CPUTime> GPUTracer::CreateCPUTime() { | |
378 return new CPUTime(); | |
379 } | |
380 | |
381 GpuTracerType GPUTracer::DetermineTracerType() { | |
382 if (gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { | |
383 return kTracerTypeDisjointTimer; | |
384 } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | |
385 return kTracerTypeARBTimer; | |
386 } | |
387 | |
388 return kTracerTypeInvalid; | |
389 } | |
390 | |
391 void GPUTracer::PostTask() { | |
392 base::MessageLoop::current()->PostDelayedTask( | |
393 FROM_HERE, | |
394 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), | |
395 base::TimeDelta::FromMilliseconds(kProcessInterval)); | |
331 } | 396 } |
332 | 397 |
333 void GPUTracer::Process() { | 398 void GPUTracer::Process() { |
334 process_posted_ = false; | 399 process_posted_ = false; |
335 ProcessTraces(); | 400 ProcessTraces(); |
336 IssueProcessTask(); | 401 IssueProcessTask(); |
337 } | 402 } |
338 | 403 |
339 void GPUTracer::ProcessTraces() { | 404 void GPUTracer::ProcessTraces() { |
340 if (tracer_type_ == kTracerTypeInvalid) { | 405 if (tracer_type_ == kTracerTypeInvalid) { |
341 traces_.clear(); | 406 traces_.clear(); |
342 return; | 407 return; |
343 } | 408 } |
344 | 409 |
345 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); | 410 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); |
346 | 411 |
347 // Make owning decoder's GL context current | 412 // Make owning decoder's GL context current |
348 if (!decoder_->MakeCurrent()) { | 413 if (decoder_ && !decoder_->MakeCurrent()) { |
vmiura
2015/01/07 00:40:56
Should the tests use a mock decoder instead?
David Yen
2015/01/07 18:11:48
Done.
| |
349 // Skip subsequent GL calls if MakeCurrent fails | 414 // Skip subsequent GL calls if MakeCurrent fails |
350 traces_.clear(); | 415 traces_.clear(); |
351 return; | 416 return; |
352 } | 417 } |
353 | 418 |
354 // Check if disjoint operation has occurred, discard ongoing traces if so. | 419 // Check if disjoint operation has occurred, discard ongoing traces if so. |
355 if (tracer_type_ == kTracerTypeDisjointTimer) { | 420 if (tracer_type_ == kTracerTypeDisjointTimer) { |
356 GLint disjoint_value = 0; | 421 GLint disjoint_value = 0; |
357 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | 422 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
358 if (disjoint_value) | 423 if (disjoint_value) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
394 | 459 |
395 glGenQueriesARB(1, &query); | 460 glGenQueriesARB(1, &query); |
396 | 461 |
397 glFinish(); | 462 glFinish(); |
398 glQueryCounter(query, GL_TIMESTAMP); | 463 glQueryCounter(query, GL_TIMESTAMP); |
399 glFinish(); | 464 glFinish(); |
400 | 465 |
401 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | 466 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
402 glDeleteQueriesARB(1, &query); | 467 glDeleteQueriesARB(1, &query); |
403 | 468 |
404 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | |
405 | |
406 gl_now /= base::Time::kNanosecondsPerMicrosecond; | 469 gl_now /= base::Time::kNanosecondsPerMicrosecond; |
407 timer_offset_ = system_now.ToInternalValue() - gl_now; | 470 timer_offset_ = cpu_time_->GetCurrentTime() - gl_now; |
408 gpu_timing_synced_ = true; | 471 gpu_timing_synced_ = true; |
409 } | 472 } |
410 } | 473 } |
411 | 474 |
412 void GPUTracer::IssueProcessTask() { | 475 void GPUTracer::IssueProcessTask() { |
413 if (traces_.empty() || process_posted_) | 476 if (traces_.empty() || process_posted_) |
414 return; | 477 return; |
415 | 478 |
416 process_posted_ = true; | 479 process_posted_ = true; |
417 base::MessageLoop::current()->PostDelayedTask( | 480 PostTask(); |
418 FROM_HERE, | |
419 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), | |
420 base::TimeDelta::FromMilliseconds(kProcessInterval)); | |
421 } | 481 } |
422 | 482 |
423 } // namespace gles2 | 483 } // namespace gles2 |
424 } // namespace gpu | 484 } // namespace gpu |
OLD | NEW |