802467cb76
Change-Id: I1924c72dbda64d864d5139b93c5b3377898d6ede Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/174780 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Devon Carew <devoncarew@google.com>
254 lines
6.1 KiB
Dart
254 lines
6.1 KiB
Dart
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
|
// for details. 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:convert';
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:args/args.dart';
|
|
import 'package:meta/meta.dart';
|
|
|
|
List<Benchmark> benchmarks = [
|
|
DartStartup(),
|
|
DartRunStartup(),
|
|
SdkSize(),
|
|
];
|
|
|
|
void main(List<String> args) async {
|
|
ArgParser argParser = _createArgParser();
|
|
|
|
ArgResults argResults;
|
|
|
|
try {
|
|
argResults = argParser.parse(args);
|
|
} on FormatException catch (e) {
|
|
print(e.message);
|
|
print('');
|
|
printUsage(argParser, includeDescription: false);
|
|
io.exit(1);
|
|
}
|
|
|
|
if (argResults['help'] || argResults.arguments.isEmpty) {
|
|
printUsage(argParser);
|
|
io.exit(0);
|
|
}
|
|
|
|
if (!argResults.wasParsed('dart-sdk')) {
|
|
print('No value passed for \`dart-sdk\`.');
|
|
print('');
|
|
printUsage(argParser);
|
|
io.exit(1);
|
|
}
|
|
|
|
if (!argResults.wasParsed('run')) {
|
|
print('No value passed for \`run\`.');
|
|
print('');
|
|
printUsage(argParser);
|
|
io.exit(1);
|
|
}
|
|
|
|
Context context = Context(argResults['dart-sdk']);
|
|
|
|
String benchmarkName = argResults['run'];
|
|
Benchmark benchmark = benchmarks.singleWhere((b) => b.id == benchmarkName);
|
|
|
|
BenchmarkResult result = await benchmark.run(context);
|
|
print(result.toJson());
|
|
io.exit(0);
|
|
}
|
|
|
|
void printUsage(ArgParser argParser, {bool includeDescription = true}) {
|
|
print('usage: dart bin/bench.dart <options>');
|
|
print('');
|
|
if (includeDescription) {
|
|
print('Run benchmarks for the dartdev tool.');
|
|
print('');
|
|
}
|
|
print('Options:');
|
|
print(argParser.usage);
|
|
}
|
|
|
|
ArgParser _createArgParser() {
|
|
ArgParser argParser = ArgParser(usageLineLength: io.stdout.terminalColumns);
|
|
argParser.addFlag(
|
|
'help',
|
|
abbr: 'h',
|
|
negatable: false,
|
|
help: 'Print this usage information.',
|
|
);
|
|
argParser.addOption(
|
|
'dart-sdk',
|
|
valueHelp: 'sdk path',
|
|
help: 'The path to the Dart SDK to use for benchmarking.',
|
|
);
|
|
argParser.addOption(
|
|
'run',
|
|
valueHelp: 'benchmark',
|
|
allowed: benchmarks.map((b) => b.id).toList(),
|
|
allowedHelp: {
|
|
for (var benchmark in benchmarks) benchmark.id: benchmark.description,
|
|
},
|
|
help: 'The benchmark to run.',
|
|
);
|
|
return argParser;
|
|
}
|
|
|
|
abstract class Benchmark {
|
|
final String id;
|
|
final String description;
|
|
|
|
Benchmark(this.id, this.description);
|
|
|
|
Future<BenchmarkResult> run(Context context);
|
|
}
|
|
|
|
class DartStartup extends Benchmark {
|
|
DartStartup()
|
|
: super(
|
|
'script-startup',
|
|
'Benchmark the startup time of a minimal Dart script (μs).',
|
|
);
|
|
|
|
@override
|
|
Future<BenchmarkResult> run(Context context) async {
|
|
// setup
|
|
io.Directory dir = io.Directory.systemTemp.createTempSync('dartdev');
|
|
io.File file = io.File('${dir.path}/hello.dart');
|
|
file.writeAsStringSync('void main() => print(\'hello\');');
|
|
|
|
// perform the benchmark
|
|
Stopwatch timer = Stopwatch()..start();
|
|
io.Process.runSync(
|
|
'${context.sdkPath}/bin/dart',
|
|
[file.absolute.path],
|
|
);
|
|
timer.stop();
|
|
|
|
// cleanup
|
|
dir.deleteSync(recursive: true);
|
|
|
|
// report the result
|
|
int micros = timer.elapsedMicroseconds;
|
|
return BenchmarkResult(
|
|
id: id,
|
|
value: micros,
|
|
units: 'microseconds',
|
|
userDescription: '${(micros / 1000.0).toStringAsFixed(2)}ms',
|
|
);
|
|
}
|
|
}
|
|
|
|
class DartRunStartup extends Benchmark {
|
|
DartRunStartup()
|
|
: super(
|
|
'run-script-startup',
|
|
'Benchmark the startup time of a minimal Dart script, executed with '
|
|
'\`dart run\` (μs).',
|
|
);
|
|
|
|
@override
|
|
Future<BenchmarkResult> run(Context context) async {
|
|
// setup
|
|
io.Directory dir = io.Directory.systemTemp.createTempSync('dartdev');
|
|
io.File file = io.File('${dir.path}/hello.dart');
|
|
file.writeAsStringSync('void main() => print(\'hello\');');
|
|
|
|
// perform the benchmark
|
|
Stopwatch timer = Stopwatch()..start();
|
|
io.Process.runSync(
|
|
'${context.sdkPath}/bin/dart',
|
|
['run', file.absolute.path],
|
|
);
|
|
timer.stop();
|
|
|
|
// cleanup
|
|
dir.deleteSync(recursive: true);
|
|
|
|
// report the result
|
|
int micros = timer.elapsedMicroseconds;
|
|
return BenchmarkResult(
|
|
id: id,
|
|
value: micros,
|
|
units: 'microseconds',
|
|
userDescription: '${(micros / 1000.0).toStringAsFixed(2)}ms',
|
|
);
|
|
}
|
|
}
|
|
|
|
class SdkSize extends Benchmark {
|
|
SdkSize()
|
|
: super(
|
|
'sdk-size',
|
|
'Benchmark the compressed size of the Dart SDK (bytes).',
|
|
);
|
|
|
|
@override
|
|
Future<BenchmarkResult> run(Context context) async {
|
|
// setup
|
|
io.Directory tempDir = io.Directory.systemTemp.createTempSync('dartdev');
|
|
|
|
// perform the benchmark
|
|
io.File sdkArchive = compress(io.Directory(context.sdkPath), tempDir);
|
|
int bytes = sdkArchive.lengthSync();
|
|
|
|
// cleanup
|
|
tempDir.deleteSync(recursive: true);
|
|
|
|
// report the result
|
|
return BenchmarkResult(
|
|
id: id,
|
|
value: bytes,
|
|
units: 'bytes',
|
|
userDescription: '${(bytes / (1024.0 * 1024.0)).toStringAsFixed(1)}MB',
|
|
);
|
|
}
|
|
|
|
io.File compress(io.Directory sourceDir, io.Directory targetDir) {
|
|
String name = sourceDir.path.substring(sourceDir.path.lastIndexOf('/') + 1);
|
|
io.File outFile = io.File('${targetDir.absolute.path}/$name.zip');
|
|
|
|
if (io.Platform.isMacOS || io.Platform.isLinux) {
|
|
io.Process.runSync('zip', [
|
|
'-r',
|
|
'-9', // optimized for compressed size
|
|
outFile.absolute.path,
|
|
sourceDir.absolute.path,
|
|
]);
|
|
} else {
|
|
throw Exception('platform not supported: ${io.Platform.operatingSystem}');
|
|
}
|
|
|
|
return outFile;
|
|
}
|
|
}
|
|
|
|
class Context {
|
|
final String sdkPath;
|
|
|
|
Context(this.sdkPath);
|
|
}
|
|
|
|
class BenchmarkResult {
|
|
final String id;
|
|
final int value;
|
|
final String units;
|
|
final String userDescription;
|
|
|
|
BenchmarkResult({
|
|
@required this.id,
|
|
@required this.value,
|
|
@required this.units,
|
|
@required this.userDescription,
|
|
});
|
|
|
|
String toJson() {
|
|
Map m = {
|
|
'id': id,
|
|
'value': value,
|
|
'units': units,
|
|
'userDescription': userDescription,
|
|
};
|
|
return JsonEncoder.withIndent(' ').convert(m);
|
|
}
|
|
}
|