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

Unified Diff: pkg/compiler/tool/perf.dart

Issue 2385893002: Create entrypoint to measure performance of the dart2js frontend (Closed)
Patch Set: Cl comments Created 4 years, 2 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/compiler/tool/perf_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/tool/perf.dart
diff --git a/pkg/compiler/tool/perf.dart b/pkg/compiler/tool/perf.dart
new file mode 100644
index 0000000000000000000000000000000000000000..51f98d61021901b04ac80ef5644223be97e48c82
--- /dev/null
+++ b/pkg/compiler/tool/perf.dart
@@ -0,0 +1,319 @@
+// Copyright (c) 2016, 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 dart2js and measure its performance.
+library compiler.tool.perf;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:compiler/compiler_new.dart';
+import 'package:compiler/src/common.dart';
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
+import 'package:compiler/src/diagnostics/messages.dart'
+ show Message, MessageTemplate;
+import 'package:compiler/src/io/source_file.dart';
+import 'package:compiler/src/options.dart' show ParserOptions;
+import 'package:compiler/src/options.dart';
+import 'package:compiler/src/parser/element_listener.dart' show ScannerOptions;
+import 'package:compiler/src/parser/listener.dart';
+import 'package:compiler/src/parser/node_listener.dart' show NodeListener;
+import 'package:compiler/src/parser/parser.dart' show Parser;
+import 'package:compiler/src/parser/partial_parser.dart';
+import 'package:compiler/src/platform_configuration.dart' as platform;
+import 'package:compiler/src/scanner/scanner.dart';
+import 'package:compiler/src/source_file_provider.dart';
+import 'package:compiler/src/tokens/token.dart' show Token;
+import 'package:package_config/discovery.dart' show findPackages;
+import 'package:package_config/packages.dart' show Packages;
+import 'package:package_config/src/util.dart' show checkValidPackageUri;
+
+/// Cumulative total number of chars scanned.
+int scanTotalChars = 0;
+
+/// Cumulative time spent scanning.
+Stopwatch scanTimer = new Stopwatch();
+
+/// Helper class used to load source files using dart2js's internal APIs.
+_Loader loader;
+
+main(List<String> args) async {
+ // TODO(sigmund): provide sdk folder as well.
+ if (args.length < 2) {
+ print('usage: perf.dart <bench-id> <entry.dart>');
+ exit(1);
+ }
+ var totalTimer = new Stopwatch()..start();
+
+ var bench = args[0];
+ var entryUri = Uri.base.resolve(args[1]);
+
+ await setup(entryUri);
+
+ if (bench == 'scan') {
+ Set<SourceFile> files = await scanReachableFiles(entryUri);
+ // TODO(sigmund): consider replacing the warmup with instrumented snapshots.
+ for (int i = 0; i < 10; i++) scanFiles(files);
+ } else if (bench == 'parse') {
+ Set<SourceFile> files = await scanReachableFiles(entryUri);
+ // TODO(sigmund): consider replacing the warmup with instrumented snapshots.
+ for (int i = 0; i < 10; i++) parseFiles(files);
+ } else {
+ print('unsupported bench-id: $bench. Please specify "scan" or "parse"');
+ // TODO(sigmund): implement the remaining benchmarks.
+ exit(1);
+ }
+
+ totalTimer.stop();
+ report("total", totalTimer.elapsedMicroseconds);
+}
+
+Future setup(Uri entryUri) async {
+ var inputProvider = new CompilerSourceFileProvider();
+ var sdkLibraries = await platform.load(_platformConfigUri, inputProvider);
+ var packages = await findPackages(entryUri);
+ loader = new _Loader(inputProvider, sdkLibraries, packages);
+}
+
+/// Load and scans all files we need to process: files reachable from the
+/// entrypoint and all core libraries automatically included by the VM.
+Future<Set<SourceFile>> scanReachableFiles(Uri entryUri) async {
+ var files = new Set<SourceFile>();
+ var loadTimer = new Stopwatch()..start();
+ var entrypoints = [
+ entryUri,
+ 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(await loader.loadFile(entry), files);
+ }
+ loadTimer.stop();
+
+ print('input size: ${scanTotalChars} chars');
+ var loadTime = loadTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
+ report("load", loadTime);
+ report("scan", scanTimer.elapsedMicroseconds);
+ return files;
+}
+
+/// Scans every file in [files] and reports the time spent doing so.
+void scanFiles(Set<SourceFile> files) {
+ // The code below will record again how many chars are scanned and how long it
+ // takes to scan them, even though we already did so in [scanReachableFiles].
+ // Recording and reporting this twice is unnecessary, but we do so for now to
+ // validate that the results are consistent.
+ scanTimer = new Stopwatch();
+ var old = scanTotalChars;
+ scanTotalChars = 0;
+ for (var source in files) {
+ tokenize(source);
+ }
+
+ // Report size and scanning time again. See discussion above.
+ if (old != scanTotalChars) print('input size changed? ${old} chars');
+ report("scan", scanTimer.elapsedMicroseconds);
+}
+
+/// Parses every file in [files] and reports the time spent doing so.
+void parseFiles(Set<SourceFile> files) {
+ // The code below will record again how many chars are scanned and how long it
+ // takes to scan them, even though we already did so in [scanReachableFiles].
+ // Recording and reporting this twice is unnecessary, but we do so for now to
+ // validate that the results are consistent.
+ scanTimer = new Stopwatch();
+ var old = scanTotalChars;
+ scanTotalChars = 0;
+ var parseTimer = new Stopwatch()..start();
+ for (var source in files) {
+ parseFull(source);
+ }
+ parseTimer.stop();
+
+ // Report size and scanning time again. See discussion above.
+ if (old != scanTotalChars) print('input size changed? ${old} chars');
+ report("scan", scanTimer.elapsedMicroseconds);
+
+ report(
+ "parse", parseTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds);
+}
+
+/// Add to [files] all sources reachable from [start].
+Future collectSources(SourceFile start, Set<SourceFile> files) async {
+ if (!files.add(start)) return;
+ for (var directive in parseDirectives(start)) {
+ var next = await loader.loadFile(start.uri.resolve(directive));
+ await collectSources(next, files);
+ }
+}
+
+/// Uses the diet-parser to parse only directives in [source], returns the
+/// URIs seen in import/export/part directives in the file.
+Set<String> parseDirectives(SourceFile source) {
+ var tokens = tokenize(source);
+ var listener = new DirectiveListener();
+ new PartialParser(listener, const _ParserOptions()).parseUnit(tokens);
+ return listener.targets;
+}
+
+/// Parse the full body of [source].
+parseFull(SourceFile source) {
+ var tokens = tokenize(source);
+ NodeListener listener = new NodeListener(
+ const ScannerOptions(canUseNative: true), new FakeReporter(), null);
+ Parser parser = new Parser(listener, const _ParserOptions());
+ parser.parseUnit(tokens);
+ return listener.popNode();
+}
+
+/// Scan [source] and return the first token produced by the scanner.
+Token tokenize(SourceFile source) {
+ scanTimer.start();
+ scanTotalChars += source.length;
+ var token = new Scanner(source).tokenize();
+ scanTimer.stop();
+ return token;
+}
+
+/// Report that metric [name] took [time] micro-seconds to process
+/// [scanTotalChars] characters.
+void report(String name, int time) {
+ var sb = new StringBuffer();
+ sb.write('$name: $time us, ${time ~/ 1000} ms');
+ sb.write(', ${scanTotalChars * 1000 ~/ time} chars/ms');
+ print('$sb');
+}
+
+/// Listener that parses out just the uri in imports, exports, and part
+/// directives.
+class DirectiveListener extends Listener {
+ Set<String> targets = new Set<String>();
+
+ bool inDirective = false;
+ void enterDirective() {
+ inDirective = true;
+ }
+
+ void exitDirective() {
+ inDirective = false;
+ }
+
+ void beginImport(Token importKeyword) => enterDirective();
+ void beginExport(Token token) => enterDirective();
+ void beginPart(Token token) => enterDirective();
+
+ void beginLiteralString(Token token) {
+ if (inDirective) {
+ var quotedString = token.value;
+ targets.add(quotedString.substring(1, quotedString.length - 1));
+ }
+ }
+
+ void endExport(Token exportKeyword, Token semicolon) => exitDirective();
+ void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
+ Token semicolon) =>
+ exitDirective();
+ void endPart(Token partKeyword, Token semicolon) => exitDirective();
+}
+
+Uri _libraryRoot = Platform.script.resolve('../../../sdk/');
+Uri _platformConfigUri = _libraryRoot.resolve("lib/dart_server.platform");
+
+class FakeReporter extends DiagnosticReporter {
+ final hasReportedError = false;
+ final options = new FakeReporterOptions();
+
+ withCurrentElement(e, f) => f();
+ log(m) => print(m);
+ internalError(_, m) => print(m);
+ spanFromSpannable(_) => null;
+
+ void reportError(DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ print('error: ${message.message}');
+ }
+
+ void reportWarning(DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ print('warning: ${message.message}');
+ }
+
+ void reportHint(DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ print('hint: ${message.message}');
+ }
+
+ void reportInfo(_, __, [Map arguments = const {}]) {}
+
+ DiagnosticMessage createMessage(_, MessageKind kind,
+ [Map arguments = const {}]) {
+ MessageTemplate template = MessageTemplate.TEMPLATES[kind];
+ Message message = template.message(arguments, false);
+ return new DiagnosticMessage(null, null, message);
+ }
+}
+
+class FakeReporterOptions {
+ bool get suppressHints => false;
+ bool get hidePackageWarnings => false;
+}
+
+class _Loader {
+ CompilerInput inputProvider;
+
+ /// Maps dart-URIs to a known location in the sdk.
+ Map<String, Uri> sdkLibraries;
+ Map<Uri, SourceFile> _cache = {};
+ Packages packages;
+
+ _Loader(this.inputProvider, this.sdkLibraries, this.packages);
+
+ Future<SourceFile> loadFile(Uri uri) async {
+ if (!uri.isAbsolute) throw 'Relative uri $uri provided to readScript.';
+ Uri resourceUri = _translateUri(uri);
+ if (resourceUri == null || resourceUri.scheme == 'dart-ext') {
+ throw '$uri not resolved or unsupported.';
+ }
+ var file = _cache[resourceUri];
+ if (file != null) return _cache[resourceUri];
+ return _cache[resourceUri] = await _readFile(resourceUri);
+ }
+
+ Future<SourceFile> _readFile(Uri uri) async {
+ var data = await inputProvider.readFromUri(uri);
+ if (data is List<int>) return new Utf8BytesSourceFile(uri, data);
+ if (data is String) return new StringSourceFile.fromUri(uri, data);
+ // TODO(sigmund): properly handle errors, just report, return null, wrap
+ // above and continue...
+ throw "Expected a 'String' or a 'List<int>' from the input "
+ "provider, but got: ${data.runtimeType}.";
+ }
+
+ Uri _translateUri(Uri uri) {
+ if (uri.scheme == 'dart') return sdkLibraries[uri.path];
+ if (uri.scheme == 'package') return _translatePackageUri(uri);
+ return uri;
+ }
+
+ Uri _translatePackageUri(Uri uri) {
+ checkValidPackageUri(uri);
+ return packages.resolve(uri, notFound: (_) {
+ print('$uri not found');
+ });
+ }
+}
+
+class _ParserOptions implements ParserOptions {
+ const _ParserOptions();
+ bool get enableGenericMethodSyntax => true;
+}
« no previous file with comments | « no previous file | pkg/compiler/tool/perf_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698