Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Unified Diff: pkg/front_end/tool/fasta_perf.dart

Issue 2697403005: Add script to run fasta as a benchmark (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/front_end/tool/fasta_perf_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/front_end/tool/fasta_perf.dart
diff --git a/pkg/front_end/tool/fasta_perf.dart b/pkg/front_end/tool/fasta_perf.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ab8043028a1c4c4b8032c767d4a3cd5a0972a77f
--- /dev/null
+++ b/pkg/front_end/tool/fasta_perf.dart
@@ -0,0 +1,298 @@
+// Copyright (c) 2017, 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.
+
+/// An entrypoint used to run portions of fasta and measure its performance.
+library front_end.tool.fasta_perf;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:front_end/src/fasta/analyzer/ast_builder.dart';
+import 'package:front_end/src/fasta/ast_kind.dart' show AstKind;
+import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
+import 'package:front_end/src/fasta/kernel/kernel_target.dart'
+ show KernelTarget;
+import 'package:front_end/src/fasta/parser.dart';
+import 'package:front_end/src/fasta/scanner.dart';
+import 'package:front_end/src/fasta/scanner/io.dart' show readBytesFromFileSync;
+import 'package:front_end/src/fasta/scanner/precedence.dart';
+import 'package:front_end/src/fasta/source/scope_listener.dart' show Scope;
+import 'package:front_end/src/fasta/ticker.dart' show Ticker;
+import 'package:front_end/src/fasta/translate_uri.dart' show TranslateUri;
+import 'package:front_end/src/fasta/translate_uri.dart';
+
+/// Cumulative total number of chars scanned.
+int inputSize = 0;
+
+/// Cumulative time spent scanning.
+Stopwatch scanTimer = new Stopwatch();
+
+main(List<String> args) async {
+ // TODO(sigmund): provide sdk folder as well.
+ if (args.length < 2) {
+ print('usage: fasta_perf.dart <bench-id> <entry.dart>');
+ exit(1);
+ }
+ var bench = args[0];
+ var entryUri = Uri.base.resolve(args[1]);
+
+ await setup(entryUri);
+
+ Map<Uri, List<int>> files = await scanReachableFiles(entryUri);
+ var handlers = {
+ 'scan': () async => scanFiles(files),
+ // TODO(sigmund): enable when we can run the ast-builder standalone.
+ // 'parse': () async => parseFiles(files),
+ 'kernel_gen_e2e': () async {
+ await generateKernel(entryUri);
+ },
+ // TODO(sigmund): enable once we add a build step to create the
+ // platform.dill files.
+ // 'kernel_gen_e2e_sum': () async {
+ // await generateKernel(entryUri, compileSdk: false);
+ // },
+ };
+
+ var handler = handlers[bench];
+ if (handler == null) {
+ // TODO(sigmund): implement the remaining benchmarks.
+ print('unsupported bench-id: $bench. Please specify one of the following: '
+ '${handlers.keys.join(", ")}');
+ exit(1);
+ }
+
+ // TODO(sigmund): replace the warmup with instrumented snapshots.
+ int iterations = bench.contains('kernel_gen') ? 2 : 10;
+ for (int i = 0; i < iterations; i++) {
+ var totalTimer = new Stopwatch()..start();
+ print('== iteration $i');
+ await handler();
+ totalTimer.stop();
+ report('total', totalTimer.elapsedMicroseconds);
+ }
+}
+
+/// Translates `dart:*` and `package:*` URIs to resolved URIs.
+TranslateUri uriResolver;
+
+/// Preliminary set up to be able to correctly resolve URIs on the given
+/// program.
+Future setup(Uri entryUri) async {
+ // TODO(sigmund): use `perf.dart::_findSdkPath` here when fasta can patch the
+ // sdk directly.
+ var sdkRoot =
+ Uri.base.resolve(Platform.resolvedExecutable).resolve('patched_sdk/');
+ uriResolver = await TranslateUri.parse(sdkRoot);
+}
+
+/// Scan [contents] and return the first token produced by the scanner.
+Token tokenize(List<int> contents) {
+ scanTimer.start();
+ var token = scan(contents).tokens;
+ scanTimer.stop();
+ return token;
+}
+
+/// Scans every file in [files] and reports the time spent doing so.
+void scanFiles(Map<Uri, List<int>> files) {
+ scanTimer = new Stopwatch();
+ for (var source in files.values) {
+ tokenize(source);
+ }
+ report('scan', scanTimer.elapsedMicroseconds);
+}
+
+/// Load and scans all files we need to process: files reachable from the
+/// entrypoint and all core libraries automatically included by the VM.
+Future<Map<Uri, List<int>>> scanReachableFiles(Uri entryUri) async {
+ var files = <Uri, List<int>>{};
+ var loadTimer = new Stopwatch()..start();
+ scanTimer = new Stopwatch();
+ var entrypoints = [
+ entryUri,
+ // These extra libraries are added to match the same set of libraries
+ // scanned by default by the VM and the other benchmarks.
+ Uri.parse('dart:async'),
+ Uri.parse('dart:collection'),
+ Uri.parse('dart:convert'),
+ Uri.parse('dart:core'),
+ Uri.parse('dart:developer'),
+ Uri.parse('dart:_internal'),
+ Uri.parse('dart:io'),
+ Uri.parse('dart:isolate'),
+ Uri.parse('dart:math'),
+ Uri.parse('dart:mirrors'),
+ Uri.parse('dart:typed_data'),
+ ];
+ for (var entry in entrypoints) {
+ await collectSources(entry, files);
+ }
+ loadTimer.stop();
+
+ inputSize = 0;
+ // adjust size because there is a null-terminator on the contents.
+ for (var source in files.values) inputSize += (source.length - 1);
+ print('input size: ${inputSize} chars');
+ var loadTime = loadTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
+ report('load', loadTime);
+ report('scan', scanTimer.elapsedMicroseconds);
+ return files;
+}
+
+/// Add to [files] all sources reachable from [start].
+Future<Null> collectSources(Uri start, Map<Uri, List<int>> files) async {
+ helper(Uri uri) {
+ uri = uriResolver.translate(uri) ?? uri;
+ if (uri == null) return;
+ if (files.containsKey(uri)) return;
+ var contents = readBytesFromFileSync(uri);
+ files[uri] = contents;
+ for (var directiveUri in extractDirectiveUris(contents)) {
+ helper(uri.resolve(directiveUri));
+ }
+ }
+
+ helper(start);
+}
+
+/// Parse [contents] as a Dart program and return the URIs that appear in its
+/// import, export, and part directives.
+Set<String> extractDirectiveUris(List<int> contents) {
+ var listener = new DirectiveListener();
+ new DirectiveParser(listener).parseUnit(tokenize(contents));
+ return listener.uris;
+}
+
+/// Diet parser that stops eagerly at the first sign that we have seen all the
+/// import, export, and part directives.
+class DirectiveParser extends ClassMemberParser {
+ DirectiveParser(listener) : super(listener);
+
+ static final _endToken = new SymbolToken(EOF_INFO, -1);
+
+ Token parseClassOrNamedMixinApplication(Token token) => _endToken;
+ Token parseEnum(Token token) => _endToken;
+ parseTypedef(token) => _endToken;
+ parseTopLevelMember(Token token) => _endToken;
+}
+
+/// Listener that records the URIs from imports, exports, and part directives.
+class DirectiveListener extends Listener {
+ bool _inDirective = false;
+ Set<String> uris = new Set<String>();
+
+ void _enterDirective() {
+ _inDirective = true;
+ }
+
+ void _exitDirective() {
+ _inDirective = false;
+ }
+
+ beginImport(_) => _enterDirective();
+ beginExport(_) => _enterDirective();
+ beginPart(_) => _enterDirective();
+
+ endExport(export, semicolon) => _exitDirective();
+ endImport(import, deferred, asKeyword, semicolon) => _exitDirective();
+ endPart(part, semicolon) => _exitDirective();
+
+ void beginLiteralString(Token token) {
+ if (_inDirective) {
+ var quotedString = token.value;
+ uris.add(quotedString.substring(1, quotedString.length - 1));
+ }
+ }
+}
+
+/// Parses every file in [files] and reports the time spent doing so.
+void parseFiles(Map<Uri, List<int>> files) {
+ scanTimer = new Stopwatch();
+ var parseTimer = new Stopwatch()..start();
+ files.forEach((uri, source) {
+ parseFull(uri, source);
+ });
+ parseTimer.stop();
+
+ report('scan', scanTimer.elapsedMicroseconds);
+ report(
+ 'parse', parseTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds);
+}
+
+/// Parse the full body of [source].
+parseFull(Uri uri, List<int> source) {
+ var tokens = tokenize(source);
+ Parser parser = new Parser(new _PartialAstBuilder(uri));
+ parser.parseUnit(tokens);
+}
+
+class _EmptyScope extends Scope {
+ _EmptyScope() : super({}, null);
+}
+
+// Note: AstBuilder doesn't build compilation-units or classes, only method
+// bodies. So this listener is not feature complete.
+class _PartialAstBuilder extends AstBuilder {
+ final Uri uri;
+ _PartialAstBuilder(this.uri) : super(null, null, null, new _EmptyScope());
+
+ // Note: this method converts the body to kernel, so we skip that here.
+ @override
+ finishFunction(formals, asyncModifier, body) {}
+}
+
+// Invoke the fasta kernel generator for the program starting in [entryUri]
+// TODO(sigmund): update to uyse the frontend api once fasta is beind hit.
+generateKernel(Uri entryUri, {bool compileSdk: true}) async {
+ // TODO(sigmund): this is here only to compute the input size,
+ // we should extract the input size from the frontend instead.
+ scanReachableFiles(entryUri);
+
+ var timer = new Stopwatch()..start();
+ final Ticker ticker = new Ticker();
+ final DillTarget dillTarget = new DillTarget(ticker, uriResolver);
+ final KernelTarget kernelTarget = new KernelTarget(dillTarget, uriResolver);
+ var entrypoints = [
+ entryUri,
+ // These extra libraries are added to match the same set of libraries
+ // scanned by default by the VM and the other benchmarks.
+ Uri.parse('dart:async'),
+ Uri.parse('dart:collection'),
+ Uri.parse('dart:convert'),
+ Uri.parse('dart:core'),
+ Uri.parse('dart:developer'),
+ Uri.parse('dart:_internal'),
+ Uri.parse('dart:io'),
+ Uri.parse('dart:isolate'),
+ Uri.parse('dart:math'),
+ Uri.parse('dart:mirrors'),
+ Uri.parse('dart:typed_data'),
+ ];
+ entrypoints.forEach(kernelTarget.read);
+
+ if (!compileSdk) {
+ dillTarget.read(
+ Uri.base.resolve(Platform.resolvedExecutable).resolve('platform.dill'));
+ }
+ await dillTarget.writeOutline(null);
+ var program = await kernelTarget.writeOutline(null);
+ program = await kernelTarget.writeProgram(null, AstKind.Kernel);
+ if (kernelTarget.errors.isNotEmpty) {
+ throw kernelTarget.errors.first;
+ }
+ timer.stop();
+ report('kernel_gen_e2e', timer.elapsedMicroseconds);
+ return program;
+}
+
+/// Report that metric [name] took [time] micro-seconds to process
+/// [inputSize] characters.
+void report(String name, int time) {
+ var sb = new StringBuffer();
+ var padding = ' ' * (20 - name.length);
+ sb.write('$name:$padding $time us, ${time ~/ 1000} ms');
+ var invSpeed = (time * 1000 / inputSize).toStringAsFixed(2);
+ sb.write(', $invSpeed ns/char');
+ print('$sb');
+}
« no previous file with comments | « no previous file | pkg/front_end/tool/fasta_perf_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698