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 expected_timeline_track_name_(
167 context->storage->InternString("Expected Timeline")),
168 actual_timeline_track_name_(
169 context->storage->InternString("Actual Timeline")),
170 surface_frame_token_id_(
171 context->storage->InternString("Surface frame token")),
172 display_frame_token_id_(
173 context->storage->InternString("Display frame token")),
174 present_type_id_(context->storage->InternString("Present type")),
175 on_time_finish_id_(context->storage->InternString("On time finish")),
176 gpu_composition_id_(context->storage->InternString("GPU composition")),
177 jank_type_id_(context->storage->InternString("Jank type")),
178 layer_name_id_(context->storage->InternString("Layer name")),
179 prediction_type_id_(context->storage->InternString("Prediction type")),
180 is_buffer_id_(context->storage->InternString("Is Buffer?")),
181 jank_tag_none_id_(context->storage->InternString("No Jank")),
182 jank_tag_self_id_(context->storage->InternString("Self Jank")),
183 jank_tag_other_id_(context->storage->InternString("Other Jank")),
184 jank_tag_dropped_id_(context->storage->InternString("Dropped Frame")),
185 jank_tag_buffer_stuffing_id_(
186 context->storage->InternString("Buffer Stuffing")),
187 jank_tag_sf_stuffing_id_(
188 context->storage->InternString("SurfaceFlinger Stuffing")) {}
189
ParseExpectedDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)190 void FrameTimelineEventParser::ParseExpectedDisplayFrameStart(
191 int64_t timestamp,
192 ConstBytes bufferBlob) {
193 ExpectedDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
194 if (!event.has_cookie()) {
195 context_->storage->IncrementStats(
196 stats::frame_timeline_event_parser_errors);
197 return;
198 }
199
200 if (!event.has_token()) {
201 context_->storage->IncrementStats(
202 stats::frame_timeline_event_parser_errors);
203 return;
204 }
205
206 if (!event.has_pid()) {
207 context_->storage->IncrementStats(
208 stats::frame_timeline_event_parser_errors);
209 return;
210 }
211
212 int64_t cookie = event.cookie();
213 int64_t token = event.token();
214 StringId name_id =
215 context_->storage->InternString(base::StringView(std::to_string(token)));
216
217 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
218 static_cast<uint32_t>(event.pid()));
219 auto expected_track_set_id =
220 context_->async_track_set_tracker->InternProcessTrackSet(
221 upid, expected_timeline_track_name_);
222 cookie_track_set_id_map_[cookie] = expected_track_set_id;
223
224 tables::ExpectedFrameTimelineSliceTable::Row expected_row;
225 expected_row.ts = timestamp;
226 expected_row.track_id =
227 context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
228 expected_row.name = name_id;
229
230 expected_row.display_frame_token = token;
231 expected_row.upid = upid;
232
233 context_->slice_tracker->BeginTyped(
234 context_->storage->mutable_expected_frame_timeline_slice_table(),
235 expected_row, [this, token](ArgsTracker::BoundInserter* inserter) {
236 inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
237 });
238 }
239
ParseActualDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)240 void FrameTimelineEventParser::ParseActualDisplayFrameStart(
241 int64_t timestamp,
242 ConstBytes bufferBlob) {
243 ActualDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
244 if (!event.has_cookie()) {
245 context_->storage->IncrementStats(
246 stats::frame_timeline_event_parser_errors);
247 return;
248 }
249
250 if (!event.has_token()) {
251 context_->storage->IncrementStats(
252 stats::frame_timeline_event_parser_errors);
253 return;
254 }
255 if (!event.has_pid()) {
256 context_->storage->IncrementStats(
257 stats::frame_timeline_event_parser_errors);
258 return;
259 }
260
261 int64_t cookie = event.cookie();
262 int64_t token = event.token();
263 StringId name_id =
264 context_->storage->InternString(base::StringView(std::to_string(token)));
265
266 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
267 static_cast<uint32_t>(event.pid()));
268 auto actual_track_set_id =
269 context_->async_track_set_tracker->InternProcessTrackSet(
270 upid, actual_timeline_track_name_);
271 cookie_track_set_id_map_[cookie] = actual_track_set_id;
272
273 tables::ActualFrameTimelineSliceTable::Row actual_row;
274 actual_row.ts = timestamp;
275 actual_row.track_id =
276 context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
277 actual_row.name = name_id;
278 actual_row.display_frame_token = token;
279 actual_row.upid = upid;
280 StringId present_type = present_type_ids_[0];
281 if (event.has_present_type() &&
282 ValidatePresentType(context_, event.present_type())) {
283 present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
284 }
285 actual_row.present_type = present_type;
286 actual_row.on_time_finish = event.on_time_finish();
287 actual_row.gpu_composition = event.gpu_composition();
288 StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
289 actual_row.jank_type = jank_type;
290 StringId prediction_type = prediction_type_ids_[0];
291 if (event.has_prediction_type() &&
292 ValidatePredictionType(context_, event.prediction_type())) {
293 prediction_type =
294 prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
295 }
296 actual_row.prediction_type = prediction_type;
297 if (DisplayFrameJanky(event.jank_type())) {
298 actual_row.jank_tag = jank_tag_self_id_;
299 } else if (event.jank_type() == FrameTimelineEvent::JANK_SF_STUFFING) {
300 actual_row.jank_tag = jank_tag_sf_stuffing_id_;
301 } else {
302 actual_row.jank_tag = jank_tag_none_id_;
303 }
304
305 std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
306 context_->storage->mutable_actual_frame_timeline_slice_table(),
307 actual_row,
308 [this, token, jank_type, present_type, prediction_type,
309 &event](ArgsTracker::BoundInserter* inserter) {
310 inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
311 inserter->AddArg(present_type_id_, Variadic::String(present_type));
312 inserter->AddArg(on_time_finish_id_,
313 Variadic::Integer(event.on_time_finish()));
314 inserter->AddArg(gpu_composition_id_,
315 Variadic::Integer(event.gpu_composition()));
316 inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
317 inserter->AddArg(prediction_type_id_,
318 Variadic::String(prediction_type));
319 });
320
321 // SurfaceFrames will always be parsed before the matching DisplayFrame
322 // (since the app works on the frame before SurfaceFlinger does). Because
323 // of this it's safe to add all the flow events here and then forget the
324 // surface_slice id - we shouldn't see more surfaces_slices that should be
325 // connected to this slice after this point.
326 auto range = display_token_to_surface_slice_.equal_range(token);
327 if (opt_slice_id) {
328 for (auto it = range.first; it != range.second; ++it) {
329 SliceId display_slice = *opt_slice_id; // SurfaceFlinger
330 SliceId surface_slice = it->second; // App
331 context_->flow_tracker->InsertFlow(display_slice, surface_slice);
332 }
333 }
334 display_token_to_surface_slice_.erase(range.first, range.second);
335 }
336
ParseExpectedSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)337 void FrameTimelineEventParser::ParseExpectedSurfaceFrameStart(
338 int64_t timestamp,
339 ConstBytes bufferBlob) {
340 ExpectedSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
341
342 if (!event.has_cookie()) {
343 context_->storage->IncrementStats(
344 stats::frame_timeline_event_parser_errors);
345 return;
346 }
347
348 if (!event.has_token()) {
349 context_->storage->IncrementStats(
350 stats::frame_timeline_event_parser_errors);
351 return;
352 }
353
354 if (!event.has_display_frame_token()) {
355 context_->storage->IncrementStats(
356 stats::frame_timeline_event_parser_errors);
357 return;
358 }
359
360 if (!event.has_pid()) {
361 context_->storage->IncrementStats(
362 stats::frame_timeline_event_parser_errors);
363 return;
364 }
365
366 int64_t cookie = event.cookie();
367 int64_t token = event.token();
368 int64_t display_frame_token = event.display_frame_token();
369 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
370 static_cast<uint32_t>(event.pid()));
371 auto token_set_it = expected_timeline_token_map_.find(upid);
372 if (token_set_it != expected_timeline_token_map_.end()) {
373 auto& token_set = token_set_it->second;
374 if (token_set.find(token) != token_set.end()) {
375 // If we already have an expected timeline for a token, the expectations
376 // are same for all frames that use the token. No need to add duplicate
377 // entries.
378 return;
379 }
380 }
381 // This is the first time we are seeing this token for this process. Add to
382 // the map.
383 expected_timeline_token_map_[upid].insert(token);
384
385 StringId layer_name_id = event.has_layer_name()
386 ? context_->storage->InternString(
387 base::StringView(event.layer_name()))
388 : kNullStringId;
389 StringId name_id =
390 context_->storage->InternString(base::StringView(std::to_string(token)));
391
392 auto expected_track_set_id =
393 context_->async_track_set_tracker->InternProcessTrackSet(
394 upid, expected_timeline_track_name_);
395 cookie_track_set_id_map_[cookie] = expected_track_set_id;
396
397 tables::ExpectedFrameTimelineSliceTable::Row expected_row;
398 expected_row.ts = timestamp;
399 expected_row.track_id =
400 context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
401 expected_row.name = name_id;
402
403 expected_row.surface_frame_token = token;
404 expected_row.display_frame_token = display_frame_token;
405 expected_row.upid = upid;
406 expected_row.layer_name = layer_name_id;
407 context_->slice_tracker->BeginTyped(
408 context_->storage->mutable_expected_frame_timeline_slice_table(),
409 expected_row,
410 [this, token, layer_name_id](ArgsTracker::BoundInserter* inserter) {
411 inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
412 inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
413 });
414 }
415
ParseActualSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)416 void FrameTimelineEventParser::ParseActualSurfaceFrameStart(
417 int64_t timestamp,
418 ConstBytes bufferBlob) {
419 ActualSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
420
421 if (!event.has_cookie()) {
422 context_->storage->IncrementStats(
423 stats::frame_timeline_event_parser_errors);
424 return;
425 }
426
427 if (!event.has_token()) {
428 context_->storage->IncrementStats(
429 stats::frame_timeline_event_parser_errors);
430 return;
431 }
432
433 if (!event.has_display_frame_token()) {
434 context_->storage->IncrementStats(
435 stats::frame_timeline_event_parser_errors);
436 return;
437 }
438
439 if (!event.has_pid()) {
440 context_->storage->IncrementStats(
441 stats::frame_timeline_event_parser_errors);
442 return;
443 }
444
445 int64_t cookie = event.cookie();
446 int64_t token = event.token();
447 int64_t display_frame_token = event.display_frame_token();
448
449 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
450 static_cast<uint32_t>(event.pid()));
451 StringId layer_name_id;
452 if (event.has_layer_name())
453 layer_name_id =
454 context_->storage->InternString(base::StringView(event.layer_name()));
455 StringId name_id =
456 context_->storage->InternString(base::StringView(std::to_string(token)));
457
458 auto actual_track_set_id =
459 context_->async_track_set_tracker->InternProcessTrackSet(
460 upid, actual_timeline_track_name_);
461 cookie_track_set_id_map_[cookie] = actual_track_set_id;
462
463 tables::ActualFrameTimelineSliceTable::Row actual_row;
464 actual_row.ts = timestamp;
465 actual_row.track_id =
466 context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
467 actual_row.name = name_id;
468 actual_row.surface_frame_token = token;
469 actual_row.display_frame_token = display_frame_token;
470 actual_row.upid = upid;
471 actual_row.layer_name = layer_name_id;
472 StringId present_type = present_type_ids_[0];
473 bool present_type_validated = false;
474 if (event.has_present_type() &&
475 ValidatePresentType(context_, event.present_type())) {
476 present_type_validated = true;
477 present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
478 }
479 actual_row.present_type = present_type;
480 actual_row.on_time_finish = event.on_time_finish();
481 actual_row.gpu_composition = event.gpu_composition();
482 StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
483 actual_row.jank_type = jank_type;
484 StringId prediction_type = prediction_type_ids_[0];
485 if (event.has_prediction_type() &&
486 ValidatePredictionType(context_, event.prediction_type())) {
487 prediction_type =
488 prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
489 }
490 actual_row.prediction_type = prediction_type;
491 if (SurfaceFrameJanky(event.jank_type())) {
492 actual_row.jank_tag = jank_tag_self_id_;
493 } else if (DisplayFrameJanky(event.jank_type())) {
494 actual_row.jank_tag = jank_tag_other_id_;
495 } else if (event.jank_type() == FrameTimelineEvent::JANK_BUFFER_STUFFING) {
496 actual_row.jank_tag = jank_tag_buffer_stuffing_id_;
497 } else if (present_type_validated &&
498 event.present_type() == FrameTimelineEvent::PRESENT_DROPPED) {
499 actual_row.jank_tag = jank_tag_dropped_id_;
500 } else {
501 actual_row.jank_tag = jank_tag_none_id_;
502 }
503 StringId is_buffer = context_->storage->InternString("Unspecified");
504 if (event.has_is_buffer()) {
505 if (event.is_buffer())
506 is_buffer = context_->storage->InternString("Yes");
507 else
508 is_buffer = context_->storage->InternString("No");
509 }
510
511 std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
512 context_->storage->mutable_actual_frame_timeline_slice_table(),
513 actual_row,
514 [this, jank_type, present_type, token, layer_name_id, display_frame_token,
515 prediction_type, is_buffer,
516 &event](ArgsTracker::BoundInserter* inserter) {
517 inserter->AddArg(surface_frame_token_id_, Variadic::Integer(token));
518 inserter->AddArg(display_frame_token_id_,
519 Variadic::Integer(display_frame_token));
520 inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
521 inserter->AddArg(present_type_id_, Variadic::String(present_type));
522 inserter->AddArg(on_time_finish_id_,
523 Variadic::Integer(event.on_time_finish()));
524 inserter->AddArg(gpu_composition_id_,
525 Variadic::Integer(event.gpu_composition()));
526 inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
527 inserter->AddArg(prediction_type_id_,
528 Variadic::String(prediction_type));
529 inserter->AddArg(is_buffer_id_, Variadic::String(is_buffer));
530 });
531
532 if (opt_slice_id) {
533 display_token_to_surface_slice_.emplace(display_frame_token, *opt_slice_id);
534 }
535 }
536
ParseFrameEnd(int64_t timestamp,ConstBytes bufferBlob)537 void FrameTimelineEventParser::ParseFrameEnd(int64_t timestamp,
538 ConstBytes bufferBlob) {
539 FrameEndDecoder event(bufferBlob.data, bufferBlob.size);
540
541 if (!event.has_cookie()) {
542 context_->storage->IncrementStats(
543 stats::frame_timeline_event_parser_errors);
544 return;
545 }
546
547 int64_t cookie = event.cookie();
548 auto it = cookie_track_set_id_map_.find(cookie);
549 if (it == cookie_track_set_id_map_.end()) {
550 context_->storage->IncrementStats(stats::frame_timeline_unpaired_end_event);
551 return;
552 }
553 auto track_set_id = it->second;
554 auto track_id = context_->async_track_set_tracker->End(track_set_id, cookie);
555 context_->slice_tracker->End(timestamp, track_id);
556 cookie_track_set_id_map_.erase(it);
557 }
558
ParseFrameTimelineEvent(int64_t timestamp,ConstBytes blob)559 void FrameTimelineEventParser::ParseFrameTimelineEvent(int64_t timestamp,
560 ConstBytes blob) {
561 protos::pbzero::FrameTimelineEvent_Decoder frame_event(blob.data, blob.size);
562
563 if (IsBadTimestamp(timestamp)) {
564 context_->storage->IncrementStats(
565 stats::frame_timeline_event_parser_errors);
566 return;
567 }
568
569 if (frame_event.has_expected_display_frame_start()) {
570 ParseExpectedDisplayFrameStart(timestamp,
571 frame_event.expected_display_frame_start());
572 } else if (frame_event.has_actual_display_frame_start()) {
573 ParseActualDisplayFrameStart(timestamp,
574 frame_event.actual_display_frame_start());
575 } else if (frame_event.has_expected_surface_frame_start()) {
576 ParseExpectedSurfaceFrameStart(timestamp,
577 frame_event.expected_surface_frame_start());
578 } else if (frame_event.has_actual_surface_frame_start()) {
579 ParseActualSurfaceFrameStart(timestamp,
580 frame_event.actual_surface_frame_start());
581 } else if (frame_event.has_frame_end()) {
582 ParseFrameEnd(timestamp, frame_event.frame_end());
583 } else {
584 context_->storage->IncrementStats(
585 stats::frame_timeline_event_parser_errors);
586 }
587 }
588 } // namespace trace_processor
589 } // namespace perfetto
590