1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/proto/graphics_frame_event_parser.h"
18
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <optional>
23
24 #include "perfetto/base/logging.h"
25 #include "perfetto/ext/base/string_view.h"
26 #include "perfetto/ext/base/string_writer.h"
27 #include "perfetto/ext/base/utils.h"
28 #include "protos/perfetto/trace/android/graphics_frame_event.pbzero.h"
29 #include "src/trace_processor/importers/common/event_tracker.h"
30 #include "src/trace_processor/importers/common/slice_tracker.h"
31 #include "src/trace_processor/importers/common/track_tracker.h"
32 #include "src/trace_processor/storage/stats.h"
33 #include "src/trace_processor/storage/trace_storage.h"
34 #include "src/trace_processor/tables/slice_tables_py.h"
35 #include "src/trace_processor/tables/track_tables_py.h"
36 #include "src/trace_processor/types/trace_processor_context.h"
37
38 namespace perfetto::trace_processor {
39
40 constexpr char kQueueLostMessage[] =
41 "Missing queue event. The slice is now a bit extended than it might "
42 "actually have been";
GraphicsFrameEventParser(TraceProcessorContext * context)43 GraphicsFrameEventParser::GraphicsFrameEventParser(
44 TraceProcessorContext* context)
45 : context_(context),
46 graphics_event_scope_id_(
47 context->storage->InternString("graphics_frame_event")),
48 unknown_event_name_id_(context->storage->InternString("unknown_event")),
49 no_layer_name_name_id_(context->storage->InternString("no_layer_name")),
50 layer_name_key_id_(context->storage->InternString("layer_name")),
51 event_type_name_ids_{
52 {context->storage->InternString(
53 "unspecified_event") /* UNSPECIFIED */,
54 context->storage->InternString("Dequeue") /* DEQUEUE */,
55 context->storage->InternString("Queue") /* QUEUE */,
56 context->storage->InternString("Post") /* POST */,
57 context->storage->InternString(
58 "AcquireFenceSignaled") /* ACQUIRE_FENCE */,
59 context->storage->InternString("Latch") /* LATCH */,
60 context->storage->InternString(
61 "HWCCompositionQueued") /* HWC_COMPOSITION_QUEUED */,
62 context->storage->InternString(
63 "FallbackComposition") /* FALLBACK_COMPOSITION */,
64 context->storage->InternString(
65 "PresentFenceSignaled") /* PRESENT_FENCE */,
66 context->storage->InternString(
67 "ReleaseFenceSignaled") /* RELEASE_FENCE */,
68 context->storage->InternString("Modify") /* MODIFY */,
69 context->storage->InternString("Detach") /* DETACH */,
70 context->storage->InternString("Attach") /* ATTACH */,
71 context->storage->InternString("Cancel") /* CANCEL */}},
72 queue_lost_message_id_(
73 context->storage->InternString(kQueueLostMessage)) {}
74
CreateBufferEvent(int64_t timestamp,GraphicsFrameEventDecoder & event)75 bool GraphicsFrameEventParser::CreateBufferEvent(
76 int64_t timestamp,
77 GraphicsFrameEventDecoder& event) {
78 if (!event.has_buffer_id()) {
79 context_->storage->IncrementStats(
80 stats::graphics_frame_event_parser_errors);
81 PERFETTO_ELOG("GraphicsFrameEvent with missing buffer id field.");
82 return false;
83 }
84
85 // Use buffer id + layer name as key because sometimes the same buffer can be
86 // used by different layers.
87 char event_key_buffer[4096];
88 base::StringWriter event_key_str(event_key_buffer,
89 base::ArraySize(event_key_buffer));
90 const uint32_t buffer_id = event.buffer_id();
91 StringId layer_name_id;
92 event_key_str.AppendUnsignedInt(buffer_id);
93
94 if (event.has_layer_name()) {
95 layer_name_id = context_->storage->InternString(event.layer_name());
96 event_key_str.AppendString(base::StringView(event.layer_name()));
97 } else {
98 layer_name_id = no_layer_name_name_id_;
99 }
100 StringId event_key =
101 context_->storage->InternString(event_key_str.GetStringView());
102
103 StringId event_name_id = unknown_event_name_id_;
104 if (event.has_type()) {
105 const auto type = static_cast<size_t>(event.type());
106 if (type < event_type_name_ids_.size()) {
107 event_name_id = event_type_name_ids_[type];
108 graphics_frame_stats_map_[event_key][type] = timestamp;
109 } else {
110 context_->storage->IncrementStats(
111 stats::graphics_frame_event_parser_errors);
112 PERFETTO_ELOG("GraphicsFrameEvent with unknown type %zu.", type);
113 }
114 } else {
115 context_->storage->IncrementStats(
116 stats::graphics_frame_event_parser_errors);
117 PERFETTO_ELOG("GraphicsFrameEvent with missing type field.");
118 }
119
120 char buffer[4096];
121 base::StringWriter track_name(buffer, base::ArraySize(buffer));
122 track_name.AppendLiteral("Buffer: ");
123 track_name.AppendUnsignedInt(buffer_id);
124 track_name.AppendLiteral(" ");
125 track_name.AppendString(base::StringView(event.layer_name()));
126
127 const StringId track_name_id =
128 context_->storage->InternString(track_name.GetStringView());
129 const int64_t duration =
130 event.has_duration_ns() ? static_cast<int64_t>(event.duration_ns()) : 0;
131 uint32_t frame_number = event.has_frame_number() ? event.frame_number() : 0;
132
133 tables::GpuTrackTable::Row track(track_name_id);
134 track.scope = graphics_event_scope_id_;
135 TrackId track_id = context_->track_tracker->LegacyInternGpuTrack(track);
136
137 auto* graphics_frame_slice_table =
138 context_->storage->mutable_graphics_frame_slice_table();
139 {
140 tables::GraphicsFrameSliceTable::Row row;
141 row.ts = timestamp;
142 row.track_id = track_id;
143 row.name = event_name_id;
144 row.dur = duration;
145 row.frame_number = frame_number;
146 row.layer_name = layer_name_id;
147 if (event.type() == GraphicsFrameEvent::PRESENT_FENCE) {
148 auto acquire_ts =
149 graphics_frame_stats_map_[event_key]
150 [GraphicsFrameEvent::ACQUIRE_FENCE];
151 auto queue_ts =
152 graphics_frame_stats_map_[event_key][GraphicsFrameEvent::QUEUE];
153 auto latch_ts =
154 graphics_frame_stats_map_[event_key][GraphicsFrameEvent::LATCH];
155
156 row.queue_to_acquire_time =
157 std::max(acquire_ts - queue_ts, static_cast<int64_t>(0));
158 row.acquire_to_latch_time = latch_ts - acquire_ts;
159 row.latch_to_present_time = timestamp - latch_ts;
160 }
161 std::optional<SliceId> opt_slice_id =
162 context_->slice_tracker->ScopedTyped(graphics_frame_slice_table, row);
163 if (event.type() == GraphicsFrameEvent::DEQUEUE) {
164 if (opt_slice_id) {
165 dequeue_slice_ids_[event_key] = *opt_slice_id;
166 }
167 } else if (event.type() == GraphicsFrameEvent::QUEUE) {
168 auto it = dequeue_slice_ids_.find(event_key);
169 if (it != dequeue_slice_ids_.end()) {
170 auto rr = graphics_frame_slice_table->FindById(it->second);
171 rr->set_frame_number(frame_number);
172 }
173 }
174 }
175 return true;
176 }
177
InvalidatePhaseEvent(int64_t timestamp,TrackId track_id,bool reset_name)178 void GraphicsFrameEventParser::InvalidatePhaseEvent(int64_t timestamp,
179 TrackId track_id,
180 bool reset_name) {
181 const auto opt_slice_id = context_->slice_tracker->End(timestamp, track_id);
182
183 if (opt_slice_id) {
184 auto* graphics_frame_slice_table =
185 context_->storage->mutable_graphics_frame_slice_table();
186 auto rr = *graphics_frame_slice_table->FindById(*opt_slice_id);
187 if (reset_name) {
188 // Set the name (frame_number) to be 0 since there is no frame number
189 // associated, example : dequeue event.
190 StringId frame_name_id = context_->storage->InternString("0");
191 rr.set_name(frame_name_id);
192 rr.set_frame_number(0);
193 }
194
195 // Set the duration to -1 so that this slice will be ignored by the
196 // UI. Setting any other duration results in wrong data which we want
197 // to avoid at all costs.
198 rr.set_dur(-1);
199 }
200 }
201
202 // Here we convert the buffer events into Phases(slices)
203 // APP: Dequeue to Queue
204 // Wait for GPU: Queue to Acquire
205 // SurfaceFlinger (SF): Latch to Present
206 // Display: Present to next Present (of the same layer)
CreatePhaseEvent(int64_t timestamp,GraphicsFrameEventDecoder & event)207 void GraphicsFrameEventParser::CreatePhaseEvent(
208 int64_t timestamp,
209 GraphicsFrameEventDecoder& event) {
210 // Use buffer id + layer name as key because sometimes the same buffer can be
211 // used by different layers.
212 char event_key_buffer[4096];
213 base::StringWriter event_key_str(event_key_buffer,
214 base::ArraySize(event_key_buffer));
215 const uint32_t buffer_id = event.buffer_id();
216 uint32_t frame_number = event.has_frame_number() ? event.frame_number() : 0;
217 event_key_str.AppendUnsignedInt(buffer_id);
218 StringId layer_name_id;
219 if (event.has_layer_name()) {
220 layer_name_id = context_->storage->InternString(event.layer_name());
221 event_key_str.AppendString(base::StringView(event.layer_name()));
222 } else {
223 layer_name_id = no_layer_name_name_id_;
224 }
225 StringId event_key =
226 context_->storage->InternString(event_key_str.GetStringView());
227
228 char track_buffer[4096];
229 char slice_buffer[4096];
230 // We'll be using the name StringWriter and name_id for writing track names
231 // and slice names.
232 base::StringWriter track_name(track_buffer, base::ArraySize(track_buffer));
233 base::StringWriter slice_name(slice_buffer, base::ArraySize(slice_buffer));
234 StringId track_name_id;
235 TrackId track_id;
236 bool start_slice = true;
237
238 // Close the previous phase before starting the new phase
239 switch (event.type()) {
240 case GraphicsFrameEvent::DEQUEUE: {
241 track_name.reset();
242 track_name.AppendLiteral("APP_");
243 track_name.AppendUnsignedInt(buffer_id);
244 track_name.AppendLiteral(" ");
245 track_name.AppendString(base::StringView(event.layer_name()));
246 track_name_id =
247 context_->storage->InternString(track_name.GetStringView());
248 tables::GpuTrackTable::Row app_track(track_name_id);
249 app_track.scope = graphics_event_scope_id_;
250 track_id = context_->track_tracker->LegacyInternGpuTrack(app_track);
251
252 // Error handling
253 auto dequeue_time = dequeue_map_.find(event_key);
254 if (dequeue_time != dequeue_map_.end()) {
255 InvalidatePhaseEvent(timestamp, dequeue_time->second, true);
256 dequeue_map_.erase(dequeue_time);
257 }
258 auto queue_time = queue_map_.find(event_key);
259 if (queue_time != queue_map_.end()) {
260 InvalidatePhaseEvent(timestamp, queue_time->second);
261 queue_map_.erase(queue_time);
262 }
263
264 dequeue_map_[event_key] = track_id;
265 last_dequeued_[event_key] = timestamp;
266 break;
267 }
268
269 case GraphicsFrameEvent::QUEUE: {
270 auto dequeue_time = dequeue_map_.find(event_key);
271 if (dequeue_time != dequeue_map_.end()) {
272 const auto opt_slice_id =
273 context_->slice_tracker->End(timestamp, dequeue_time->second);
274 slice_name.reset();
275 slice_name.AppendUnsignedInt(frame_number);
276 if (opt_slice_id) {
277 auto* graphics_frame_slice_table =
278 context_->storage->mutable_graphics_frame_slice_table();
279 // Set the name of the slice to be the frame number since dequeue did
280 // not have a frame number at that time.
281 auto rr = *graphics_frame_slice_table->FindById(*opt_slice_id);
282 rr.set_name(
283 context_->storage->InternString(slice_name.GetStringView()));
284 rr.set_frame_number(frame_number);
285 dequeue_map_.erase(dequeue_time);
286 }
287 }
288 // The AcquireFence might be signaled before receiving a QUEUE event
289 // sometimes. In that case, we shouldn't start a slice.
290 if (last_acquired_[event_key] > last_dequeued_[event_key] &&
291 last_acquired_[event_key] < timestamp) {
292 start_slice = false;
293 break;
294 }
295 track_name.reset();
296 track_name.AppendLiteral("GPU_");
297 track_name.AppendUnsignedInt(buffer_id);
298 track_name.AppendLiteral(" ");
299 track_name.AppendString(base::StringView(event.layer_name()));
300 track_name_id =
301 context_->storage->InternString(track_name.GetStringView());
302 tables::GpuTrackTable::Row gpu_track(track_name_id);
303 gpu_track.scope = graphics_event_scope_id_;
304 track_id = context_->track_tracker->LegacyInternGpuTrack(gpu_track);
305 queue_map_[event_key] = track_id;
306 break;
307 }
308 case GraphicsFrameEvent::ACQUIRE_FENCE: {
309 auto queue_time = queue_map_.find(event_key);
310 if (queue_time != queue_map_.end()) {
311 context_->slice_tracker->End(timestamp, queue_time->second);
312 queue_map_.erase(queue_time);
313 }
314 last_acquired_[event_key] = timestamp;
315 start_slice = false;
316 break;
317 }
318 case GraphicsFrameEvent::LATCH: {
319 // b/157578286 - Sometimes Queue event goes missing. To prevent having a
320 // wrong slice info, we try to close any existing APP slice.
321 auto dequeue_time = dequeue_map_.find(event_key);
322 if (dequeue_time != dequeue_map_.end()) {
323 InvalidatePhaseEvent(timestamp, dequeue_time->second, true);
324 dequeue_map_.erase(dequeue_time);
325 }
326 track_name.reset();
327 track_name.AppendLiteral("SF_");
328 track_name.AppendUnsignedInt(buffer_id);
329 track_name.AppendLiteral(" ");
330 track_name.AppendString(base::StringView(event.layer_name()));
331 track_name_id =
332 context_->storage->InternString(track_name.GetStringView());
333 tables::GpuTrackTable::Row sf_track(track_name_id);
334 sf_track.scope = graphics_event_scope_id_;
335 track_id = context_->track_tracker->LegacyInternGpuTrack(sf_track);
336 latch_map_[event_key] = track_id;
337 break;
338 }
339
340 case GraphicsFrameEvent::PRESENT_FENCE: {
341 auto latch_time = latch_map_.find(event_key);
342 if (latch_time != latch_map_.end()) {
343 context_->slice_tracker->End(timestamp, latch_time->second);
344 latch_map_.erase(latch_time);
345 }
346 auto display_time = display_map_.find(layer_name_id);
347 if (display_time != display_map_.end()) {
348 context_->slice_tracker->End(timestamp, display_time->second);
349 display_map_.erase(display_time);
350 }
351 base::StringView layerName(event.layer_name());
352 track_name.reset();
353 track_name.AppendLiteral("Display_");
354 track_name.AppendString(layerName.substr(0, 10));
355 track_name_id =
356 context_->storage->InternString(track_name.GetStringView());
357 tables::GpuTrackTable::Row display_track(track_name_id);
358 display_track.scope = graphics_event_scope_id_;
359 track_id = context_->track_tracker->LegacyInternGpuTrack(display_track);
360 display_map_[layer_name_id] = track_id;
361 break;
362 }
363
364 default:
365 start_slice = false;
366 }
367
368 // Start the new phase if needed.
369 if (start_slice) {
370 tables::GraphicsFrameSliceTable::Row slice;
371 slice.ts = timestamp;
372 slice.track_id = track_id;
373 slice.layer_name = layer_name_id;
374 slice_name.reset();
375 // If the frame_number is known, set it as the name of the slice.
376 // If not known (DEQUEUE), set the name as the timestamp.
377 // Timestamp is chosen here because the stack_id is hashed based on the name
378 // of the slice. To not have any conflicting stack_id with any of the
379 // existing slices, we use timestamp as the temporary name.
380 if (frame_number != 0) {
381 slice_name.AppendUnsignedInt(frame_number);
382 } else {
383 slice_name.AppendInt(timestamp);
384 }
385 slice.name = context_->storage->InternString(slice_name.GetStringView());
386 slice.frame_number = frame_number;
387 context_->slice_tracker->BeginTyped(
388 context_->storage->mutable_graphics_frame_slice_table(), slice);
389 }
390 }
391
ParseGraphicsFrameEvent(int64_t timestamp,ConstBytes blob)392 void GraphicsFrameEventParser::ParseGraphicsFrameEvent(int64_t timestamp,
393 ConstBytes blob) {
394 protos::pbzero::GraphicsFrameEvent::Decoder frame_event(blob);
395 if (!frame_event.has_buffer_event()) {
396 return;
397 }
398
399 protos::pbzero::GraphicsFrameEvent::BufferEvent::Decoder event(
400 frame_event.buffer_event());
401 if (CreateBufferEvent(timestamp, event)) {
402 // Create a phase event only if the buffer event finishes successfully
403 CreatePhaseEvent(timestamp, event);
404 }
405 }
406
407 } // namespace perfetto::trace_processor
408