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_timer_
= gpu_timing_client
->CreateGPUTimer();
98 GPUTrace::~GPUTrace() {
101 void GPUTrace::Start(bool trace_service
) {
103 outputter_
->TraceServiceBegin(category_
, name_
);
105 if (gpu_timer_
.get()) {
110 void GPUTrace::End(bool tracing_service
) {
111 if (gpu_timer_
.get()) {
114 if (tracing_service
) {
115 outputter_
->TraceServiceEnd(category_
, name_
);
119 bool GPUTrace::IsAvailable() {
120 return !gpu_timer_
.get() || gpu_timer_
->IsAvailable();
123 void GPUTrace::Process() {
124 if (gpu_timer_
.get()) {
125 DCHECK(IsAvailable());
129 gpu_timer_
->GetStartEndTimestamps(&start
, &end
);
130 outputter_
->TraceDevice(category_
, name_
, start
, end
);
134 GPUTracer::GPUTracer(gles2::GLES2Decoder
* decoder
)
135 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
136 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
137 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
138 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
140 gpu_executing_(false),
141 process_posted_(false) {
143 gfx::GLContext
* context
= decoder_
->GetGLContext();
145 gpu_timing_client_
= context
->CreateGPUTimingClient();
147 gpu_timing_client_
= new gfx::GPUTimingClient();
151 GPUTracer::~GPUTracer() {
154 bool GPUTracer::BeginDecoding() {
159 outputter_
= CreateOutputter(gpu_timing_client_
->GetTimerTypeName());
162 if (*gpu_trace_dev_category
== '\0') {
163 // If GPU device category is off, invalidate timing sync.
164 gpu_timing_client_
->InvalidateTimerOffset();
167 gpu_executing_
= true;
169 gpu_timing_client_
->CheckAndResetTimerErrors();
170 // Begin a Trace for all active markers
171 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
172 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
173 TraceMarker
& trace_marker
= markers_
[n
][i
];
174 trace_marker
.trace_
=
175 new GPUTrace(outputter_
, gpu_timing_client_
.get(),
176 trace_marker
.category_
, trace_marker
.name_
,
177 *gpu_trace_dev_category
!= 0);
178 trace_marker
.trace_
->Start(*gpu_trace_srv_category
!= 0);
185 bool GPUTracer::EndDecoding() {
189 // End Trace for all active markers
191 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
192 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
193 TraceMarker
& marker
= markers_
[n
][i
];
194 if (marker
.trace_
.get()) {
195 marker
.trace_
->End(*gpu_trace_srv_category
!= 0);
196 if (marker
.trace_
->IsEnabled())
197 traces_
.push_back(marker
.trace_
);
199 markers_
[n
][i
].trace_
= 0;
206 gpu_executing_
= false;
208 // NOTE(vmiura): glFlush() here can help give better trace results,
209 // but it distorts the normal device behavior.
213 bool GPUTracer::Begin(const std::string
& category
, const std::string
& name
,
214 GpuTracerSource source
) {
218 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
220 // Push new marker from given 'source'
221 markers_
[source
].push_back(TraceMarker(category
, name
));
225 scoped_refptr
<GPUTrace
> trace
= new GPUTrace(
226 outputter_
, gpu_timing_client_
.get(), category
, name
,
227 *gpu_trace_dev_category
!= 0);
228 trace
->Start(*gpu_trace_srv_category
!= 0);
229 markers_
[source
].back().trace_
= trace
;
235 bool GPUTracer::End(GpuTracerSource source
) {
239 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
241 // Pop last marker with matching 'source'
242 if (!markers_
[source
].empty()) {
244 scoped_refptr
<GPUTrace
> trace
= markers_
[source
].back().trace_
;
246 trace
->End(*gpu_trace_srv_category
!= 0);
247 if (trace
->IsEnabled())
248 traces_
.push_back(trace
);
253 markers_
[source
].pop_back();
259 bool GPUTracer::IsTracing() {
260 return (*gpu_trace_srv_category
!= 0) || (*gpu_trace_dev_category
!= 0);
263 const std::string
& GPUTracer::CurrentCategory(GpuTracerSource source
) const {
265 source
< NUM_TRACER_SOURCES
&&
266 !markers_
[source
].empty()) {
267 return markers_
[source
].back().category_
;
269 return base::EmptyString();
272 const std::string
& GPUTracer::CurrentName(GpuTracerSource source
) const {
274 source
< NUM_TRACER_SOURCES
&&
275 !markers_
[source
].empty()) {
276 return markers_
[source
].back().name_
;
278 return base::EmptyString();
281 scoped_refptr
<Outputter
> GPUTracer::CreateOutputter(const std::string
& name
) {
282 return TraceOutputter::Create(name
);
285 void GPUTracer::PostTask() {
286 base::MessageLoop::current()->PostDelayedTask(
288 base::Bind(&GPUTracer::Process
, base::AsWeakPtr(this)),
289 base::TimeDelta::FromMilliseconds(kProcessInterval
));
292 void GPUTracer::Process() {
293 process_posted_
= false;
298 void GPUTracer::ProcessTraces() {
299 if (!gpu_timing_client_
->IsAvailable()) {
304 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces");
306 // Make owning decoder's GL context current
307 if (!decoder_
->MakeCurrent()) {
308 // Skip subsequent GL calls if MakeCurrent fails
313 // Check if timers are still valid (e.g: a disjoint operation
314 // might have occurred.)
315 if (gpu_timing_client_
->CheckAndResetTimerErrors())
318 while (!traces_
.empty() && traces_
.front()->IsAvailable()) {
319 traces_
.front()->Process();
323 // Clear pending traces if there were are any errors
324 GLenum err
= glGetError();
325 if (err
!= GL_NO_ERROR
)
329 void GPUTracer::IssueProcessTask() {
330 if (traces_
.empty() || process_posted_
)
333 process_posted_
= true;