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/location.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/string_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "base/trace_event/trace_event.h"
16 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
17 #include "gpu/command_buffer/service/context_group.h"
18 #include "ui/gl/gl_bindings.h"
19 #include "ui/gl/gl_version_info.h"
20 #include "ui/gl/gpu_timing.h"
25 static const unsigned int kProcessInterval
= 16;
26 static const char* kGpuTraceSourceNames
[] = {
27 "GroupMarker", // kTraceGroupMarker = 0,
28 "TraceCHROMIUM", // kTraceCHROMIUM = 1,
29 "TraceCmd", // kTraceDecoder = 2,
31 static_assert(NUM_TRACER_SOURCES
== arraysize(kGpuTraceSourceNames
),
32 "Trace source names must match enumeration.");
34 static TraceOutputter
* g_outputter_thread
= NULL
;
36 TraceMarker::TraceMarker(const std::string
& category
, const std::string
& name
)
37 : category_(category
),
42 TraceMarker::~TraceMarker() {
45 scoped_refptr
<TraceOutputter
> TraceOutputter::Create(const std::string
& name
) {
46 if (!g_outputter_thread
) {
47 g_outputter_thread
= new TraceOutputter(name
);
49 return g_outputter_thread
;
52 TraceOutputter::TraceOutputter(const std::string
& name
)
53 : named_thread_(name
.c_str()) {
54 named_thread_
.Start();
58 TraceOutputter::~TraceOutputter() { g_outputter_thread
= NULL
; }
60 void TraceOutputter::TraceDevice(GpuTracerSource source
,
61 const std::string
& category
,
62 const std::string
& name
,
65 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
66 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2(
67 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
69 local_trace_device_id_
,
70 named_thread_
.thread_id(),
75 kGpuTraceSourceNames
[source
]);
76 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2(
77 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
79 local_trace_device_id_
,
80 named_thread_
.thread_id(),
85 kGpuTraceSourceNames
[source
]);
86 ++local_trace_device_id_
;
89 void TraceOutputter::TraceServiceBegin(GpuTracerSource source
,
90 const std::string
& category
,
91 const std::string
& name
) {
92 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
93 TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(
94 TRACE_DISABLED_BY_DEFAULT("gpu.service"),
95 name
.c_str(), local_trace_service_id_
,
96 "gl_category", category
.c_str(),
97 "channel", kGpuTraceSourceNames
[source
]);
99 trace_service_id_stack_
[source
].push(local_trace_service_id_
);
100 ++local_trace_service_id_
;
103 void TraceOutputter::TraceServiceEnd(GpuTracerSource source
,
104 const std::string
& category
,
105 const std::string
& name
) {
106 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
107 DCHECK(!trace_service_id_stack_
[source
].empty());
108 const uint64 local_trace_id
= trace_service_id_stack_
[source
].top();
109 trace_service_id_stack_
[source
].pop();
111 TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(
112 TRACE_DISABLED_BY_DEFAULT("gpu.service"),
113 name
.c_str(), local_trace_id
,
114 "gl_category", category
.c_str(),
115 "channel", kGpuTraceSourceNames
[source
]);
118 GPUTrace::GPUTrace(scoped_refptr
<Outputter
> outputter
,
119 gfx::GPUTimingClient
* gpu_timing_client
,
120 const GpuTracerSource source
,
121 const std::string
& category
,
122 const std::string
& name
,
123 const bool tracing_service
,
124 const bool tracing_device
)
128 outputter_(outputter
),
129 service_enabled_(tracing_service
),
130 device_enabled_(tracing_device
) {
131 if (tracing_device
&&
132 gpu_timing_client
->IsAvailable() &&
133 gpu_timing_client
->IsTimerOffsetAvailable()) {
134 gpu_timer_
= gpu_timing_client
->CreateGPUTimer();
138 GPUTrace::~GPUTrace() {
141 void GPUTrace::Destroy(bool have_context
) {
142 if (gpu_timer_
.get()) {
143 gpu_timer_
->Destroy(have_context
);
147 void GPUTrace::Start() {
148 if (service_enabled_
) {
149 outputter_
->TraceServiceBegin(source_
, category_
, name_
);
151 if (gpu_timer_
.get()) {
156 void GPUTrace::End() {
157 if (gpu_timer_
.get()) {
160 if (service_enabled_
) {
161 outputter_
->TraceServiceEnd(source_
, category_
, name_
);
165 bool GPUTrace::IsAvailable() {
166 return !gpu_timer_
.get() || gpu_timer_
->IsAvailable();
169 void GPUTrace::Process() {
170 if (gpu_timer_
.get()) {
171 DCHECK(IsAvailable());
175 gpu_timer_
->GetStartEndTimestamps(&start
, &end
);
176 outputter_
->TraceDevice(source_
, category_
, name_
, start
, end
);
180 GPUTracer::GPUTracer(gles2::GLES2Decoder
* decoder
)
181 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
182 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
183 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
184 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
186 gpu_executing_(false),
187 process_posted_(false) {
189 gfx::GLContext
* context
= decoder_
->GetGLContext();
191 gpu_timing_client_
= context
->CreateGPUTimingClient();
193 gpu_timing_client_
= new gfx::GPUTimingClient();
197 GPUTracer::~GPUTracer() {
200 void GPUTracer::Destroy(bool have_context
) {
201 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
202 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
203 TraceMarker
& marker
= markers_
[n
][i
];
204 if (marker
.trace_
.get()) {
205 marker
.trace_
->Destroy(have_context
);
211 ClearFinishedTraces(have_context
);
214 bool GPUTracer::BeginDecoding() {
219 outputter_
= CreateOutputter(gpu_timing_client_
->GetTimerTypeName());
222 if (*gpu_trace_dev_category
== '\0') {
223 // If GPU device category is off, invalidate timing sync.
224 gpu_timing_client_
->InvalidateTimerOffset();
227 gpu_executing_
= true;
229 gpu_timing_client_
->CheckAndResetTimerErrors();
230 // Begin a Trace for all active markers
231 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
232 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
233 TraceMarker
& trace_marker
= markers_
[n
][i
];
234 trace_marker
.trace_
=
235 new GPUTrace(outputter_
, gpu_timing_client_
.get(),
236 static_cast<GpuTracerSource
>(n
),
237 trace_marker
.category_
, trace_marker
.name_
,
238 *gpu_trace_srv_category
!= 0,
239 *gpu_trace_dev_category
!= 0);
240 trace_marker
.trace_
->Start();
247 bool GPUTracer::EndDecoding() {
251 // End Trace for all active markers
253 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
254 if (!markers_
[n
].empty()) {
255 for (int i
= static_cast<int>(markers_
[n
].size()) - 1; i
>= 0; --i
) {
256 TraceMarker
& marker
= markers_
[n
][i
];
257 if (marker
.trace_
.get()) {
258 marker
.trace_
->End();
260 finished_traces_
.push_back(marker
.trace_
);
269 gpu_executing_
= false;
271 // NOTE(vmiura): glFlush() here can help give better trace results,
272 // but it distorts the normal device behavior.
276 bool GPUTracer::Begin(const std::string
& category
, const std::string
& name
,
277 GpuTracerSource source
) {
281 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
283 // Push new marker from given 'source'
284 markers_
[source
].push_back(TraceMarker(category
, name
));
288 scoped_refptr
<GPUTrace
> trace
= new GPUTrace(
289 outputter_
, gpu_timing_client_
.get(), source
, category
, name
,
290 *gpu_trace_srv_category
!= 0,
291 *gpu_trace_dev_category
!= 0);
293 markers_
[source
].back().trace_
= trace
;
299 bool GPUTracer::End(GpuTracerSource source
) {
303 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
305 // Pop last marker with matching 'source'
306 if (!markers_
[source
].empty()) {
307 scoped_refptr
<GPUTrace
> trace
= markers_
[source
].back().trace_
;
313 finished_traces_
.push_back(trace
);
317 markers_
[source
].pop_back();
323 bool GPUTracer::IsTracing() {
324 return (*gpu_trace_srv_category
!= 0) || (*gpu_trace_dev_category
!= 0);
327 const std::string
& GPUTracer::CurrentCategory(GpuTracerSource source
) const {
329 source
< NUM_TRACER_SOURCES
&&
330 !markers_
[source
].empty()) {
331 return markers_
[source
].back().category_
;
333 return base::EmptyString();
336 const std::string
& GPUTracer::CurrentName(GpuTracerSource source
) const {
338 source
< NUM_TRACER_SOURCES
&&
339 !markers_
[source
].empty()) {
340 return markers_
[source
].back().name_
;
342 return base::EmptyString();
345 scoped_refptr
<Outputter
> GPUTracer::CreateOutputter(const std::string
& name
) {
346 return TraceOutputter::Create(name
);
349 void GPUTracer::PostTask() {
350 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
351 FROM_HERE
, base::Bind(&GPUTracer::Process
, base::AsWeakPtr(this)),
352 base::TimeDelta::FromMilliseconds(kProcessInterval
));
355 void GPUTracer::Process() {
356 process_posted_
= false;
361 void GPUTracer::ProcessTraces() {
362 if (!gpu_timing_client_
->IsAvailable()) {
363 ClearFinishedTraces(false);
367 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces");
369 // Make owning decoder's GL context current
370 if (!decoder_
->MakeCurrent()) {
371 // Skip subsequent GL calls if MakeCurrent fails
372 ClearFinishedTraces(false);
376 // Check if timers are still valid (e.g: a disjoint operation
377 // might have occurred.)
378 if (gpu_timing_client_
->CheckAndResetTimerErrors()) {
379 ClearFinishedTraces(true);
382 while (!finished_traces_
.empty()) {
383 scoped_refptr
<GPUTrace
>& trace
= finished_traces_
.front();
384 if (trace
->IsDeviceTraceEnabled()) {
385 if (!finished_traces_
.front()->IsAvailable())
387 finished_traces_
.front()->Process();
389 finished_traces_
.front()->Destroy(true);
390 finished_traces_
.pop_front();
393 // Clear pending traces if there were are any errors
394 GLenum err
= glGetError();
395 if (err
!= GL_NO_ERROR
)
396 ClearFinishedTraces(true);
399 void GPUTracer::ClearFinishedTraces(bool have_context
) {
400 while (!finished_traces_
.empty()) {
401 finished_traces_
.front()->Destroy(have_context
);
402 finished_traces_
.pop_front();
406 void GPUTracer::IssueProcessTask() {
407 if (finished_traces_
.empty() || process_posted_
)
410 process_posted_
= true;