xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/frame_timeline_event_parser.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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