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

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

Issue 2339803004: entrypoint to measure performance of the analyzer frontend (Closed)
Patch Set: Created 4 years, 3 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/analyzer_cli/tool/perf_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer_cli/tool/perf.dart
diff --git a/pkg/analyzer_cli/tool/perf.dart b/pkg/analyzer_cli/tool/perf.dart
new file mode 100644
index 0000000000000000000000000000000000000000..268b0b7d3be676c86761df1dce01a848a30aa046
--- /dev/null
+++ b/pkg/analyzer_cli/tool/perf.dart
@@ -0,0 +1,169 @@
+// 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 analyzer and measure its performance.
+library analyzer_cli.tool.perf;
+
+import 'dart:io' show exit;
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/file_system/file_system.dart'
+ show ResourceProvider, ResourceUriResolver
+ hide File;
+import 'package:analyzer/file_system/physical_file_system.dart'
+ show PhysicalResourceProvider;
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk;
+import 'package:analyzer/src/error.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_io.dart' show JavaFile;
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+
+/// Cummulative total number of chars scanned.
+int scanTotalChars = 0;
+
+/// Cummulative time spent scanning.
+Stopwatch scanTimer = new Stopwatch();
+
+/// Factory to load and resolve app, packages, and sdk sources.
+SourceFactory sources;
+
+main(args) {
+ // TODO(sigmund): provide sdk folder as well.
+ if (args.length < 2) {
+ print('usage: perf.dart <bench-id> <package-root> <entry.dart>');
+ exit(1);
+ }
+ var totalTimer = new Stopwatch()..start();
+
+ var bench = args[0];
+ var packageRoot = args[1];
+ var entryUri = Uri.base.resolve(args[2]);
+
+ setup(packageRoot);
+ if (bench == 'scan') {
+ scanReachableFiles(entryUri);
+ } else if (bench == 'parse') {
+ Set<Source> files = scanReachableFiles(entryUri);
+ 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);
+}
+
+/// Sets up analyzer to be able to load and resolve app, packages, and sdk
+/// sources.
+void setup(String packageRoot) {
+ var provider = PhysicalResourceProvider.INSTANCE;
+ sources = new SourceFactory([
+ new ResourceUriResolver(provider),
+ new PackageUriResolver([new JavaFile(packageRoot)]),
+ new DartUriResolver(
+ new FolderBasedDartSdk(provider, provider.getFolder("sdk"))),
+ ]);
+}
+
+/// Load and scans all files we need to process: files reachable from the
+/// entrypoint and all core libraries automatically included by the VM.
+Set<Source> scanReachableFiles(Uri entryUri) {
+ var files = new Set<Source>();
+ var loadTimer = new Stopwatch()..start();
+ collectSources(sources.forUri2(entryUri), files);
+ collectSources(sources.forUri("dart:async"), files);
+ collectSources(sources.forUri("dart:collection"), files);
+ collectSources(sources.forUri("dart:convert"), files);
+ collectSources(sources.forUri("dart:core"), files);
+ collectSources(sources.forUri("dart:developer"), files);
+ collectSources(sources.forUri("dart:_internal"), files);
+ collectSources(sources.forUri("dart:isolate"), files);
+ collectSources(sources.forUri("dart:math"), files);
+ collectSources(sources.forUri("dart:mirrors"), files);
+ collectSources(sources.forUri("dart:typed_data"), files);
+ loadTimer.stop();
+
+ print('input size: ${scanTotalChars} chars');
+ var loadTime = loadTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
+ report("Loader", loadTime);
+ report("Scanner", scanTimer.elapsedMicroseconds);
+ return files;
+}
+
+/// Parses every file in [files] and reports the time spent doing so.
+void parseFiles(Set<Source> 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 oldTotal = 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 (oldTotal != scanTotalChars) print('input size changed? ${total} chars');
+ report("Scanner", scanTimer.elapsedMicroseconds);
+
+ var pTime = parseTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
+ report("Parser", pTime);
+}
+
+/// Add to [files] all sources reachable from [start].
+void collectSources(Source start, Set<Source> files) {
+ if (!files.add(start)) return;
+ var unit = parseDirectives(start);
+ for (var directive in unit.directives) {
+ if (directive is! UriBasedDirective) continue;
+ var next = sources.resolveUri(start, directive.uri.stringValue);
Brian Wilkerson 2016/09/16 15:32:02 This introduces a compilation error: ERROR: The g
+ collectSources(next, files);
+ }
+}
+
+/// Uses the diet-parser to parse only directives in [source].
+CompilationUnit parseDirectives(Source source) {
+ var token = tokenize(source);
+ var parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
+ return parser.parseDirectives(token);
+}
+
+/// Parse the full body of [source] and return it's compilation unit.
+CompilationUnit parseFull(Source source) {
+ var token = tokenize(source);
+ var parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
+ return parser.parseCompilationUnit(token);
+}
+
+/// Scan [source] and return the first token produced by the scanner.
+Token tokenize(Source source) {
+ scanTimer.start();
+ var contents = source.contents.data;
+ scanTotalChars += contents.length;
+ // TODO(sigmund): is there a way to scan from a random-access-file without
+ // first converting to String?
+ var scanner = new Scanner(source, new CharSequenceReader(contents),
+ AnalysisErrorListener.NULL_LISTENER);
+ var token = scanner.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 ~/ 1000} ms');
+ sb.write(', ${scanTotalChars * 1000 ~/ time} chars/ms');
+ print('$sb');
+}
« no previous file with comments | « no previous file | pkg/analyzer_cli/tool/perf_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698