// 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 'dart:io'; import 'dart:math'; import 'package:args/args.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; import 'benchmark_binding.dart'; import 'foundation/all_elements_bench.dart' as all_elements_bench; import 'foundation/change_notifier_bench.dart' as change_notifier_bench; import 'foundation/clamp.dart' as clamp; import 'foundation/decode_and_parse_asset_manifest.dart' as decode_and_parse_asset_manifest; import 'foundation/observer_list_bench.dart' as observer_list_bench; import 'foundation/platform_asset_bundle.dart' as platform_asset_bundle; import 'foundation/standard_message_codec_bench.dart' as standard_message_codec_bench; import 'foundation/standard_method_codec_bench.dart' as standard_method_codec_bench; import 'foundation/timeline_bench.dart' as timeline_bench; import 'geometry/matrix_utils_transform_bench.dart' as matrix_utils_transform_bench; import 'geometry/rrect_contains_bench.dart' as rrect_contains_bench; import 'gestures/gesture_detector_bench.dart' as gesture_detector_bench; import 'gestures/velocity_tracker_bench.dart' as velocity_tracker_bench; import 'language/compute_bench.dart' as compute_bench; import 'language/sync_star_bench.dart' as sync_star_bench; import 'language/sync_star_semantics_bench.dart' as sync_star_semantics_bench; import 'layout/text_intrinsic_bench.dart' as text_intrinsic_bench; import 'stocks/animation_bench.dart' as animation_bench; import 'stocks/build_bench.dart' as build_bench; import 'stocks/build_bench_profiled.dart' as build_bench_profiled; import 'stocks/layout_bench.dart' as layout_bench; import 'ui/image_bench.dart' as image_bench; typedef Benchmark = (String name, Future Function() value); Future main() async { assert(false, "Don't run benchmarks in debug mode! Use 'flutter run --release'."); // BenchmarkingBinding is used by animation_bench, providing a simple // stopwatch interface over rendering. Lifting it here makes all // benchmarks run together. final BenchmarkingBinding binding = BenchmarkingBinding(); final List benchmarks = [ ('foundation/change_notifier_bench.dart', change_notifier_bench.execute), ('foundation/clamp.dart', clamp.execute), ('foundation/platform_asset_bundle.dart', platform_asset_bundle.execute), ('foundation/standard_message_codec_bench.dart', standard_message_codec_bench.execute), ('foundation/standard_method_codec_bench.dart', standard_method_codec_bench.execute), ('foundation/timeline_bench.dart', timeline_bench.execute), ('foundation/decode_and_parse_asset_manifest.dart', decode_and_parse_asset_manifest.execute), ('foundation/observer_list_bench.dart', observer_list_bench.execute), ('geometry/matrix_utils_transform_bench.dart', matrix_utils_transform_bench.execute), ('geometry/rrect_contains_bench.dart', rrect_contains_bench.execute), ('gestures/gesture_detector_bench.dart', gesture_detector_bench.execute), ('gestures/velocity_tracker_bench.dart', velocity_tracker_bench.execute), ('language/compute_bench.dart', compute_bench.execute), ('language/sync_star_bench.dart', sync_star_bench.execute), ('language/sync_star_semantics_bench.dart', sync_star_semantics_bench.execute), ('stocks/animation_bench.dart', () => animation_bench.execute(binding)), ('stocks/build_bench.dart', build_bench.execute), ('stocks/build_bench_profiled.dart', build_bench_profiled.execute), ('stocks/layout_bench.dart', layout_bench.execute), ('ui/image_bench.dart', image_bench.execute), ('layout/text_intrinsic_bench.dart', text_intrinsic_bench.execute), ( 'foundation/all_elements_bench.dart', () async { binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive; runApp(const SizedBox.shrink()); // ensure dispose await SchedulerBinding.instance.endOfFrame; await all_elements_bench.execute(); }, ), ]; // Parses the optional compile-time dart variables; we can't have // arguments passed in to main. final ArgParser parser = ArgParser(); final List allowed = benchmarks.map((Benchmark e) => e.$1).toList(); parser.addMultiOption( 'tests', abbr: 't', defaultsTo: allowed, allowed: allowed, help: 'selected tests to run', ); parser.addOption('seed', defaultsTo: '12345', help: 'selects seed to sort tests by'); final List mainArgs = []; const String testArgs = String.fromEnvironment('tests'); if (testArgs.isNotEmpty) { mainArgs.addAll(['--tests', testArgs]); print('╡ ••• environment test override: $testArgs ••• ╞'); } const String seedArgs = String.fromEnvironment('seed'); if (seedArgs.isNotEmpty) { mainArgs.addAll(['--seed', seedArgs]); print('╡ ••• environment seed override: $seedArgs ••• ╞'); } final ArgResults results = parser.parse(mainArgs); final List selectedTests = results.multiOption('tests'); // Shuffle the tests because we don't want order dependent tests. // It is the responsibility of the infra to tell us what the seed value is, // in case we want to have the seed stable for some time period. final List tests = benchmarks.where((Benchmark e) => selectedTests.contains(e.$1)).toList(); tests.shuffle(Random(int.parse(results.option('seed')!))); print('╡ ••• Running microbenchmarks ••• ╞'); for (final Benchmark mark in tests) { // Reset the frame policy to default - each test can set it on their own. binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fadePointers; print('╡ ••• Running ${mark.$1} ••• ╞'); await mark.$2(); } print('\n\n╡ ••• Done ••• ╞\n\n'); exit(0); }