diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart index 61c21dbc1d..c867a62b0d 100644 --- a/dev/benchmarks/macrobenchmarks/lib/common.dart +++ b/dev/benchmarks/macrobenchmarks/lib/common.dart @@ -20,6 +20,7 @@ const String kMultiWidgetConstructionRouteName = '/multi_widget_construction'; const String kHeavyGridViewRouteName = '/heavy_gridview'; const String kSimpleScrollRouteName = '/simple_scroll'; const String kStackSizeRouteName = '/stack_size'; +const String kAnimationWithMicrotasksRouteName = '/animation_with_microtasks'; const String kScrollableName = '/macrobenchmark_listview'; diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart index 0754a2df5c..34d063af65 100644 --- a/dev/benchmarks/macrobenchmarks/lib/main.dart +++ b/dev/benchmarks/macrobenchmarks/lib/main.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'common.dart'; import 'src/animated_placeholder.dart'; +import 'src/animation_with_microtasks.dart'; import 'src/backdrop_filter.dart'; import 'src/color_filter_and_fade.dart'; import 'src/cubic_bezier.dart'; @@ -56,6 +57,7 @@ class MacrobenchmarksApp extends StatelessWidget { kHeavyGridViewRouteName: (BuildContext context) => const HeavyGridViewPage(), kSimpleScrollRouteName: (BuildContext context) => const SimpleScroll(), kStackSizeRouteName: (BuildContext context) => const StackSizePage(), + kAnimationWithMicrotasksRouteName: (BuildContext context) => const AnimationWithMicrotasks(), }, ); } @@ -192,6 +194,13 @@ class HomePage extends StatelessWidget { Navigator.pushNamed(context, kStackSizeRouteName); }, ), + ElevatedButton( + key: const Key(kAnimationWithMicrotasksRouteName), + child: const Text('Animation With Microtasks'), + onPressed: () { + Navigator.pushNamed(context, kAnimationWithMicrotasksRouteName); + }, + ), ], ), ); diff --git a/dev/benchmarks/macrobenchmarks/lib/src/animation_with_microtasks.dart b/dev/benchmarks/macrobenchmarks/lib/src/animation_with_microtasks.dart new file mode 100644 index 0000000000..8ef4ac42fd --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/animation_with_microtasks.dart @@ -0,0 +1,74 @@ +// 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 'package:flutter/material.dart'; + +class AnimationWithMicrotasks extends StatefulWidget { + const AnimationWithMicrotasks({Key key}) : super(key: key); + + @override + _AnimationWithMicrotasksState createState() => + _AnimationWithMicrotasksState(); +} + +class _AnimationWithMicrotasksState extends State { + final _ChunkedWork work = _ChunkedWork(); + + @override + void initState() { + super.initState(); + work.start(); + } + + @override + void dispose() { + work.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return const Scaffold( + backgroundColor: Colors.grey, + body: Center( + child: SizedBox( + width: 200, + height: 100, + child: LinearProgressIndicator(), + ), + ), + ); + } +} + +class _ChunkedWork { + bool _canceled = false; + + Future start() async { + // Run 100 pieces of synchronous work. + // Chunked up to allow frames to be drawn. + for (int i = 0; i < 100; ++i) { + _chunkedSynchronousWork(); + } + } + + void cancel() { + _canceled = true; + } + + Future _chunkedSynchronousWork() async { + while (!_canceled) { + // Yield to the event loop to let engine draw frames. + await Future.delayed(Duration.zero); + + // Perform synchronous computation for 1 ms. + _syncComputationFor(const Duration(milliseconds: 1)); + } + } + + void _syncComputationFor(Duration duration) { + final Stopwatch sw = Stopwatch()..start(); + while (!_canceled && sw.elapsed < duration) {} + } +} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/animation_with_microtasks_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/animation_with_microtasks_perf_test.dart new file mode 100644 index 0000000000..4ffa35bff0 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test_driver/animation_with_microtasks_perf_test.dart @@ -0,0 +1,16 @@ +// 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 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTest( + 'animation_with_microtasks_perf', + kAnimationWithMicrotasksRouteName, + pageDelay: const Duration(seconds: 1), + duration: const Duration(seconds: 10), + ); +} diff --git a/dev/devicelab/bin/tasks/animation_with_microtasks_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/animation_with_microtasks_perf_ios__timeline_summary.dart new file mode 100644 index 0000000000..c3ebf6b6df --- /dev/null +++ b/dev/devicelab/bin/tasks/animation_with_microtasks_perf_ios__timeline_summary.dart @@ -0,0 +1,12 @@ +// 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 'package:flutter_devicelab/tasks/perf_tests.dart'; +import 'package:flutter_devicelab/framework/adb.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createAnimationWithMicrotasksPerfTest()); +} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 13b566a3c5..a9e4aeba99 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -151,6 +151,17 @@ TaskFunction createBackdropFilterPerfTest({bool measureCpuGpu = true}) { ).run; } +TaskFunction createAnimationWithMicrotasksPerfTest({bool measureCpuGpu = true}) { + return PerfTest( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test_driver/run_app.dart', + 'animation_with_microtasks_perf', + measureCpuGpu: measureCpuGpu, + testDriver: 'test_driver/animation_with_microtasks_perf_test.dart', + saveTraceFile: true, + ).run; +} + TaskFunction createBackdropFilterPerfE2ETest() { return PerfTest.e2e( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', diff --git a/dev/prod_builders.json b/dev/prod_builders.json index f78e3501fb..68d1ea1dba 100644 --- a/dev/prod_builders.json +++ b/dev/prod_builders.json @@ -942,6 +942,12 @@ "task_name": "mac_tool_integration_tests_3_3", "flaky": false }, + { + "name": "Mac_ios animation_with_microtasks_perf_ios__timeline_summary", + "repo": "flutter", + "task_name": "mac_ios_animation_with_microtasks_perf_ios__timeline_summary", + "flaky": false + }, { "name": "Mac_ios backdrop_filter_perf_ios__timeline_summary", "repo": "flutter",