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/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.h"
16 #include "base/trace_event/trace_event.h"
17 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
18 #include "gpu/command_buffer/service/context_group.h"
19 #include "ui/gl/gl_bindings.h"
20 #include "ui/gl/gl_context.h"
21 #include "ui/gl/gl_version_info.h"
22 #include "ui/gl/gpu_timing.h"
27 static const char* kGpuTraceSourceNames
[] = {
28 "TraceCHROMIUM", // kTraceCHROMIUM,
29 "TraceCmd", // kTraceDecoder,
30 "Disjoint", // kTraceDisjoint, // Used internally.
32 static_assert(NUM_TRACER_SOURCES
== arraysize(kGpuTraceSourceNames
),
33 "Trace source names must match enumeration.");
35 static TraceOutputter
* g_outputter_thread
= NULL
;
37 TraceMarker::TraceMarker(const std::string
& category
, const std::string
& name
)
38 : category_(category
),
43 TraceMarker::~TraceMarker() {
46 scoped_refptr
<TraceOutputter
> TraceOutputter::Create(const std::string
& name
) {
47 if (!g_outputter_thread
) {
48 g_outputter_thread
= new TraceOutputter(name
);
50 return g_outputter_thread
;
53 TraceOutputter::TraceOutputter(const std::string
& name
)
54 : named_thread_(name
.c_str()) {
55 named_thread_
.Start();
59 TraceOutputter::~TraceOutputter() { g_outputter_thread
= NULL
; }
61 void TraceOutputter::TraceDevice(GpuTracerSource source
,
62 const std::string
& category
,
63 const std::string
& name
,
66 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
67 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2(
68 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
70 local_trace_device_id_
,
71 named_thread_
.GetThreadId(),
76 kGpuTraceSourceNames
[source
]);
78 // Time stamps are inclusive, since the traces are durations we subtract
79 // 1 microsecond from the end time to make the trace markers show up cleaner.
80 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2(
81 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
83 local_trace_device_id_
,
84 named_thread_
.GetThreadId(),
89 kGpuTraceSourceNames
[source
]);
90 ++local_trace_device_id_
;
93 void TraceOutputter::TraceServiceBegin(GpuTracerSource source
,
94 const std::string
& category
,
95 const std::string
& name
) {
96 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
97 TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(
98 TRACE_DISABLED_BY_DEFAULT("gpu.service"),
99 name
.c_str(), local_trace_service_id_
,
100 "gl_category", category
.c_str(),
101 "channel", kGpuTraceSourceNames
[source
]);
103 trace_service_id_stack_
[source
].push(local_trace_service_id_
);
104 ++local_trace_service_id_
;
107 void TraceOutputter::TraceServiceEnd(GpuTracerSource source
,
108 const std::string
& category
,
109 const std::string
& name
) {
110 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
111 DCHECK(!trace_service_id_stack_
[source
].empty());
112 const uint64 local_trace_id
= trace_service_id_stack_
[source
].top();
113 trace_service_id_stack_
[source
].pop();
115 TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(
116 TRACE_DISABLED_BY_DEFAULT("gpu.service"),
117 name
.c_str(), local_trace_id
,
118 "gl_category", category
.c_str(),
119 "channel", kGpuTraceSourceNames
[source
]);
122 GPUTrace::GPUTrace(scoped_refptr
<Outputter
> outputter
,
123 gfx::GPUTimingClient
* gpu_timing_client
,
124 const GpuTracerSource source
,
125 const std::string
& category
,
126 const std::string
& name
,
127 const bool tracing_service
,
128 const bool tracing_device
)
132 outputter_(outputter
),
133 service_enabled_(tracing_service
),
134 device_enabled_(tracing_device
) {
135 if (tracing_device
&& gpu_timing_client
->IsAvailable())
136 gpu_timer_
= gpu_timing_client
->CreateGPUTimer(false);
139 GPUTrace::~GPUTrace() {
142 void GPUTrace::Destroy(bool have_context
) {
143 if (gpu_timer_
.get()) {
144 gpu_timer_
->Destroy(have_context
);
148 void GPUTrace::Start() {
149 if (service_enabled_
) {
150 outputter_
->TraceServiceBegin(source_
, category_
, name_
);
152 if (gpu_timer_
.get()) {
157 void GPUTrace::End() {
158 if (gpu_timer_
.get()) {
161 if (service_enabled_
) {
162 outputter_
->TraceServiceEnd(source_
, category_
, name_
);
166 bool GPUTrace::IsAvailable() {
167 return !gpu_timer_
.get() || gpu_timer_
->IsAvailable();
170 void GPUTrace::Process() {
171 if (gpu_timer_
.get() && device_enabled_
) {
172 DCHECK(IsAvailable());
176 gpu_timer_
->GetStartEndTimestamps(&start
, &end
);
177 outputter_
->TraceDevice(source_
, category_
, name_
, start
, end
);
181 GPUTracer::GPUTracer(gles2::GLES2Decoder
* decoder
)
182 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
183 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
184 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
185 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
188 gfx::GLContext
* context
= decoder_
->GetGLContext();
190 gpu_timing_client_
= context
->CreateGPUTimingClient();
192 gpu_timing_client_
= new gfx::GPUTimingClient();
195 disjoint_time_
= gpu_timing_client_
->GetCurrentCPUTime();
198 GPUTracer::~GPUTracer() {
201 void GPUTracer::Destroy(bool have_context
) {
202 ClearOngoingTraces(have_context
);
205 bool GPUTracer::BeginDecoding() {
210 outputter_
= CreateOutputter(gpu_timing_client_
->GetTimerTypeName());
213 gpu_executing_
= true;
215 CheckDisjointStatus();
216 // Begin a Trace for all active markers
217 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
218 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
219 began_device_traces_
|= (*gpu_trace_dev_category
!= 0);
220 TraceMarker
& trace_marker
= markers_
[n
][i
];
221 trace_marker
.trace_
=
222 new GPUTrace(outputter_
, gpu_timing_client_
.get(),
223 static_cast<GpuTracerSource
>(n
),
224 trace_marker
.category_
, trace_marker
.name_
,
225 *gpu_trace_srv_category
!= 0,
226 *gpu_trace_dev_category
!= 0);
227 trace_marker
.trace_
->Start();
234 bool GPUTracer::EndDecoding() {
238 // End Trace for all active markers
240 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
241 if (!markers_
[n
].empty()) {
242 for (int i
= static_cast<int>(markers_
[n
].size()) - 1; i
>= 0; --i
) {
243 TraceMarker
& marker
= markers_
[n
][i
];
244 if (marker
.trace_
.get()) {
245 marker
.trace_
->End();
247 finished_traces_
.push_back(marker
.trace_
);
255 gpu_executing_
= false;
259 bool GPUTracer::Begin(const std::string
& category
, const std::string
& name
,
260 GpuTracerSource source
) {
264 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
266 // Push new marker from given 'source'
267 markers_
[source
].push_back(TraceMarker(category
, name
));
271 began_device_traces_
|= (*gpu_trace_dev_category
!= 0);
272 scoped_refptr
<GPUTrace
> trace
= new GPUTrace(
273 outputter_
, gpu_timing_client_
.get(), source
, category
, name
,
274 *gpu_trace_srv_category
!= 0,
275 *gpu_trace_dev_category
!= 0);
277 markers_
[source
].back().trace_
= trace
;
283 bool GPUTracer::End(GpuTracerSource source
) {
287 DCHECK(source
>= 0 && source
< NUM_TRACER_SOURCES
);
289 // Pop last marker with matching 'source'
290 if (!markers_
[source
].empty()) {
291 scoped_refptr
<GPUTrace
> trace
= markers_
[source
].back().trace_
;
297 finished_traces_
.push_back(trace
);
300 markers_
[source
].pop_back();
306 bool GPUTracer::HasTracesToProcess() {
307 return !finished_traces_
.empty();
310 void GPUTracer::ProcessTraces() {
311 if (!gpu_timing_client_
->IsAvailable()) {
312 while (!finished_traces_
.empty()) {
313 finished_traces_
.front()->Destroy(false);
314 finished_traces_
.pop_front();
319 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces");
321 // Make owning decoder's GL context current
322 if (!decoder_
->MakeCurrent()) {
323 // Skip subsequent GL calls if MakeCurrent fails
324 ClearOngoingTraces(false);
328 // Check available traces.
329 int available_traces
= 0;
330 for (scoped_refptr
<GPUTrace
>& trace
: finished_traces_
) {
331 if (trace
->IsDeviceTraceEnabled() && !trace
->IsAvailable()) {
337 // Clear pending traces if there were are any errors including disjoint.
338 if (CheckDisjointStatus()) {
339 ClearOngoingTraces(true);
341 for (int i
= 0; i
< available_traces
; ++i
) {
342 scoped_refptr
<GPUTrace
>& trace
= finished_traces_
.front();
344 trace
->Destroy(true);
345 finished_traces_
.pop_front();
349 DCHECK(GL_NO_ERROR
== glGetError());
352 bool GPUTracer::IsTracing() {
353 return (*gpu_trace_srv_category
!= 0) || (*gpu_trace_dev_category
!= 0);
356 const std::string
& GPUTracer::CurrentCategory(GpuTracerSource source
) const {
358 source
< NUM_TRACER_SOURCES
&&
359 !markers_
[source
].empty()) {
360 return markers_
[source
].back().category_
;
362 return base::EmptyString();
365 const std::string
& GPUTracer::CurrentName(GpuTracerSource source
) const {
367 source
< NUM_TRACER_SOURCES
&&
368 !markers_
[source
].empty()) {
369 return markers_
[source
].back().name_
;
371 return base::EmptyString();
374 scoped_refptr
<Outputter
> GPUTracer::CreateOutputter(const std::string
& name
) {
375 return TraceOutputter::Create(name
);
378 bool GPUTracer::CheckDisjointStatus() {
379 const int64 current_time
= gpu_timing_client_
->GetCurrentCPUTime();
380 if (*gpu_trace_dev_category
== 0)
383 bool status
= gpu_timing_client_
->CheckAndResetTimerErrors();
384 if (status
&& began_device_traces_
) {
385 // Log disjoint event if we have active traces.
386 const std::string unique_disjoint_name
=
387 base::StringPrintf("DisjointEvent-%p", this);
388 outputter_
->TraceDevice(kTraceDisjoint
,
390 unique_disjoint_name
,
394 disjoint_time_
= current_time
;
398 void GPUTracer::ClearOngoingTraces(bool have_context
) {
399 for (int n
= 0; n
< NUM_TRACER_SOURCES
; n
++) {
400 for (size_t i
= 0; i
< markers_
[n
].size(); i
++) {
401 TraceMarker
& marker
= markers_
[n
][i
];
402 if (marker
.trace_
.get()) {
403 marker
.trace_
->Destroy(have_context
);
409 while (!finished_traces_
.empty()) {
410 finished_traces_
.front()->Destroy(have_context
);
411 finished_traces_
.pop_front();