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/frame_timeline_event_parser.h"
18
19 #include <cinttypes>
20
21 #include "perfetto/ext/base/utils.h"
22 #include "perfetto/protozero/field.h"
23 #include "src/trace_processor/importers/common/args_tracker.h"
24 #include "src/trace_processor/importers/common/event_tracker.h"
25 #include "src/trace_processor/importers/common/flow_tracker.h"
26 #include "src/trace_processor/importers/common/process_tracker.h"
27 #include "src/trace_processor/importers/common/slice_tracker.h"
28 #include "src/trace_processor/importers/common/track_tracker.h"
29 #include "src/trace_processor/types/trace_processor_context.h"
30
31 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
32
33 namespace perfetto {
34 namespace trace_processor {
35 namespace {
36
IsBadTimestamp(int64_t ts)37 bool IsBadTimestamp(int64_t ts) {
38 // Very small or very large timestamps are likely a mistake.
39 // See b/185978397
40 constexpr int64_t kBadTimestamp =
41 std::numeric_limits<int64_t>::max() - (10LL * 1000 * 1000 * 1000);
42 return std::abs(ts) >= kBadTimestamp;
43 }
44
45 } // namespace
46
47 using ExpectedDisplayFrameStartDecoder =
48 protos::pbzero::FrameTimelineEvent_ExpectedDisplayFrameStart_Decoder;
49 using ActualDisplayFrameStartDecoder =
50 protos::pbzero::FrameTimelineEvent_ActualDisplayFrameStart_Decoder;
51
52 using ExpectedSurfaceFrameStartDecoder =
53 protos::pbzero::FrameTimelineEvent_ExpectedSurfaceFrameStart_Decoder;
54 using ActualSurfaceFrameStartDecoder =
55 protos::pbzero::FrameTimelineEvent_ActualSurfaceFrameStart_Decoder;
56
57 using FrameEndDecoder = protos::pbzero::FrameTimelineEvent_FrameEnd_Decoder;
58
JankTypeBitmaskToStringId(TraceProcessorContext * context,int32_t jank_type)59 static StringId JankTypeBitmaskToStringId(TraceProcessorContext* context,
60 int32_t jank_type) {
61 if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED)
62 return context->storage->InternString("Unspecified");
63 if (jank_type == FrameTimelineEvent::JANK_NONE)
64 return context->storage->InternString("None");
65
66 std::vector<std::string> jank_reasons;
67 if (jank_type & FrameTimelineEvent::JANK_SF_SCHEDULING)
68 jank_reasons.emplace_back("SurfaceFlinger Scheduling");
69 if (jank_type & FrameTimelineEvent::JANK_PREDICTION_ERROR)
70 jank_reasons.emplace_back("Prediction Error");
71 if (jank_type & FrameTimelineEvent::JANK_DISPLAY_HAL)
72 jank_reasons.emplace_back("Display HAL");
73 if (jank_type & FrameTimelineEvent::JANK_SF_CPU_DEADLINE_MISSED)
74 jank_reasons.emplace_back("SurfaceFlinger CPU Deadline Missed");
75 if (jank_type & FrameTimelineEvent::JANK_SF_GPU_DEADLINE_MISSED)
76 jank_reasons.emplace_back("SurfaceFlinger GPU Deadline Missed");
77 if (jank_type & FrameTimelineEvent::JANK_APP_DEADLINE_MISSED)
78 jank_reasons.emplace_back("App Deadline Missed");
79 if (jank_type & FrameTimelineEvent::JANK_BUFFER_STUFFING)
80 jank_reasons.emplace_back("Buffer Stuffing");
81 if (jank_type & FrameTimelineEvent::JANK_UNKNOWN)
82 jank_reasons.emplace_back("Unknown Jank");
83 if (jank_type & FrameTimelineEvent::JANK_SF_STUFFING)
84 jank_reasons.emplace_back("SurfaceFlinger Stuffing");
85 if (jank_type & FrameTimelineEvent::JANK_DROPPED)
86 jank_reasons.emplace_back("Dropped Frame");
87
88 std::string jank_str(
89 std::accumulate(jank_reasons.begin(), jank_reasons.end(), std::string(),
90 [](const std::string& l, const std::string& r) {
91 return l.empty() ? r : l + ", " + r;
92 }));
93 return context->storage->InternString(base::StringView(jank_str));
94 }
95
DisplayFrameJanky(int32_t jank_type)96 static bool DisplayFrameJanky(int32_t jank_type) {
97 if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED ||
98 jank_type == FrameTimelineEvent::JANK_NONE)
99 return false;
100
101 int32_t display_frame_jank_bitmask =
102 FrameTimelineEvent::JANK_SF_SCHEDULING |
103 FrameTimelineEvent::JANK_PREDICTION_ERROR |
104 FrameTimelineEvent::JANK_DISPLAY_HAL |
105 FrameTimelineEvent::JANK_SF_CPU_DEADLINE_MISSED |
106 FrameTimelineEvent::JANK_SF_GPU_DEADLINE_MISSED;
107 if (jank_type & display_frame_jank_bitmask)
108 return true;
109 return false;
110 }
111
SurfaceFrameJanky(int32_t jank_type)112 static bool SurfaceFrameJanky(int32_t jank_type) {
113 if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED ||
114 jank_type == FrameTimelineEvent::JANK_NONE)
115 return false;
116
117 int32_t surface_frame_jank_bitmask =
118 FrameTimelineEvent::JANK_APP_DEADLINE_MISSED |
119 FrameTimelineEvent::JANK_UNKNOWN;
120 if (jank_type & surface_frame_jank_bitmask)
121 return true;
122 return false;
123 }
124
ValidatePredictionType(TraceProcessorContext * context,int32_t prediction_type)125 static bool ValidatePredictionType(TraceProcessorContext* context,
126 int32_t prediction_type) {
127 if (prediction_type >= FrameTimelineEvent::PREDICTION_VALID /*1*/ &&
128 prediction_type <= FrameTimelineEvent::PREDICTION_UNKNOWN /*3*/)
129 return true;
130 context->storage->IncrementStats(stats::frame_timeline_event_parser_errors);
131 return false;
132 }
133
ValidatePresentType(TraceProcessorContext * context,int32_t present_type)134 static bool ValidatePresentType(TraceProcessorContext* context,
135 int32_t present_type) {
136 if (present_type >= FrameTimelineEvent::PRESENT_ON_TIME /*1*/ &&
137 present_type <= FrameTimelineEvent::PRESENT_UNKNOWN /*5*/)
138 return true;
139 context->storage->IncrementStats(stats::frame_timeline_event_parser_errors);
140 return false;
141 }
142
FrameTimelineEventParser(TraceProcessorContext * context)143 FrameTimelineEventParser::FrameTimelineEventParser(
144 TraceProcessorContext* context)
145 : context_(context),
146 present_type_ids_{
147 {context->storage->InternString(
148 "Unspecified Present") /* PRESENT_UNSPECIFIED */,
149 context->storage->InternString(
150 "On-time Present") /* PRESENT_ON_TIME */,
151 context->storage->InternString("Late Present") /* PRESENT_LATE */,
152 context->storage->InternString("Early Present") /* PRESENT_EARLY */,
153 context->storage->InternString(
154 "Dropped Frame") /* PRESENT_DROPPED */,
155 context->storage->InternString(
156 "Unknown Present") /* PRESENT_UNKNOWN */}},
157 prediction_type_ids_{
158 {context->storage->InternString(
159 "Unspecified Prediction") /* PREDICTION_UNSPECIFIED */,
160 context->storage->InternString(
161 "Valid Prediction") /* PREDICTION_VALID */,
162 context->storage->InternString(
163 "Expired Prediction") /* PREDICTION_EXPIRED */,
164 context->storage->InternString(
165 "Unknown Prediction") /* PREDICTION_UNKNOWN */}},
166 jank_severity_type_ids_{{context->storage->InternString("Unknown"),
167 context->storage->InternString("None"),
168 context->storage->InternString("Partial"),
169 context->storage->InternString("Full")}},
170 expected_timeline_track_name_(
171 context->storage->InternString("Expected Timeline")),
172 actual_timeline_track_name_(
173 context->storage->InternString("Actual Timeline")),
174 surface_frame_token_id_(
175 context->storage->InternString("Surface frame token")),
176 display_frame_token_id_(
177 context->storage->InternString("Display frame token")),
178 present_type_id_(context->storage->InternString("Present type")),
179 on_time_finish_id_(context->storage->InternString("On time finish")),
180 gpu_composition_id_(context->storage->InternString("GPU composition")),
181 jank_type_id_(context->storage->InternString("Jank type")),
182 jank_severity_type_id_(
183 context->storage->InternString("Jank severity type")),
184 layer_name_id_(context->storage->InternString("Layer name")),
185 prediction_type_id_(context->storage->InternString("Prediction type")),
186 is_buffer_id_(context->storage->InternString("Is Buffer?")),
187 jank_tag_none_id_(context->storage->InternString("No Jank")),
188 jank_tag_self_id_(context->storage->InternString("Self Jank")),
189 jank_tag_other_id_(context->storage->InternString("Other Jank")),
190 jank_tag_dropped_id_(context->storage->InternString("Dropped Frame")),
191 jank_tag_buffer_stuffing_id_(
192 context->storage->InternString("Buffer Stuffing")),
193 jank_tag_sf_stuffing_id_(
194 context->storage->InternString("SurfaceFlinger Stuffing")) {}
195
ParseExpectedDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)196 void FrameTimelineEventParser::ParseExpectedDisplayFrameStart(
197 int64_t timestamp,
198 ConstBytes bufferBlob) {
199 ExpectedDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
200 if (!event.has_cookie()) {
201 context_->storage->IncrementStats(
202 stats::frame_timeline_event_parser_errors);
203 return;
204 }
205
206 if (!event.has_token()) {
207 context_->storage->IncrementStats(
208 stats::frame_timeline_event_parser_errors);
209 return;
210 }
211
212 if (!event.has_pid()) {
213 context_->storage->IncrementStats(
214 stats::frame_timeline_event_parser_errors);
215 return;
216 }
217
218 int64_t cookie = event.cookie();
219 int64_t token = event.token();
220 StringId name_id =
221 context_->storage->InternString(base::StringView(std::to_string(token)));
222
223 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
224 static_cast<uint32_t>(event.pid()));
225 auto expected_track_set_id =
226 context_->async_track_set_tracker->InternProcessTrackSet(
227 upid, expected_timeline_track_name_);
228 cookie_track_set_id_map_[cookie] = expected_track_set_id;
229
230 tables::ExpectedFrameTimelineSliceTable::Row expected_row;
231 expected_row.ts = timestamp;
232 expected_row.track_id =
233 context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
234 expected_row.name = name_id;
235
236 expected_row.display_frame_token = token;
237 expected_row.upid = upid;
238
239 context_->slice_tracker->BeginTyped(
240 context_->storage->mutable_expected_frame_timeline_slice_table(),
241 expected_row, [this, token](ArgsTracker::BoundInserter* inserter) {
242 inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
243 });
244 }
245
ParseActualDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)246 void FrameTimelineEventParser::ParseActualDisplayFrameStart(
247 int64_t timestamp,
248 ConstBytes bufferBlob) {
249 ActualDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
250 if (!event.has_cookie()) {
251 context_->storage->IncrementStats(
252 stats::frame_timeline_event_parser_errors);
253 return;
254 }
255
256 if (!event.has_token()) {
257 context_->storage->IncrementStats(
258 stats::frame_timeline_event_parser_errors);
259 return;
260 }
261 if (!event.has_pid()) {
262 context_->storage->IncrementStats(
263 stats::frame_timeline_event_parser_errors);
264 return;
265 }
266
267 int64_t cookie = event.cookie();
268 int64_t token = event.token();
269 StringId name_id =
270 context_->storage->InternString(base::StringView(std::to_string(token)));
271
272 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
273 static_cast<uint32_t>(event.pid()));
274 auto actual_track_set_id =
275 context_->async_track_set_tracker->InternProcessTrackSet(
276 upid, actual_timeline_track_name_);
277 cookie_track_set_id_map_[cookie] = actual_track_set_id;
278
279 tables::ActualFrameTimelineSliceTable::Row actual_row;
280 actual_row.ts = timestamp;
281 actual_row.track_id =
282 context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
283 actual_row.name = name_id;
284 actual_row.display_frame_token = token;
285 actual_row.upid = upid;
286 actual_row.on_time_finish = event.on_time_finish();
287 actual_row.gpu_composition = event.gpu_composition();
288
289 // parse present type
290 StringId present_type = present_type_ids_[0];
291 if (event.has_present_type() &&
292 ValidatePresentType(context_, event.present_type())) {
293 present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
294 }
295 actual_row.present_type = present_type;
296
297 // parse jank type
298 StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
299 actual_row.jank_type = jank_type;
300
301 // parse jank severity type
302 if (event.has_jank_severity_type()) {
303 actual_row.jank_severity_type = jank_severity_type_ids_[static_cast<size_t>(
304 event.jank_severity_type())];
305 } else {
306 // NOTE: Older traces don't have this field. If JANK_NONE use
307 // |severity_type| "None", and is not present, use "Unknown".
308 actual_row.jank_severity_type =
309 (event.jank_type() == FrameTimelineEvent::JANK_NONE)
310 ? jank_severity_type_ids_[1] /* None */
311 : jank_severity_type_ids_[0]; /* Unknown */
312 }
313 StringId jank_severity_type = actual_row.jank_severity_type;
314
315 // parse prediction type
316 StringId prediction_type = prediction_type_ids_[0];
317 if (event.has_prediction_type() &&
318 ValidatePredictionType(context_, event.prediction_type())) {
319 prediction_type =
320 prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
321 }
322 actual_row.prediction_type = prediction_type;
323
324 if (DisplayFrameJanky(event.jank_type())) {
325 actual_row.jank_tag = jank_tag_self_id_;
326 } else if (event.jank_type() == FrameTimelineEvent::JANK_SF_STUFFING) {
327 actual_row.jank_tag = jank_tag_sf_stuffing_id_;
328 } else if (event.jank_type() == FrameTimelineEvent::JANK_DROPPED) {
329 actual_row.jank_tag = jank_tag_dropped_id_;
330 } else {
331 actual_row.jank_tag = jank_tag_none_id_;
332 }
333
334 std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
335 context_->storage->mutable_actual_frame_timeline_slice_table(),
336 actual_row,
337 [this, token, jank_type, jank_severity_type, present_type,
338 prediction_type, &event](ArgsTracker::BoundInserter* inserter) {
339 inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
340 inserter->AddArg(present_type_id_, Variadic::String(present_type));
341 inserter->AddArg(on_time_finish_id_,
342 Variadic::Integer(event.on_time_finish()));
343 inserter->AddArg(gpu_composition_id_,
344 Variadic::Integer(event.gpu_composition()));
345 inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
346 inserter->AddArg(jank_severity_type_id_,
347 Variadic::String(jank_severity_type));
348 inserter->AddArg(prediction_type_id_,
349 Variadic::String(prediction_type));
350 });
351
352 // SurfaceFrames will always be parsed before the matching DisplayFrame
353 // (since the app works on the frame before SurfaceFlinger does). Because
354 // of this it's safe to add all the flow events here and then forget the
355 // surface_slice id - we shouldn't see more surfaces_slices that should be
356 // connected to this slice after this point.
357 auto range = display_token_to_surface_slice_.equal_range(token);
358 if (opt_slice_id) {
359 for (auto it = range.first; it != range.second; ++it) {
360 SliceId surface_slice = it->second; // App
361 SliceId display_slice = *opt_slice_id; // SurfaceFlinger
362 context_->flow_tracker->InsertFlow(surface_slice, display_slice);
363 }
364 }
365 display_token_to_surface_slice_.erase(range.first, range.second);
366 }
367
ParseExpectedSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)368 void FrameTimelineEventParser::ParseExpectedSurfaceFrameStart(
369 int64_t timestamp,
370 ConstBytes bufferBlob) {
371 ExpectedSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
372
373 if (!event.has_cookie()) {
374 context_->storage->IncrementStats(
375 stats::frame_timeline_event_parser_errors);
376 return;
377 }
378
379 if (!event.has_token()) {
380 context_->storage->IncrementStats(
381 stats::frame_timeline_event_parser_errors);
382 return;
383 }
384
385 if (!event.has_display_frame_token()) {
386 context_->storage->IncrementStats(
387 stats::frame_timeline_event_parser_errors);
388 return;
389 }
390
391 if (!event.has_pid()) {
392 context_->storage->IncrementStats(
393 stats::frame_timeline_event_parser_errors);
394 return;
395 }
396
397 int64_t cookie = event.cookie();
398 int64_t token = event.token();
399 int64_t display_frame_token = event.display_frame_token();
400 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
401 static_cast<uint32_t>(event.pid()));
402 auto token_set_it = expected_timeline_token_map_.find(upid);
403 if (token_set_it != expected_timeline_token_map_.end()) {
404 auto& token_set = token_set_it->second;
405 if (token_set.find(token) != token_set.end()) {
406 // If we already have an expected timeline for a token, the expectations
407 // are same for all frames that use the token. No need to add duplicate
408 // entries.
409 return;
410 }
411 }
412 // This is the first time we are seeing this token for this process. Add to
413 // the map.
414 expected_timeline_token_map_[upid].insert(token);
415
416 StringId layer_name_id = event.has_layer_name()
417 ? context_->storage->InternString(
418 base::StringView(event.layer_name()))
419 : kNullStringId;
420 StringId name_id =
421 context_->storage->InternString(base::StringView(std::to_string(token)));
422
423 auto expected_track_set_id =
424 context_->async_track_set_tracker->InternProcessTrackSet(
425 upid, expected_timeline_track_name_);
426 cookie_track_set_id_map_[cookie] = expected_track_set_id;
427
428 tables::ExpectedFrameTimelineSliceTable::Row expected_row;
429 expected_row.ts = timestamp;
430 expected_row.track_id =
431 context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
432 expected_row.name = name_id;
433
434 expected_row.surface_frame_token = token;
435 expected_row.display_frame_token = display_frame_token;
436 expected_row.upid = upid;
437 expected_row.layer_name = layer_name_id;
438 context_->slice_tracker->BeginTyped(
439 context_->storage->mutable_expected_frame_timeline_slice_table(),
440 expected_row,
441 [this, token, layer_name_id](ArgsTracker::BoundInserter* inserter) {
442 inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
443 inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
444 });
445 }
446
ParseActualSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)447 void FrameTimelineEventParser::ParseActualSurfaceFrameStart(
448 int64_t timestamp,
449 ConstBytes bufferBlob) {
450 ActualSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
451
452 if (!event.has_cookie()) {
453 context_->storage->IncrementStats(
454 stats::frame_timeline_event_parser_errors);
455 return;
456 }
457
458 if (!event.has_token()) {
459 context_->storage->IncrementStats(
460 stats::frame_timeline_event_parser_errors);
461 return;
462 }
463
464 if (!event.has_display_frame_token()) {
465 context_->storage->IncrementStats(
466 stats::frame_timeline_event_parser_errors);
467 return;
468 }
469
470 if (!event.has_pid()) {
471 context_->storage->IncrementStats(
472 stats::frame_timeline_event_parser_errors);
473 return;
474 }
475
476 int64_t cookie = event.cookie();
477 int64_t token = event.token();
478 int64_t display_frame_token = event.display_frame_token();
479
480 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
481 static_cast<uint32_t>(event.pid()));
482 StringId layer_name_id;
483 if (event.has_layer_name())
484 layer_name_id =
485 context_->storage->InternString(base::StringView(event.layer_name()));
486 StringId name_id =
487 context_->storage->InternString(base::StringView(std::to_string(token)));
488
489 auto actual_track_set_id =
490 context_->async_track_set_tracker->InternProcessTrackSet(
491 upid, actual_timeline_track_name_);
492 cookie_track_set_id_map_[cookie] = actual_track_set_id;
493
494 tables::ActualFrameTimelineSliceTable::Row actual_row;
495 actual_row.ts = timestamp;
496 actual_row.track_id =
497 context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
498 actual_row.name = name_id;
499 actual_row.surface_frame_token = token;
500 actual_row.display_frame_token = display_frame_token;
501 actual_row.upid = upid;
502 actual_row.layer_name = layer_name_id;
503 actual_row.on_time_finish = event.on_time_finish();
504 actual_row.gpu_composition = event.gpu_composition();
505
506 // parse present type
507 StringId present_type = present_type_ids_[0];
508 bool present_type_validated = false;
509 if (event.has_present_type() &&
510 ValidatePresentType(context_, event.present_type())) {
511 present_type_validated = true;
512 present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
513 }
514 actual_row.present_type = present_type;
515
516 // parse jank type
517 StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
518 actual_row.jank_type = jank_type;
519
520 // parse jank severity type
521 if (event.has_jank_severity_type()) {
522 actual_row.jank_severity_type = jank_severity_type_ids_[static_cast<size_t>(
523 event.jank_severity_type())];
524 } else {
525 // NOTE: Older traces don't have this field. If JANK_NONE use
526 // |severity_type| "None", and is not present, use "Unknown".
527 actual_row.jank_severity_type =
528 (event.jank_type() == FrameTimelineEvent::JANK_NONE)
529 ? jank_severity_type_ids_[1] /* None */
530 : jank_severity_type_ids_[0]; /* Unknown */
531 }
532 StringId jank_severity_type = actual_row.jank_severity_type;
533
534 // parse prediction type
535 StringId prediction_type = prediction_type_ids_[0];
536 if (event.has_prediction_type() &&
537 ValidatePredictionType(context_, event.prediction_type())) {
538 prediction_type =
539 prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
540 }
541 actual_row.prediction_type = prediction_type;
542
543 if (SurfaceFrameJanky(event.jank_type())) {
544 actual_row.jank_tag = jank_tag_self_id_;
545 } else if (DisplayFrameJanky(event.jank_type())) {
546 actual_row.jank_tag = jank_tag_other_id_;
547 } else if (event.jank_type() == FrameTimelineEvent::JANK_BUFFER_STUFFING) {
548 actual_row.jank_tag = jank_tag_buffer_stuffing_id_;
549 } else if (present_type_validated &&
550 event.present_type() == FrameTimelineEvent::PRESENT_DROPPED) {
551 actual_row.jank_tag = jank_tag_dropped_id_;
552 } else {
553 actual_row.jank_tag = jank_tag_none_id_;
554 }
555 StringId is_buffer = context_->storage->InternString("Unspecified");
556 if (event.has_is_buffer()) {
557 if (event.is_buffer())
558 is_buffer = context_->storage->InternString("Yes");
559 else
560 is_buffer = context_->storage->InternString("No");
561 }
562
563 std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
564 context_->storage->mutable_actual_frame_timeline_slice_table(),
565 actual_row,
566 [this, jank_type, jank_severity_type, present_type, token, layer_name_id,
567 display_frame_token, prediction_type, is_buffer,
568 &event](ArgsTracker::BoundInserter* inserter) {
569 inserter->AddArg(surface_frame_token_id_, Variadic::Integer(token));
570 inserter->AddArg(display_frame_token_id_,
571 Variadic::Integer(display_frame_token));
572 inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
573 inserter->AddArg(present_type_id_, Variadic::String(present_type));
574 inserter->AddArg(on_time_finish_id_,
575 Variadic::Integer(event.on_time_finish()));
576 inserter->AddArg(gpu_composition_id_,
577 Variadic::Integer(event.gpu_composition()));
578 inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
579 inserter->AddArg(jank_severity_type_id_,
580 Variadic::String(jank_severity_type));
581 inserter->AddArg(prediction_type_id_,
582 Variadic::String(prediction_type));
583 inserter->AddArg(is_buffer_id_, Variadic::String(is_buffer));
584 });
585
586 if (opt_slice_id) {
587 display_token_to_surface_slice_.emplace(display_frame_token, *opt_slice_id);
588 }
589 }
590
ParseFrameEnd(int64_t timestamp,ConstBytes bufferBlob)591 void FrameTimelineEventParser::ParseFrameEnd(int64_t timestamp,
592 ConstBytes bufferBlob) {
593 FrameEndDecoder event(bufferBlob.data, bufferBlob.size);
594
595 if (!event.has_cookie()) {
596 context_->storage->IncrementStats(
597 stats::frame_timeline_event_parser_errors);
598 return;
599 }
600
601 int64_t cookie = event.cookie();
602 auto it = cookie_track_set_id_map_.find(cookie);
603 if (it == cookie_track_set_id_map_.end()) {
604 context_->storage->IncrementStats(stats::frame_timeline_unpaired_end_event);
605 return;
606 }
607 auto track_set_id = it->second;
608 auto track_id = context_->async_track_set_tracker->End(track_set_id, cookie);
609 context_->slice_tracker->End(timestamp, track_id);
610 cookie_track_set_id_map_.erase(it);
611 }
612
ParseFrameTimelineEvent(int64_t timestamp,ConstBytes blob)613 void FrameTimelineEventParser::ParseFrameTimelineEvent(int64_t timestamp,
614 ConstBytes blob) {
615 protos::pbzero::FrameTimelineEvent_Decoder frame_event(blob.data, blob.size);
616
617 // Due to platform bugs, negative timestamps can creep into into traces.
618 // Ensure that it doesn't make it into the tables.
619 // TODO(mayzner): remove the negative check once we have some logic handling
620 // this at the sorter level.
621 if (timestamp < 0 || IsBadTimestamp(timestamp)) {
622 context_->storage->IncrementStats(
623 stats::frame_timeline_event_parser_errors);
624 return;
625 }
626
627 if (frame_event.has_expected_display_frame_start()) {
628 ParseExpectedDisplayFrameStart(timestamp,
629 frame_event.expected_display_frame_start());
630 } else if (frame_event.has_actual_display_frame_start()) {
631 ParseActualDisplayFrameStart(timestamp,
632 frame_event.actual_display_frame_start());
633 } else if (frame_event.has_expected_surface_frame_start()) {
634 ParseExpectedSurfaceFrameStart(timestamp,
635 frame_event.expected_surface_frame_start());
636 } else if (frame_event.has_actual_surface_frame_start()) {
637 ParseActualSurfaceFrameStart(timestamp,
638 frame_event.actual_surface_frame_start());
639 } else if (frame_event.has_frame_end()) {
640 ParseFrameEnd(timestamp, frame_event.frame_end());
641 } else {
642 context_->storage->IncrementStats(
643 stats::frame_timeline_event_parser_errors);
644 }
645 }
646 } // namespace trace_processor
647 } // namespace perfetto
648