// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'percentile_utils.dart'; import 'timeline.dart'; const String _kPlatformVsyncEvent = 'VSYNC'; const String _kUIThreadVsyncProcessEvent = 'VsyncProcessCallback'; /// Event names for frame lag related timeline events. const Set<String> kVsyncTimelineEventNames = <String>{ _kUIThreadVsyncProcessEvent, _kPlatformVsyncEvent, }; /// Summarizes [TimelineEvents]s corresponding to [kVsyncTimelineEventNames] events. /// /// `VsyncFrameLag` is the time between when a platform vsync event is received to /// when the frame starts getting processed by the Flutter Engine. This delay is /// typically seen due to non-frame workload related dart tasks being scheduled /// on the UI thread. class VsyncFrameLagSummarizer { /// Creates a VsyncFrameLagSummarizer given the timeline events. VsyncFrameLagSummarizer(this.vsyncEvents); /// Timeline events with names in [kVsyncTimelineEventNames]. final List<TimelineEvent> vsyncEvents; /// Computes the average `VsyncFrameLag` over the period of the timeline. double computeAverageVsyncFrameLag() { final List<double> vsyncFrameLags = _computePlatformToFlutterVsyncBeginLags(); if (vsyncFrameLags.isEmpty) { return 0; } final double total = vsyncFrameLags.reduce((double a, double b) => a + b); return total / vsyncFrameLags.length; } /// Computes the [percentile]-th percentile `VsyncFrameLag` over the /// period of the timeline. double computePercentileVsyncFrameLag(double percentile) { final List<double> vsyncFrameLags = _computePlatformToFlutterVsyncBeginLags(); if (vsyncFrameLags.isEmpty) { return 0; } return findPercentile(vsyncFrameLags, percentile); } List<double> _computePlatformToFlutterVsyncBeginLags() { int platformIdx = -1; final List<double> result = <double>[]; for (int i = 0; i < vsyncEvents.length; i++) { final TimelineEvent event = vsyncEvents[i]; if (event.phase != 'B') { continue; } if (event.name == _kPlatformVsyncEvent) { // There was a vsync that resulted in a frame not being built. // This needs to be penalized. if (platformIdx != -1) { final int prevTS = vsyncEvents[platformIdx].timestampMicros!; result.add((event.timestampMicros! - prevTS).toDouble()); } platformIdx = i; } else if (platformIdx != -1) { final int platformTS = vsyncEvents[platformIdx].timestampMicros!; result.add((event.timestampMicros! - platformTS).toDouble()); platformIdx = -1; } } return result; } }