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;
273 bool GPUTracer::Begin(const std::string
& category
, const std::string
& name
,
274 GpuTracerSource source
) {
278 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
280 // Push new marker from given 'source'
281 markers_
[source
].push_back(TraceMarker(category
, name
));
285 scoped_refptr
<GPUTrace
> trace
= new GPUTrace(
286 outputter_
, gpu_timing_client_
.get(), source
, category
, name
,
287 *gpu_trace_srv_category
!= 0,
288 *gpu_trace_dev_category
!= 0);
290 markers_
[source
].back().trace_
= trace
;
296 bool GPUTracer::End(GpuTracerSource source
) {
300 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
302 // Pop last marker with matching 'source'
303 if (!markers_
[source
].empty()) {
304 scoped_refptr
<GPUTrace
> trace
= markers_
[source
].back().trace_
;
310 finished_traces_
.push_back(trace
);
314 markers_
[source
].pop_back();
320 bool GPUTracer::IsTracing() {
321 return (*gpu_trace_srv_category
!= 0) || (*gpu_trace_dev_category
!= 0);
324 const std::string
& GPUTracer::CurrentCategory(GpuTracerSource source
) const {
326 source
< NUM_TRACER_SOURCES
&&
327 !markers_
[source
].empty()) {
328 return markers_
[source
].back().category_
;
330 return base::EmptyString();
333 const std::string
& GPUTracer::CurrentName(GpuTracerSource source
) const {
335 source
< NUM_TRACER_SOURCES
&&
336 !markers_
[source
].empty()) {
337 return markers_
[source
].back().name_
;
339 return base::EmptyString();
342 scoped_refptr
<Outputter
> GPUTracer::CreateOutputter(const std::string
& name
) {
343 return TraceOutputter::Create(name
);
346 void GPUTracer::PostTask() {
347 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
348 FROM_HERE
, base::Bind(&GPUTracer::Process
, base::AsWeakPtr(this)),
349 base::TimeDelta::FromMilliseconds(kProcessInterval
));
352 void GPUTracer::Process() {
353 process_posted_
= false;
358 void GPUTracer::ProcessTraces() {
359 if (!gpu_timing_client_
->IsAvailable()) {
360 ClearFinishedTraces(false);
364 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces");
366 // Make owning decoder's GL context current
367 if (!decoder_
->MakeCurrent()) {
368 // Skip subsequent GL calls if MakeCurrent fails
369 ClearFinishedTraces(false);
373 // Check if timers are still valid (e.g: a disjoint operation
374 // might have occurred.)
375 if (gpu_timing_client_
->CheckAndResetTimerErrors()) {
376 ClearFinishedTraces(true);
379 while (!finished_traces_
.empty()) {
380 scoped_refptr
<GPUTrace
>& trace
= finished_traces_
.front();
381 if (trace
->IsDeviceTraceEnabled()) {
382 if (!finished_traces_
.front()->IsAvailable())
384 finished_traces_
.front()->Process();
386 finished_traces_
.front()->Destroy(true);
387 finished_traces_
.pop_front();
390 // Clear pending traces if there were are any errors
391 GLenum err
= glGetError();
392 if (err
!= GL_NO_ERROR
)
393 ClearFinishedTraces(true);
396 void GPUTracer::ClearFinishedTraces(bool have_context
) {
397 while (!finished_traces_
.empty()) {
398 finished_traces_
.front()->Destroy(have_context
);
399 finished_traces_
.pop_front();
403 void GPUTracer::IssueProcessTask() {
404 if (finished_traces_
.empty() || process_posted_
)
407 process_posted_
= true;