Restrict timeline collection to a subset of demos (#9093)
Also refactors demos list into a class with `synchronized` and
`profiled` properties.
When run with --trace-startup, as we do in this test, the VM stores
trace events in an endless buffer instead of a ring buffer. To avoid
out-of-memory conditions, we restrict timeline collection to a subset.
diff --git a/examples/flutter_gallery/test_driver/transitions_perf_test.dart b/examples/flutter_gallery/test_driver/transitions_perf_test.dart
index cc6c29a..79b5252 100644
--- a/examples/flutter_gallery/test_driver/transitions_perf_test.dart
+++ b/examples/flutter_gallery/test_driver/transitions_perf_test.dart
@@ -11,57 +11,72 @@
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
+class Demo {
+ const Demo(this.title, {this.synchronized = true, this.profiled = false});
+
+ /// The title of the demo.
+ final String title;
+
+ /// True if frameSync should be enabled for this test.
+ final bool synchronized;
+
+ // True if timeline data should be collected for this test.
+ //
+ // Warning: The number of tests executed with timeline collection enabled
+ // significantly impacts heap size of the running app. When run with
+ // --trace-startup, as we do in this test, the VM stores trace events in an
+ // endless buffer instead of a ring buffer.
+ final bool profiled;
+}
+
// Warning: this list must be kept in sync with the value of
// kAllGalleryItems.map((GalleryItem item) => item.title).toList();
-final List<String> demoTitles = <String>[
+const List<Demo> demos = const <Demo>[
// Demos
- 'Pesto',
- 'Shrine',
- 'Contact profile',
- 'Animation',
- // Material Components
- 'Bottom navigation',
- 'Buttons',
- 'Cards',
- 'Chips',
- 'Date and time pickers',
- 'Dialog',
- 'Drawer',
- 'Expand/collapse list control',
- 'Expansion panels',
- 'Floating action button',
- 'Grid',
- 'Icons',
- 'Leave-behind list items',
- 'List',
- 'Menus',
- 'Modal bottom sheet',
- 'Page selector',
- 'Persistent bottom sheet',
- 'Progress indicators',
- 'Pull to refresh',
- 'Scrollable tabs',
- 'Selection controls',
- 'Sliders',
- 'Snackbar',
- 'Tabs',
- 'Text fields',
- 'Tooltips',
- // Cupertino Components
- 'Activity Indicator',
- 'Buttons',
- 'Dialogs',
- 'Sliders',
- 'Switches',
- // Style
- 'Colors',
- 'Typography'
-];
+ const Demo('Pesto', profiled: true),
+ const Demo('Shrine', profiled: true),
+ const Demo('Contact profile', profiled: true),
+ const Demo('Animation', profiled: true),
-// Subset of [demoTitles] that needs frameSync turned off.
-final List<String> unsynchedDemoTitles = <String>[
- 'Progress indicators',
- 'Activity Indicator',
+ // Material Components
+ const Demo('Bottom navigation', profiled: true),
+ const Demo('Buttons', profiled: true),
+ const Demo('Cards', profiled: true),
+ const Demo('Chips', profiled: true),
+ const Demo('Date and time pickers', profiled: true),
+ const Demo('Dialog', profiled: true),
+ const Demo('Drawer'),
+ const Demo('Expand/collapse list control'),
+ const Demo('Expansion panels'),
+ const Demo('Floating action button'),
+ const Demo('Grid'),
+ const Demo('Icons'),
+ const Demo('Leave-behind list items'),
+ const Demo('List'),
+ const Demo('Menus'),
+ const Demo('Modal bottom sheet'),
+ const Demo('Page selector'),
+ const Demo('Persistent bottom sheet'),
+ const Demo('Progress indicators', synchronized: false),
+ const Demo('Pull to refresh'),
+ const Demo('Scrollable tabs'),
+ const Demo('Selection controls'),
+ const Demo('Sliders'),
+ const Demo('Snackbar'),
+ const Demo('Tabs'),
+ const Demo('Text fields'),
+ const Demo('Tooltips'),
+
+ // Cupertino Components
+ const Demo('Activity Indicator', synchronized: false),
+ const Demo('Buttons'),
+ const Demo('Dialogs'),
+ const Demo('Sliders'),
+ const Demo('Switches'),
+
+ // Style
+ const Demo('Colors'),
+ const Demo('Typography'),
];
final FileSystem _fs = const LocalFileSystem();
@@ -134,6 +149,32 @@
await file.writeAsString(const JsonEncoder.withIndent(' ').convert(durations));
}
+/// Scrolls each demo menu item into view, launches it, then returns to the
+/// home screen twice.
+Future<Null> runDemos(Iterable<Demo> demos, FlutterDriver driver) async {
+ for (Demo demo in demos) {
+ print('Testing "${demo.title}" demo');
+ final SerializableFinder menuItem = find.text(demo.title);
+ await driver.scrollIntoView(menuItem, alignment: 0.5);
+ await new Future<Null>.delayed(kWaitBetweenActions);
+
+ for (int i = 0; i < 2; i += 1) {
+ await driver.tap(menuItem); // Launch the demo
+ await new Future<Null>.delayed(kWaitBetweenActions);
+ if (demo.synchronized) {
+ await driver.tap(find.byTooltip('Back'));
+ } else {
+ await driver.runUnsynchronized<Future<Null>>(() async {
+ await new Future<Null>.delayed(kWaitBetweenActions);
+ await driver.tap(find.byTooltip('Back'));
+ });
+ }
+ await new Future<Null>.delayed(kWaitBetweenActions);
+ }
+ print('Success');
+ }
+}
+
void main() {
group('flutter gallery transitions', () {
FlutterDriver driver;
@@ -147,30 +188,10 @@
});
test('all demos', () async {
+ // Collect timeline data for just a limited set of demos to avoid OOMs.
final Timeline timeline = await driver.traceAction(() async {
- // Scroll each demo menu item into view, launch the demo and
- // return to the demo menu 2x.
- for(String demoTitle in demoTitles) {
- print('Testing "$demoTitle" demo');
- final SerializableFinder menuItem = find.text(demoTitle);
- await driver.scrollIntoView(menuItem, alignment: 0.5);
- await new Future<Null>.delayed(kWaitBetweenActions);
-
- for(int i = 0; i < 2; i += 1) {
- await driver.tap(menuItem); // Launch the demo
- await new Future<Null>.delayed(kWaitBetweenActions);
- if (!unsynchedDemoTitles.contains(demoTitle)) {
- await driver.tap(find.byTooltip('Back'));
- } else {
- await driver.runUnsynchronized<Future<Null>>(() async {
- await new Future<Null>.delayed(kWaitBetweenActions);
- await driver.tap(find.byTooltip('Back'));
- });
- }
- await new Future<Null>.delayed(kWaitBetweenActions);
- }
- print('Success');
- }
+ final Iterable<Demo> profiledDemos = demos.where((Demo demo) => demo.profiled);
+ await runDemos(profiledDemos, driver);
},
streams: const <TimelineStream>[
TimelineStream.dart,
@@ -184,6 +205,11 @@
await summary.writeSummaryToFile('transitions', pretty: true);
final String histogramPath = path.join(testOutputsDirectory, 'transition_durations.timeline.json');
await saveDurationsHistogram(timeline.json['traceEvents'], histogramPath);
+
+ // Execute the remaining tests.
+ final Iterable<Demo> unprofiledDemos = demos.where((Demo demo) => !demo.profiled);
+ await runDemos(unprofiledDemos, driver);
+
}, timeout: const Timeout(const Duration(minutes: 5)));
});
}