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