Commit 4b401a3e authored by Ian Hickson's avatar Ian Hickson

Track the worst frame in perf tests (#3642)

* Track the worst frame in perf tests

* Use backticks in "/// Returns `null` if"
parent 4b6af7a4
......@@ -1611,7 +1611,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// the approximate bounding box of the clip rect that would be
/// applied to the given child during the paint phase, if any.
///
/// Returns null if the child would not be clipped.
/// Returns `null` if the child would not be clipped.
///
/// This is used in the semantics phase to avoid including children
/// that are not physically visible.
......
......@@ -54,7 +54,7 @@ class MojoShell {
/// Attempts to connect to an application via the Mojo shell.
///
/// Returns null if [canConnectToOtherApplications] is false.
/// Returns `null` if [canConnectToOtherApplications] is false.
ApplicationConnection connectToApplication(String url) {
if (_shell == null)
return null;
......
......@@ -104,7 +104,7 @@ class PageStorage extends StatelessWidget {
/// The bucket from the closest instance of this class that encloses the given context.
///
/// Returns null if none exists.
/// Returns `null` if none exists.
static PageStorageBucket of(BuildContext context) {
PageStorage widget = context.ancestorWidgetOfExactType(PageStorage);
return widget?.bucket;
......
......@@ -468,7 +468,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// Returns the modal route most closely associated with the given context.
///
/// Returns null if the given context is not associated with a modal route.
/// Returns `null` if the given context is not associated with a modal route.
static ModalRoute<dynamic> of(BuildContext context) {
_ModalScopeStatus widget = context.inheritFromWidgetOfExactType(_ModalScopeStatus);
return widget?.route;
......
......@@ -18,7 +18,7 @@ abstract class ScrollBehavior<T, U> {
///
/// This function is called when a drag gesture ends.
///
/// Returns null if the behavior is to do nothing.
/// Returns `null` if the behavior is to do nothing.
Simulation createScrollSimulation(T position, U velocity) => null;
/// Returns an animation that ends at the snap offset.
......@@ -26,7 +26,7 @@ abstract class ScrollBehavior<T, U> {
/// This function is called when a drag gesture ends and a
/// [SnapOffsetCallback] is specified for the scrollable.
///
/// Returns null if the behavior is to do nothing.
/// Returns `null` if the behavior is to do nothing.
Simulation createSnapScrollSimulation(T startOffset, T endOffset, U startVelocity, U endVelocity) => null;
/// Returns the scroll offset to use when the user attempts to scroll
......
......@@ -4,6 +4,7 @@
import 'dart:async';
import 'dart:convert' show JSON, JsonEncoder;
import 'dart:math' as math;
import 'package:file/file.dart';
import 'package:path/path.dart' as path;
......@@ -26,6 +27,8 @@ class TimelineSummary {
/// Average amount of time spent per frame in the framework building widgets,
/// updating layout, painting and compositing.
///
/// Returns `null` if no frames were recorded.
double computeAverageFrameBuildTimeMillis() {
int totalBuildTimeMicros = 0;
int frameCount = 0;
......@@ -40,6 +43,24 @@ class TimelineSummary {
: null;
}
/// Find amount of time spent in the framework building widgets,
/// updating layout, painting and compositing on worst frame.
///
/// Returns `null` if no frames were recorded.
double computeWorstFrameBuildTimeMillis() {
int maxBuildTimeMicros = 0;
int frameCount = 0;
for (TimedEvent event in _extractBeginFrameEvents()) {
frameCount++;
maxBuildTimeMicros = math.max(maxBuildTimeMicros, event.duration.inMicroseconds);
}
return frameCount > 0
? maxBuildTimeMicros / 1000
: null;
}
/// The total number of frames recorded in the timeline.
int countFrames() => _extractBeginFrameEvents().length;
......@@ -55,6 +76,7 @@ class TimelineSummary {
Map<String, dynamic> get summaryJson {
return <String, dynamic> {
'average_frame_build_time_millis': computeAverageFrameBuildTimeMillis(),
'worst_frame_build_time_millis': computeWorstFrameBuildTimeMillis(),
'missed_frame_build_budget_count': computeMissedFrameBuildBudgetCount(),
'frame_count': countFrames(),
'frame_build_times': _extractBeginFrameEvents()
......
......@@ -58,7 +58,7 @@ void main() {
end(1000),
begin(2000), end(4000),
]).computeAverageFrameBuildTimeMillis(),
2
2.0
);
});
......@@ -68,7 +68,50 @@ void main() {
begin(2000), end(4000),
begin(5000),
]).computeAverageFrameBuildTimeMillis(),
2
2.0
);
});
});
group('worst_frame_build_time_millis', () {
test('returns null when there is no data', () {
expect(summarize([]).computeWorstFrameBuildTimeMillis(), isNull);
});
test('computes worst frame build time in milliseconds', () {
expect(
summarize([
begin(1000), end(2000),
begin(3000), end(5000),
]).computeWorstFrameBuildTimeMillis(),
2.0
);
expect(
summarize([
begin(3000), end(5000),
begin(1000), end(2000),
]).computeWorstFrameBuildTimeMillis(),
2.0
);
});
test('skips leading "end" events', () {
expect(
summarize([
end(1000),
begin(2000), end(4000),
]).computeWorstFrameBuildTimeMillis(),
2.0
);
});
test('skips trailing "begin" events', () {
expect(
summarize([
begin(2000), end(4000),
begin(5000),
]).computeWorstFrameBuildTimeMillis(),
2.0
);
});
});
......@@ -96,6 +139,7 @@ void main() {
]).summaryJson,
{
'average_frame_build_time_millis': 7.0,
'worst_frame_build_time_millis': 11.0,
'missed_frame_build_budget_count': 2,
'frame_count': 3,
'frame_build_times': <int>[9000, 1000, 11000],
......@@ -131,6 +175,7 @@ void main() {
await fs.file('/temp/test.timeline_summary.json').readAsString();
expect(JSON.decode(written), {
'average_frame_build_time_millis': 7.0,
'worst_frame_build_time_millis': 11.0,
'missed_frame_build_budget_count': 2,
'frame_count': 3,
'frame_build_times': <int>[9000, 1000, 11000],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment