Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /// An entrypoint used to run portions of analyzer and measure its performance. | |
| 6 library analyzer_cli.tool.perf; | |
| 7 | |
| 8 import 'dart:io' show exit; | |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | |
| 10 import 'package:analyzer/dart/ast/token.dart'; | |
| 11 import 'package:analyzer/file_system/file_system.dart' | |
| 12 show ResourceProvider, ResourceUriResolver | |
| 13 hide File; | |
| 14 import 'package:analyzer/file_system/physical_file_system.dart' | |
| 15 show PhysicalResourceProvider; | |
| 16 import 'package:analyzer/src/dart/scanner/reader.dart'; | |
| 17 import 'package:analyzer/src/dart/scanner/scanner.dart'; | |
| 18 import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk; | |
| 19 import 'package:analyzer/src/error.dart'; | |
| 20 import 'package:analyzer/src/generated/error.dart'; | |
| 21 import 'package:analyzer/src/generated/java_io.dart' show JavaFile; | |
| 22 import 'package:analyzer/src/generated/parser.dart'; | |
| 23 import 'package:analyzer/src/generated/source.dart'; | |
| 24 import 'package:analyzer/src/generated/source_io.dart'; | |
| 25 | |
| 26 /// Cummulative total number of chars scanned. | |
| 27 int scanTotalChars = 0; | |
| 28 | |
| 29 /// Cummulative time spent scanning. | |
| 30 Stopwatch scanTimer = new Stopwatch(); | |
| 31 | |
| 32 /// Factory to load and resolve app, packages, and sdk sources. | |
| 33 SourceFactory sources; | |
| 34 | |
| 35 main(args) { | |
| 36 // TODO(sigmund): provide sdk folder as well. | |
| 37 if (args.length < 2) { | |
| 38 print('usage: perf.dart <bench-id> <package-root> <entry.dart>'); | |
| 39 exit(1); | |
| 40 } | |
| 41 var totalTimer = new Stopwatch()..start(); | |
| 42 | |
| 43 var bench = args[0]; | |
| 44 var packageRoot = args[1]; | |
| 45 var entryUri = Uri.base.resolve(args[2]); | |
| 46 | |
| 47 setup(packageRoot); | |
| 48 if (bench == 'scan') { | |
| 49 scanReachableFiles(entryUri); | |
| 50 } else if (bench == 'parse') { | |
| 51 Set<Source> files = scanReachableFiles(entryUri); | |
| 52 parseFiles(files); | |
| 53 } else { | |
| 54 print('unsupported bench-id: $bench. Please specify "scan" or "parse"'); | |
| 55 // TODO(sigmund): implement the remaining benchmarks. | |
| 56 exit(1); | |
| 57 } | |
| 58 | |
| 59 totalTimer.stop(); | |
| 60 report("Total", totalTimer.elapsedMicroseconds); | |
| 61 } | |
| 62 | |
| 63 /// Sets up analyzer to be able to load and resolve app, packages, and sdk | |
| 64 /// sources. | |
| 65 void setup(String packageRoot) { | |
| 66 var provider = PhysicalResourceProvider.INSTANCE; | |
| 67 sources = new SourceFactory([ | |
| 68 new ResourceUriResolver(provider), | |
| 69 new PackageUriResolver([new JavaFile(packageRoot)]), | |
| 70 new DartUriResolver( | |
| 71 new FolderBasedDartSdk(provider, provider.getFolder("sdk"))), | |
| 72 ]); | |
| 73 } | |
| 74 | |
| 75 /// Load and scans all files we need to process: files reachable from the | |
| 76 /// entrypoint and all core libraries automatically included by the VM. | |
| 77 Set<Source> scanReachableFiles(Uri entryUri) { | |
| 78 var files = new Set<Source>(); | |
| 79 var loadTimer = new Stopwatch()..start(); | |
| 80 collectSources(sources.forUri2(entryUri), files); | |
| 81 collectSources(sources.forUri("dart:async"), files); | |
| 82 collectSources(sources.forUri("dart:collection"), files); | |
| 83 collectSources(sources.forUri("dart:convert"), files); | |
| 84 collectSources(sources.forUri("dart:core"), files); | |
| 85 collectSources(sources.forUri("dart:developer"), files); | |
| 86 collectSources(sources.forUri("dart:_internal"), files); | |
| 87 collectSources(sources.forUri("dart:isolate"), files); | |
| 88 collectSources(sources.forUri("dart:math"), files); | |
| 89 collectSources(sources.forUri("dart:mirrors"), files); | |
| 90 collectSources(sources.forUri("dart:typed_data"), files); | |
| 91 loadTimer.stop(); | |
| 92 | |
| 93 print('input size: ${scanTotalChars} chars'); | |
| 94 var loadTime = loadTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds; | |
| 95 report("Loader", loadTime); | |
| 96 report("Scanner", scanTimer.elapsedMicroseconds); | |
| 97 return files; | |
| 98 } | |
| 99 | |
| 100 /// Parses every file in [files] and reports the time spent doing so. | |
| 101 void parseFiles(Set<Source> files) { | |
| 102 // The code below will record again how many chars are scanned and how long it | |
| 103 // takes to scan them, even though we already did so in [scanReachableFiles]. | |
| 104 // Recording and reporting this twice is unnecessary, but we do so for now to | |
| 105 // validate that the results are consistent. | |
| 106 scanTimer = new Stopwatch(); | |
| 107 var oldTotal = scanTotalChars; | |
| 108 scanTotalChars = 0; | |
| 109 var parseTimer = new Stopwatch()..start(); | |
| 110 for (var source in files) { | |
| 111 parseFull(source); | |
| 112 } | |
| 113 parseTimer.stop(); | |
| 114 | |
| 115 // Report size and scanning time again. See discussion above. | |
| 116 if (oldTotal != scanTotalChars) print('input size changed? ${total} chars'); | |
| 117 report("Scanner", scanTimer.elapsedMicroseconds); | |
| 118 | |
| 119 var pTime = parseTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds; | |
| 120 report("Parser", pTime); | |
| 121 } | |
| 122 | |
| 123 /// Add to [files] all sources reachable from [start]. | |
| 124 void collectSources(Source start, Set<Source> files) { | |
| 125 if (!files.add(start)) return; | |
| 126 var unit = parseDirectives(start); | |
| 127 for (var directive in unit.directives) { | |
| 128 if (directive is! UriBasedDirective) continue; | |
| 129 var next = sources.resolveUri(start, directive.uri.stringValue); | |
|
Brian Wilkerson
2016/09/16 15:32:02
This introduces a compilation error:
ERROR: The g
| |
| 130 collectSources(next, files); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 /// Uses the diet-parser to parse only directives in [source]. | |
| 135 CompilationUnit parseDirectives(Source source) { | |
| 136 var token = tokenize(source); | |
| 137 var parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER); | |
| 138 return parser.parseDirectives(token); | |
| 139 } | |
| 140 | |
| 141 /// Parse the full body of [source] and return it's compilation unit. | |
| 142 CompilationUnit parseFull(Source source) { | |
| 143 var token = tokenize(source); | |
| 144 var parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER); | |
| 145 return parser.parseCompilationUnit(token); | |
| 146 } | |
| 147 | |
| 148 /// Scan [source] and return the first token produced by the scanner. | |
| 149 Token tokenize(Source source) { | |
| 150 scanTimer.start(); | |
| 151 var contents = source.contents.data; | |
| 152 scanTotalChars += contents.length; | |
| 153 // TODO(sigmund): is there a way to scan from a random-access-file without | |
| 154 // first converting to String? | |
| 155 var scanner = new Scanner(source, new CharSequenceReader(contents), | |
| 156 AnalysisErrorListener.NULL_LISTENER); | |
| 157 var token = scanner.tokenize(); | |
| 158 scanTimer.stop(); | |
| 159 return token; | |
| 160 } | |
| 161 | |
| 162 /// Report that metric [name] took [time] micro-seconds to process | |
| 163 /// [scanTotalChars] characters. | |
| 164 void report(String name, int time) { | |
| 165 var sb = new StringBuffer(); | |
| 166 sb.write('$name: ${time ~/ 1000} ms'); | |
| 167 sb.write(', ${scanTotalChars * 1000 ~/ time} chars/ms'); | |
| 168 print('$sb'); | |
| 169 } | |
| OLD | NEW |