blob: 9fe2c50458e3eb90d3c8ee8676f89ffeae929766 [file] [log] [blame]
// 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;
}
}