From d8e42bfaa938abed892c1c04288865a8661578e0 Mon Sep 17 00:00:00 2001 From: David Morgan Date: Fri, 20 Dec 2024 10:41:32 +0100 Subject: [PATCH] WIP, not for submit: benchmark analyzer-based generation / incremental generation by number of files. --- _test/bin/benchmark.dart | 71 ++++++++++++++ _test/lib/built_value1.dart | 10 ++ _test/lib/built_value1.g.dart | 65 +++++++++++++ _test/pubspec.yaml | 2 + _test/test/common/utils.dart | 174 ++++++++++++++++++++-------------- 5 files changed, 251 insertions(+), 71 deletions(-) create mode 100644 _test/bin/benchmark.dart create mode 100644 _test/lib/built_value1.dart create mode 100644 _test/lib/built_value1.g.dart diff --git a/_test/bin/benchmark.dart b/_test/bin/benchmark.dart new file mode 100644 index 000000000..bcce0674b --- /dev/null +++ b/_test/bin/benchmark.dart @@ -0,0 +1,71 @@ +import 'dart:io'; + +import '../test/common/utils.dart'; + +Future main() async { + // only works in test + inTest = false; + ensureCleanGitClient(); + print('Initial build.'); + await runBuild(); + print('Done.'); + + print('Files,Build time/ms,Incremental time/ms'); + for (final size in [ + 100, + 500, + 1000, + 1500, + 2000, + 2500, + 3000, + 3500, + 4000, + 4500, + 5000, + ]) { + stdout.write('$size,'); + + await createFile( + 'lib/bv_app.dart', + [ + for (var i = 0; i != size; ++i) "import 'built_value${i + 1}.dart';", + ].join('\n'), + ); + + for (var i = 0; i != size; ++i) { + await createFile('lib/built_value${i + 1}.dart', ''' +import 'package:built_value/built_value.dart'; + +import 'bv_app.dart'; + +part 'built_value${i + 1}.g.dart'; + +abstract class Value implements Built { + Value._(); + factory Value([void Function(ValueBuilder)? updates]) = _\$Value; +} +'''); + } + final stopwatch = Stopwatch()..start(); + await runBuild(); + stdout.write('${stopwatch.elapsedMilliseconds},'); + + await createFile('lib/built_value1.dart', ''' +import 'package:built_value/built_value.dart'; + +import 'bv_app.dart'; + +part 'built_value1.g.dart'; + +abstract class Value implements Built { + int get x; + Value._(); + factory Value([void Function(ValueBuilder)? updates]) = _\$Value; +} +'''); + stopwatch.reset(); + await runBuild(); + print(stopwatch.elapsedMilliseconds); + } +} diff --git a/_test/lib/built_value1.dart b/_test/lib/built_value1.dart new file mode 100644 index 000000000..06ea0c106 --- /dev/null +++ b/_test/lib/built_value1.dart @@ -0,0 +1,10 @@ +import 'package:built_value/built_value.dart'; + + + +part 'built_value1.g.dart'; + +abstract class Value implements Built { + Value._(); + factory Value([void Function(ValueBuilder)? updates]) = _$Value; +} diff --git a/_test/lib/built_value1.g.dart b/_test/lib/built_value1.g.dart new file mode 100644 index 000000000..7effc11a0 --- /dev/null +++ b/_test/lib/built_value1.g.dart @@ -0,0 +1,65 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'built_value1.dart'; + +// ************************************************************************** +// BuiltValueGenerator +// ************************************************************************** + +class _$Value extends Value { + factory _$Value([void Function(ValueBuilder)? updates]) => + (new ValueBuilder()..update(updates))._build(); + + _$Value._() : super._(); + + @override + Value rebuild(void Function(ValueBuilder) updates) => + (toBuilder()..update(updates)).build(); + + @override + ValueBuilder toBuilder() => new ValueBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Value; + } + + @override + int get hashCode { + return 887435281; + } + + @override + String toString() { + return newBuiltValueToStringHelper(r'Value').toString(); + } +} + +class ValueBuilder implements Builder { + _$Value? _$v; + + ValueBuilder(); + + @override + void replace(Value other) { + ArgumentError.checkNotNull(other, 'other'); + _$v = other as _$Value; + } + + @override + void update(void Function(ValueBuilder)? updates) { + if (updates != null) updates(this); + } + + @override + Value build() => _build(); + + _$Value _build() { + final _$result = _$v ?? new _$Value._(); + replace(_$result); + return _$result; + } +} + +// ignore_for_file: deprecated_member_use_from_same_package,type=lint diff --git a/_test/pubspec.yaml b/_test/pubspec.yaml index 74954b46a..b8e412d80 100644 --- a/_test/pubspec.yaml +++ b/_test/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: ^3.6.0 dependencies: + built_value: ^8.9.0 web: ^1.0.0 dev_dependencies: @@ -18,6 +19,7 @@ dev_dependencies: build_runner_core: any build_test: any build_web_compilers: any + built_value_generator: ^8.9.0 dart_flutter_team_lints: ^3.1.0 io: ^1.0.0 path: ^1.8.0 diff --git a/_test/test/common/utils.dart b/_test/test/common/utils.dart index c966b005d..beb3f75be 100644 --- a/_test/test/common/utils.dart +++ b/_test/test/common/utils.dart @@ -11,6 +11,8 @@ import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:test_process/test_process.dart'; +bool inTest = true; + Directory _generatedDir = Directory(p.join(_toolDir.path, 'generated')); Directory _toolDir = Directory(p.join('.dart_tool', 'build')); @@ -31,22 +33,22 @@ Future runCommand(List args) => /// build to complete. /// /// To ensure a clean build, set [ensureCleanBuild] to `true`. -Future startServer( - {bool? ensureCleanBuild, List? buildArgs}) async => - _startServer( - 'dart', - [ - '--packages=${(await Isolate.packageConfig).toString()}', - p.join('..', 'build_runner', 'bin', 'build_runner.dart'), - 'serve', - '--verbose', - if (buildArgs != null) ...buildArgs, - ], - ensureCleanBuild: ensureCleanBuild, - ); - -Future _runBuild(String command, List args, - {bool? ensureCleanBuild}) async { +Future startServer({ + bool? ensureCleanBuild, + List? buildArgs, +}) async => _startServer('dart', [ + '--packages=${(await Isolate.packageConfig).toString()}', + p.join('..', 'build_runner', 'bin', 'build_runner.dart'), + 'serve', + '--verbose', + if (buildArgs != null) ...buildArgs, +], ensureCleanBuild: ensureCleanBuild); + +Future _runBuild( + String command, + List args, { + bool? ensureCleanBuild, +}) async { ensureCleanBuild ??= false; // Make sure this is a clean build @@ -55,13 +57,19 @@ Future _runBuild(String command, List args, } final result = await Process.run(command, args); - printOnFailure('${result.stdout}'); - printOnFailure('${result.stderr}'); + if (inTest) printOnFailure('${result.stdout}'); + if (inTest) printOnFailure('${result.stderr}'); + if (result.exitCode != 0) { + print('Failed! ${result.stdout} ${result.stderr}'); + } return result; } -Future _startServer(String command, List buildArgs, - {bool? ensureCleanBuild}) async { +Future _startServer( + String command, + List buildArgs, { + bool? ensureCleanBuild, +}) async { ensureCleanBuild ??= false; // Make sure this is a clean build @@ -70,18 +78,23 @@ Future _startServer(String command, List buildArgs, } final proc = _process = await Process.start(command, buildArgs); - unawaited(proc.exitCode.then((_) { - if (_process != null) _process = null; - })); - final stdOutLines = _stdOutLines = proc.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .asBroadcastStream(); - - var stdErrLines = proc.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .asBroadcastStream(); + unawaited( + proc.exitCode.then((_) { + if (_process != null) _process = null; + }), + ); + final stdOutLines = + _stdOutLines = + proc.stdout + .transform(utf8.decoder) + .transform(const LineSplitter()) + .asBroadcastStream(); + + var stdErrLines = + proc.stderr + .transform(utf8.decoder) + .transform(const LineSplitter()) + .asBroadcastStream(); stdOutLines.listen((line) => printOnFailure('StdOut: $line')); stdErrLines.listen((line) => printOnFailure('StdErr: $line')); @@ -123,10 +136,17 @@ bool _gitIsClean() { /// state for this directory after running the test. void ensureCleanGitClient() { var gitWasClean = _gitIsClean(); - expect(gitWasClean, isTrue, - reason: 'Not running on a clean git client, aborting test.\n'); + if (inTest) { + expect( + gitWasClean, + isTrue, + reason: 'Not running on a clean git client, aborting test.\n', + ); + } else { + if (!gitWasClean) throw 'Not running on a clean git client, aborting.'; + } - addTearDown(_resetGitClient); + if (inTest) addTearDown(_resetGitClient); } Future _resetGitClient() async { @@ -155,32 +175,36 @@ Future nextStdOutLine(String message) => _stdOutLines!.firstWhere((line) => line.contains(message)); /// Runs tests using the auto build script. -Future runTests( - {bool? usePrecompiled, - List? buildArgs, - List? testArgs}) async { - return _runTests('dart', ['run', 'build_runner'], - usePrecompiled: usePrecompiled, buildArgs: buildArgs, testArgs: testArgs); -} - -Future _runTests(String executable, List scriptArgs, - {bool? usePrecompiled, - List? buildArgs, - List? testArgs}) async { +Future runTests({ + bool? usePrecompiled, + List? buildArgs, + List? testArgs, +}) async { + return _runTests( + 'dart', + ['run', 'build_runner'], + usePrecompiled: usePrecompiled, + buildArgs: buildArgs, + testArgs: testArgs, + ); +} + +Future _runTests( + String executable, + List scriptArgs, { + bool? usePrecompiled, + List? buildArgs, + List? testArgs, +}) async { usePrecompiled ??= true; if (usePrecompiled) { - var args = scriptArgs.toList() - ..add('test') - ..add('--verbose') - ..addAll(buildArgs ?? []) - ..add('--') - ..addAll([ - ...?testArgs, - '-p', - 'chrome', - '-r', - 'expanded', - ]); + var args = + scriptArgs.toList() + ..add('test') + ..add('--verbose') + ..addAll(buildArgs ?? []) + ..add('--') + ..addAll([...?testArgs, '-p', 'chrome', '-r', 'expanded']); return TestProcess.start(executable, args); } else { var args = ['run', 'test', '--pub-serve', '8081', ...?testArgs]; @@ -188,23 +212,31 @@ Future _runTests(String executable, List scriptArgs, } } -Future expectTestsFail( - {bool? usePrecompiled, - List? buildArgs, - List? testArgs}) async { +Future expectTestsFail({ + bool? usePrecompiled, + List? buildArgs, + List? testArgs, +}) async { var result = await runTests( - usePrecompiled: usePrecompiled, buildArgs: buildArgs, testArgs: testArgs); + usePrecompiled: usePrecompiled, + buildArgs: buildArgs, + testArgs: testArgs, + ); expect(result.stdout, emitsThrough(contains('Some tests failed'))); expect(await result.exitCode, isNot(0)); } -Future expectTestsPass( - {int? expectedNumRan, - bool? usePrecompiled, - List? buildArgs, - List? testArgs}) async { +Future expectTestsPass({ + int? expectedNumRan, + bool? usePrecompiled, + List? buildArgs, + List? testArgs, +}) async { var result = await runTests( - usePrecompiled: usePrecompiled, buildArgs: buildArgs, testArgs: testArgs); + usePrecompiled: usePrecompiled, + buildArgs: buildArgs, + testArgs: testArgs, + ); var allLines = await result.stdout.rest.toList(); expect(allLines, contains(contains('All tests passed!'))); if (expectedNumRan != null) { @@ -216,7 +248,7 @@ Future expectTestsPass( Future createFile(String path, String contents) async { var file = File(path); - expect(await file.exists(), isFalse); + if (inTest) expect(await file.exists(), isFalse); await file.create(recursive: true); await file.writeAsString(contents); }