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