mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:59:47 +00:00
[dartdev] add several benchmarks for the dart cli and sdk
Change-Id: I5187312784dde2335b0aff605532b333ba86d29b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/173441 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Devon Carew <devoncarew@google.com>
This commit is contained in:
parent
bf24df2671
commit
4fc9632b6c
253
pkg/dartdev/benchmark/bench.dart
Normal file
253
pkg/dartdev/benchmark/bench.dart
Normal file
|
@ -0,0 +1,253 @@
|
|||
// 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(
|
||||
'dart-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(
|
||||
'dart-run-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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue