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