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.
5 #include "gpu/command_buffer/service/gpu_tracer.h"
10 #include "base/strings/string_util.h"
11 #include "base/time/time.h"
12 #include "base/trace_event/trace_event.h"
13 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
14 #include "gpu/command_buffer/service/context_group.h"
15 #include "ui/gl/gl_bindings.h"
16 #include "ui/gl/gl_version_info.h"
17 #include "ui/gl/gpu_timing.h"
22 static const unsigned int kProcessInterval
= 16;
23 static TraceOutputter
* g_outputter_thread
= NULL
;
25 TraceMarker::TraceMarker(const std::string
& category
, const std::string
& name
)
26 : category_(category
),
31 TraceMarker::~TraceMarker() {
34 scoped_refptr
<TraceOutputter
> TraceOutputter::Create(const std::string
& name
) {
35 if (!g_outputter_thread
) {
36 g_outputter_thread
= new TraceOutputter(name
);
38 return g_outputter_thread
;
41 TraceOutputter::TraceOutputter(const std::string
& name
)
42 : named_thread_(name
.c_str()), local_trace_id_(0) {
43 named_thread_
.Start();
47 TraceOutputter::~TraceOutputter() { g_outputter_thread
= NULL
; }
49 void TraceOutputter::TraceDevice(const std::string
& category
,
50 const std::string
& name
,
53 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1(
54 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
57 named_thread_
.thread_id(),
61 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1(
62 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
65 named_thread_
.thread_id(),
72 void TraceOutputter::TraceServiceBegin(const std::string
& category
,
73 const std::string
& name
) {
74 TRACE_EVENT_COPY_BEGIN1(TRACE_DISABLED_BY_DEFAULT("gpu.service"),
75 name
.c_str(), "gl_category", category
.c_str());
78 void TraceOutputter::TraceServiceEnd(const std::string
& category
,
79 const std::string
& name
) {
80 TRACE_EVENT_COPY_END1(TRACE_DISABLED_BY_DEFAULT("gpu.service"),
81 name
.c_str(), "gl_category", category
.c_str());
84 GPUTrace::GPUTrace(scoped_refptr
<Outputter
> outputter
,
85 gfx::GPUTimingClient
* gpu_timing_client
,
86 const std::string
& category
,
87 const std::string
& name
,
89 : category_(category
),
91 outputter_(outputter
),
93 if (gpu_timing_client
->IsAvailable() &&
94 gpu_timing_client
->IsTimerOffsetAvailable()) {
95 gpu_timer_
= gpu_timing_client
->CreateGPUTimer();
99 GPUTrace::~GPUTrace() {
102 void GPUTrace::Destroy(bool have_context
) {
103 if (gpu_timer_
.get()) {
104 gpu_timer_
->Destroy(have_context
);
108 void GPUTrace::Start(bool trace_service
) {
110 outputter_
->TraceServiceBegin(category_
, name_
);
112 if (gpu_timer_
.get()) {
117 void GPUTrace::End(bool tracing_service
) {
118 if (gpu_timer_
.get()) {
121 if (tracing_service
) {
122 outputter_
->TraceServiceEnd(category_
, name_
);
126 bool GPUTrace::IsAvailable() {
127 return !gpu_timer_
.get() || gpu_timer_
->IsAvailable();
130 void GPUTrace::Process() {
131 if (gpu_timer_
.get()) {
132 DCHECK(IsAvailable());
136 gpu_timer_
->GetStartEndTimestamps(&start
, &end
);
137 outputter_
->TraceDevice(category_
, name_
, start
, end
);
141 GPUTracer::GPUTracer(gles2::GLES2Decoder
* decoder
)
142 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
143 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
144 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
145 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
147 gpu_executing_(false),
148 process_posted_(false) {
150 gfx::GLContext
* context
= decoder_
->GetGLContext();
152 gpu_timing_client_
= context
->CreateGPUTimingClient();
154 gpu_timing_client_
= new gfx::GPUTimingClient();
158 GPUTracer::~GPUTracer() {
161 void GPUTracer::Destroy(bool have_context
) {
162 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
163 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
164 TraceMarker
& marker
= markers_
[n
][i
];
165 if (marker
.trace_
.get()) {
166 marker
.trace_
->Destroy(have_context
);
172 ClearFinishedTraces(have_context
);
175 bool GPUTracer::BeginDecoding() {
180 outputter_
= CreateOutputter(gpu_timing_client_
->GetTimerTypeName());
183 if (*gpu_trace_dev_category
== '\0') {
184 // If GPU device category is off, invalidate timing sync.
185 gpu_timing_client_
->InvalidateTimerOffset();
188 gpu_executing_
= true;
190 gpu_timing_client_
->CheckAndResetTimerErrors();
191 // Begin a Trace for all active markers
192 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
193 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
194 TraceMarker
& trace_marker
= markers_
[n
][i
];
195 trace_marker
.trace_
=
196 new GPUTrace(outputter_
, gpu_timing_client_
.get(),
197 trace_marker
.category_
, trace_marker
.name_
,
198 *gpu_trace_dev_category
!= 0);
199 trace_marker
.trace_
->Start(*gpu_trace_srv_category
!= 0);
206 bool GPUTracer::EndDecoding() {
210 // End Trace for all active markers
212 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
213 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
214 TraceMarker
& marker
= markers_
[n
][i
];
215 if (marker
.trace_
.get()) {
216 marker
.trace_
->End(*gpu_trace_srv_category
!= 0);
218 finished_traces_
.push_back(marker
.trace_
);
226 gpu_executing_
= false;
228 // NOTE(vmiura): glFlush() here can help give better trace results,
229 // but it distorts the normal device behavior.
233 bool GPUTracer::Begin(const std::string
& category
, const std::string
& name
,
234 GpuTracerSource source
) {
238 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
240 // Push new marker from given 'source'
241 markers_
[source
].push_back(TraceMarker(category
, name
));
245 scoped_refptr
<GPUTrace
> trace
= new GPUTrace(
246 outputter_
, gpu_timing_client_
.get(), category
, name
,
247 *gpu_trace_dev_category
!= 0);
248 trace
->Start(*gpu_trace_srv_category
!= 0);
249 markers_
[source
].back().trace_
= trace
;
255 bool GPUTracer::End(GpuTracerSource source
) {
259 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
261 // Pop last marker with matching 'source'
262 if (!markers_
[source
].empty()) {
263 scoped_refptr
<GPUTrace
> trace
= markers_
[source
].back().trace_
;
266 trace
->End(*gpu_trace_srv_category
!= 0);
269 finished_traces_
.push_back(trace
);
273 markers_
[source
].pop_back();
279 bool GPUTracer::IsTracing() {
280 return (*gpu_trace_srv_category
!= 0) || (*gpu_trace_dev_category
!= 0);
283 const std::string
& GPUTracer::CurrentCategory(GpuTracerSource source
) const {
285 source
< NUM_TRACER_SOURCES
&&
286 !markers_
[source
].empty()) {
287 return markers_
[source
].back().category_
;
289 return base::EmptyString();
292 const std::string
& GPUTracer::CurrentName(GpuTracerSource source
) const {
294 source
< NUM_TRACER_SOURCES
&&
295 !markers_
[source
].empty()) {
296 return markers_
[source
].back().name_
;
298 return base::EmptyString();
301 scoped_refptr
<Outputter
> GPUTracer::CreateOutputter(const std::string
& name
) {
302 return TraceOutputter::Create(name
);
305 void GPUTracer::PostTask() {
306 base::MessageLoop::current()->PostDelayedTask(
308 base::Bind(&GPUTracer::Process
, base::AsWeakPtr(this)),
309 base::TimeDelta::FromMilliseconds(kProcessInterval
));
312 void GPUTracer::Process() {
313 process_posted_
= false;
318 void GPUTracer::ProcessTraces() {
319 if (!gpu_timing_client_
->IsAvailable()) {
320 ClearFinishedTraces(false);
324 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces");
326 // Make owning decoder's GL context current
327 if (!decoder_
->MakeCurrent()) {
328 // Skip subsequent GL calls if MakeCurrent fails
329 ClearFinishedTraces(false);
333 // Check if timers are still valid (e.g: a disjoint operation
334 // might have occurred.)
335 if (gpu_timing_client_
->CheckAndResetTimerErrors()) {
336 ClearFinishedTraces(true);
339 while (!finished_traces_
.empty()) {
340 scoped_refptr
<GPUTrace
>& trace
= finished_traces_
.front();
341 if (trace
->IsEnabled()) {
342 if (!finished_traces_
.front()->IsAvailable())
344 finished_traces_
.front()->Process();
346 finished_traces_
.front()->Destroy(true);
347 finished_traces_
.pop_front();
350 // Clear pending traces if there were are any errors
351 GLenum err
= glGetError();
352 if (err
!= GL_NO_ERROR
)
353 ClearFinishedTraces(true);
356 void GPUTracer::ClearFinishedTraces(bool have_context
) {
357 while (!finished_traces_
.empty()) {
358 finished_traces_
.front()->Destroy(have_context
);
359 finished_traces_
.pop_front();
363 void GPUTracer::IssueProcessTask() {
364 if (finished_traces_
.empty() || process_posted_
)
367 process_posted_
= true;