| 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 front_end and measure its performance. | 5 /// An entrypoint used to run portions of front_end and measure its performance. |
| 6 library front_end.tool.perf; | 6 library front_end.tool.perf; |
| 7 | 7 |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 import 'dart:io' show exit, stderr; | 9 import 'dart:io' show exit, stderr; |
| 10 | 10 |
| 11 import 'package:analyzer/dart/ast/ast.dart'; | 11 import 'package:analyzer/dart/ast/ast.dart'; |
| 12 import 'package:analyzer/error/listener.dart'; | 12 import 'package:analyzer/error/listener.dart'; |
| 13 import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver; | 13 import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver; |
| 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'; | 16 import 'package:analyzer/source/package_map_resolver.dart'; |
| 17 import 'package:analyzer/src/context/builder.dart'; | 17 import 'package:analyzer/src/context/builder.dart'; |
| 18 import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk; | 18 import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk; |
| 19 import 'package:analyzer/src/generated/parser.dart'; | 19 import 'package:analyzer/src/generated/parser.dart'; |
| 20 import 'package:analyzer/src/generated/source.dart'; | 20 import 'package:analyzer/src/generated/source.dart'; |
| 21 import 'package:analyzer/src/generated/source_io.dart'; | 21 import 'package:analyzer/src/generated/source_io.dart'; |
| 22 import 'package:analyzer/src/summary/format.dart'; | 22 import 'package:analyzer/src/summary/format.dart'; |
| 23 import 'package:analyzer/src/summary/idl.dart'; | 23 import 'package:analyzer/src/summary/idl.dart'; |
| 24 import 'package:analyzer/src/summary/prelink.dart'; | 24 import 'package:analyzer/src/summary/link.dart'; |
| 25 import 'package:analyzer/src/summary/summarize_ast.dart'; | 25 import 'package:analyzer/src/summary/summarize_ast.dart'; |
| 26 import 'package:kernel/analyzer/loader.dart'; | 26 import 'package:kernel/analyzer/loader.dart'; |
| 27 import 'package:kernel/kernel.dart'; | 27 import 'package:kernel/kernel.dart'; |
| 28 import 'package:package_config/discovery.dart'; | 28 import 'package:package_config/discovery.dart'; |
| 29 | 29 |
| 30 import 'package:front_end/src/scanner/reader.dart'; | 30 import 'package:front_end/src/scanner/reader.dart'; |
| 31 import 'package:front_end/src/scanner/scanner.dart'; | 31 import 'package:front_end/src/scanner/scanner.dart'; |
| 32 import 'package:front_end/src/scanner/token.dart'; | 32 import 'package:front_end/src/scanner/token.dart'; |
| 33 | 33 |
| 34 /// Cumulative total number of chars scanned. | 34 /// Cumulative total number of chars scanned. |
| 35 int scanTotalChars = 0; | 35 int scanTotalChars = 0; |
| 36 | 36 |
| 37 /// Cumulative time spent scanning. | 37 /// Cumulative time spent scanning. |
| 38 Stopwatch scanTimer = new Stopwatch(); | 38 Stopwatch scanTimer = new Stopwatch(); |
| 39 | 39 |
| 40 /// Cumulative time spent parsing. | 40 /// Cumulative time spent parsing. |
| 41 Stopwatch parseTimer = new Stopwatch(); | 41 Stopwatch parseTimer = new Stopwatch(); |
| 42 | 42 |
| 43 /// Cumulative time spent building unlinked summaries. | 43 /// Cumulative time spent building unlinked summaries. |
| 44 Stopwatch unlinkedSummarizeTimer = new Stopwatch(); | 44 Stopwatch unlinkedSummarizeTimer = new Stopwatch(); |
| 45 | 45 |
| 46 /// Cumulative time spent prelinking summaries. |
| 47 Stopwatch prelinkSummaryTimer = new Stopwatch(); |
| 48 |
| 46 /// Factory to load and resolve app, packages, and sdk sources. | 49 /// Factory to load and resolve app, packages, and sdk sources. |
| 47 SourceFactory sources; | 50 SourceFactory sources; |
| 48 | 51 |
| 49 main(List<String> args) async { | 52 main(List<String> args) async { |
| 50 // TODO(sigmund): provide sdk folder as well. | 53 // TODO(sigmund): provide sdk folder as well. |
| 51 if (args.length < 2) { | 54 if (args.length < 2) { |
| 52 print('usage: perf.dart <bench-id> <entry.dart>'); | 55 print('usage: perf.dart <bench-id> <entry.dart>'); |
| 53 exit(1); | 56 exit(1); |
| 54 } | 57 } |
| 55 var totalTimer = new Stopwatch()..start(); | 58 var totalTimer = new Stopwatch()..start(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 81 }, | 84 }, |
| 82 'unlinked_summarize': () async { | 85 'unlinked_summarize': () async { |
| 83 Set<Source> files = scanReachableFiles(entryUri); | 86 Set<Source> files = scanReachableFiles(entryUri); |
| 84 // TODO(sigmund): replace the warmup with instrumented snapshots. | 87 // TODO(sigmund): replace the warmup with instrumented snapshots. |
| 85 for (int i = 0; i < 10; i++) unlinkedSummarizeFiles(files); | 88 for (int i = 0; i < 10; i++) unlinkedSummarizeFiles(files); |
| 86 }, | 89 }, |
| 87 'prelinked_summarize': () async { | 90 'prelinked_summarize': () async { |
| 88 Set<Source> files = scanReachableFiles(entryUri); | 91 Set<Source> files = scanReachableFiles(entryUri); |
| 89 // TODO(sigmund): replace the warmup with instrumented snapshots. | 92 // TODO(sigmund): replace the warmup with instrumented snapshots. |
| 90 for (int i = 0; i < 10; i++) prelinkedSummarizeFiles(files); | 93 for (int i = 0; i < 10; i++) prelinkedSummarizeFiles(files); |
| 94 }, |
| 95 'linked_summarize': () async { |
| 96 Set<Source> files = scanReachableFiles(entryUri); |
| 97 // TODO(sigmund): replace the warmup with instrumented snapshots. |
| 98 for (int i = 0; i < 10; i++) linkedSummarizeFiles(files); |
| 91 } | 99 } |
| 92 }; | 100 }; |
| 93 | 101 |
| 94 var handler = handlers[bench]; | 102 var handler = handlers[bench]; |
| 95 if (handler == null) { | 103 if (handler == null) { |
| 96 // TODO(sigmund): implement the remaining benchmarks. | 104 // TODO(sigmund): implement the remaining benchmarks. |
| 97 print('unsupported bench-id: $bench. Please specify one of the following: ' | 105 print('unsupported bench-id: $bench. Please specify one of the following: ' |
| 98 '${handlers.keys.join(", ")}'); | 106 '${handlers.keys.join(", ")}'); |
| 99 exit(1); | 107 exit(1); |
| 100 } | 108 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 void unlinkedSummarizeFiles(Set<Source> files) { | 203 void unlinkedSummarizeFiles(Set<Source> files) { |
| 196 // The code below will record again how many chars are scanned and how long it | 204 // The code below will record again how many chars are scanned and how long it |
| 197 // takes to scan them, even though we already did so in [scanReachableFiles]. | 205 // takes to scan them, even though we already did so in [scanReachableFiles]. |
| 198 // Recording and reporting this twice is unnecessary, but we do so for now to | 206 // Recording and reporting this twice is unnecessary, but we do so for now to |
| 199 // validate that the results are consistent. | 207 // validate that the results are consistent. |
| 200 scanTimer = new Stopwatch(); | 208 scanTimer = new Stopwatch(); |
| 201 var old = scanTotalChars; | 209 var old = scanTotalChars; |
| 202 scanTotalChars = 0; | 210 scanTotalChars = 0; |
| 203 parseTimer = new Stopwatch(); | 211 parseTimer = new Stopwatch(); |
| 204 unlinkedSummarizeTimer = new Stopwatch(); | 212 unlinkedSummarizeTimer = new Stopwatch(); |
| 205 for (var source in files) { | 213 generateUnlinkedSummaries(files); |
| 206 unlinkedSummarize(source); | |
| 207 } | |
| 208 | 214 |
| 209 if (old != scanTotalChars) print('input size changed? ${old} chars'); | 215 if (old != scanTotalChars) print('input size changed? ${old} chars'); |
| 210 report("scan", scanTimer.elapsedMicroseconds); | 216 report("scan", scanTimer.elapsedMicroseconds); |
| 211 report("parse", parseTimer.elapsedMicroseconds); | 217 report("parse", parseTimer.elapsedMicroseconds); |
| 212 report('unlinked summarize', unlinkedSummarizeTimer.elapsedMicroseconds); | 218 report('unlinked summarize', unlinkedSummarizeTimer.elapsedMicroseconds); |
| 213 report( | 219 report( |
| 214 'unlinked summarize + parse', | 220 'unlinked summarize + parse', |
| 215 unlinkedSummarizeTimer.elapsedMicroseconds + | 221 unlinkedSummarizeTimer.elapsedMicroseconds + |
| 216 parseTimer.elapsedMicroseconds); | 222 parseTimer.elapsedMicroseconds); |
| 217 } | 223 } |
| 218 | 224 |
| 225 /// Simple container for a mapping from URI string to an unlinked summary. |
| 226 class UnlinkedSummaries { |
| 227 final summariesByUri = <String, UnlinkedUnit>{}; |
| 228 |
| 229 /// Get the unlinked summary for the given URI, and report a warning if it |
| 230 /// can't be found. |
| 231 UnlinkedUnit getUnit(String uri) { |
| 232 var result = summariesByUri[uri]; |
| 233 if (result == null) { |
| 234 print('Warning: no summary found for: $uri'); |
| 235 } |
| 236 return result; |
| 237 } |
| 238 } |
| 239 |
| 240 /// Generates unlinkmed summaries for all files in [files], and returns them in |
| 241 /// an [UnlinkedSummaries] container. |
| 242 UnlinkedSummaries generateUnlinkedSummaries(Set<Source> files) { |
| 243 var unlinkedSummaries = new UnlinkedSummaries(); |
| 244 for (var source in files) { |
| 245 unlinkedSummaries.summariesByUri[source.uri.toString()] = |
| 246 unlinkedSummarize(source); |
| 247 } |
| 248 return unlinkedSummaries; |
| 249 } |
| 250 |
| 219 /// Produces prelinked summaries for every file in [files] and reports the time | 251 /// Produces prelinked summaries for every file in [files] and reports the time |
| 220 /// spent doing so. | 252 /// spent doing so. |
| 221 void prelinkedSummarizeFiles(Set<Source> files) { | 253 void prelinkedSummarizeFiles(Set<Source> files) { |
| 222 // The code below will record again how many chars are scanned and how long it | 254 // The code below will record again how many chars are scanned and how long it |
| 223 // takes to scan them, even though we already did so in [scanReachableFiles]. | 255 // takes to scan them, even though we already did so in [scanReachableFiles]. |
| 224 // Recording and reporting this twice is unnecessary, but we do so for now to | 256 // Recording and reporting this twice is unnecessary, but we do so for now to |
| 225 // validate that the results are consistent. | 257 // validate that the results are consistent. |
| 226 scanTimer = new Stopwatch(); | 258 scanTimer = new Stopwatch(); |
| 227 var old = scanTotalChars; | 259 var old = scanTotalChars; |
| 228 scanTotalChars = 0; | 260 scanTotalChars = 0; |
| 229 parseTimer = new Stopwatch(); | 261 parseTimer = new Stopwatch(); |
| 230 unlinkedSummarizeTimer = new Stopwatch(); | 262 unlinkedSummarizeTimer = new Stopwatch(); |
| 231 var unlinkedSummaries = <Source, UnlinkedUnit>{}; | 263 var unlinkedSummaries = generateUnlinkedSummaries(files); |
| 232 for (var source in files) { | 264 prelinkSummaryTimer = new Stopwatch(); |
| 233 unlinkedSummaries[source] = unlinkedSummarize(source); | 265 prelinkSummaries(files, unlinkedSummaries); |
| 234 } | |
| 235 var prelinkTimer = new Stopwatch()..start(); | |
| 236 for (var source in files) { | |
| 237 UnlinkedUnit getSummary(String uri) { | |
| 238 var resolvedUri = sources.resolveUri(source, uri); | |
| 239 var result = unlinkedSummaries[resolvedUri]; | |
| 240 if (result == null) { | |
| 241 print('Warning: no summary found for: $uri'); | |
| 242 } | |
| 243 return result; | |
| 244 } | |
| 245 | |
| 246 UnlinkedPublicNamespace getImport(String uri) => | |
| 247 getSummary(uri)?.publicNamespace; | |
| 248 String getDeclaredVariable(String s) => null; | |
| 249 prelink( | |
| 250 unlinkedSummaries[source], getSummary, getImport, getDeclaredVariable); | |
| 251 } | |
| 252 prelinkTimer.stop(); | |
| 253 | 266 |
| 254 if (old != scanTotalChars) print('input size changed? ${old} chars'); | 267 if (old != scanTotalChars) print('input size changed? ${old} chars'); |
| 255 report("scan", scanTimer.elapsedMicroseconds); | 268 report("scan", scanTimer.elapsedMicroseconds); |
| 269 report("parse", parseTimer.elapsedMicroseconds); |
| 270 report('unlinked summarize', unlinkedSummarizeTimer.elapsedMicroseconds); |
| 271 report( |
| 272 'unlinked summarize + parse', |
| 273 unlinkedSummarizeTimer.elapsedMicroseconds + |
| 274 parseTimer.elapsedMicroseconds); |
| 275 report('prelink', prelinkSummaryTimer.elapsedMicroseconds); |
| 276 } |
| 277 |
| 278 /// Produces linked summaries for every file in [files] and reports the time |
| 279 /// spent doing so. |
| 280 void linkedSummarizeFiles(Set<Source> files) { |
| 281 // The code below will record again how many chars are scanned and how long it |
| 282 // takes to scan them, even though we already did so in [scanReachableFiles]. |
| 283 // Recording and reporting this twice is unnecessary, but we do so for now to |
| 284 // validate that the results are consistent. |
| 285 scanTimer = new Stopwatch(); |
| 286 var old = scanTotalChars; |
| 287 scanTotalChars = 0; |
| 288 parseTimer = new Stopwatch(); |
| 289 unlinkedSummarizeTimer = new Stopwatch(); |
| 290 var unlinkedSummaries = generateUnlinkedSummaries(files); |
| 291 prelinkSummaryTimer = new Stopwatch(); |
| 292 Map<String, LinkedLibraryBuilder> prelinkedLibraries = |
| 293 prelinkSummaries(files, unlinkedSummaries); |
| 294 var linkTimer = new Stopwatch()..start(); |
| 295 LinkedLibrary getDependency(String uri) { |
| 296 // getDependency should never be called because all dependencies are present |
| 297 // in [prelinkedLibraries]. |
| 298 print('Warning: getDependency called for: $uri'); |
| 299 return null; |
| 300 } |
| 301 |
| 302 bool strong = true; |
| 303 relink(prelinkedLibraries, getDependency, unlinkedSummaries.getUnit, strong); |
| 304 linkTimer.stop(); |
| 305 |
| 306 if (old != scanTotalChars) print('input size changed? ${old} chars'); |
| 307 report("scan", scanTimer.elapsedMicroseconds); |
| 256 report("parse", parseTimer.elapsedMicroseconds); | 308 report("parse", parseTimer.elapsedMicroseconds); |
| 257 report('unlinked summarize', unlinkedSummarizeTimer.elapsedMicroseconds); | 309 report('unlinked summarize', unlinkedSummarizeTimer.elapsedMicroseconds); |
| 258 report( | 310 report( |
| 259 'unlinked summarize + parse', | 311 'unlinked summarize + parse', |
| 260 unlinkedSummarizeTimer.elapsedMicroseconds + | 312 unlinkedSummarizeTimer.elapsedMicroseconds + |
| 261 parseTimer.elapsedMicroseconds); | 313 parseTimer.elapsedMicroseconds); |
| 262 report('prelink', prelinkTimer.elapsedMicroseconds); | 314 report('prelink', prelinkSummaryTimer.elapsedMicroseconds); |
| 315 report('link', linkTimer.elapsedMicroseconds); |
| 316 } |
| 317 |
| 318 /// Prelinks all the summaries for [files], using [unlinkedSummaries] to obtain |
| 319 /// their unlinked summaries. |
| 320 /// |
| 321 /// The return value is suitable for passing to the summary linker. |
| 322 Map<String, LinkedLibraryBuilder> prelinkSummaries( |
| 323 Set<Source> files, UnlinkedSummaries unlinkedSummaries) { |
| 324 prelinkSummaryTimer.start(); |
| 325 Set<String> libraryUris = |
| 326 files.map((source) => source.uri.toString()).toSet(); |
| 327 |
| 328 String getDeclaredVariable(String s) => null; |
| 329 var prelinkedLibraries = |
| 330 setupForLink(libraryUris, unlinkedSummaries.getUnit, getDeclaredVariable); |
| 331 prelinkSummaryTimer.stop(); |
| 332 return prelinkedLibraries; |
| 263 } | 333 } |
| 264 | 334 |
| 265 /// Add to [files] all sources reachable from [start]. | 335 /// Add to [files] all sources reachable from [start]. |
| 266 void collectSources(Source start, Set<Source> files) { | 336 void collectSources(Source start, Set<Source> files) { |
| 267 if (!files.add(start)) return; | 337 if (!files.add(start)) return; |
| 268 var unit = parseDirectives(start); | 338 var unit = parseDirectives(start); |
| 269 for (var directive in unit.directives) { | 339 for (var directive in unit.directives) { |
| 270 if (directive is UriBasedDirective) { | 340 if (directive is UriBasedDirective) { |
| 271 var next = sources.resolveUri(start, directive.uri.stringValue); | 341 var next = sources.resolveUri(start, directive.uri.stringValue); |
| 272 collectSources(next, files); | 342 collectSources(next, files); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 const int errorLimit = 100; | 417 const int errorLimit = 100; |
| 348 stderr.writeln(errors.take(errorLimit).join('\n')); | 418 stderr.writeln(errors.take(errorLimit).join('\n')); |
| 349 if (errors.length > errorLimit) { | 419 if (errors.length > errorLimit) { |
| 350 stderr.writeln('[error] ${errors.length - errorLimit} errors not shown'); | 420 stderr.writeln('[error] ${errors.length - errorLimit} errors not shown'); |
| 351 } | 421 } |
| 352 } | 422 } |
| 353 dartkTimer.stop(); | 423 dartkTimer.stop(); |
| 354 report("kernel_gen_e2e", dartkTimer.elapsedMicroseconds); | 424 report("kernel_gen_e2e", dartkTimer.elapsedMicroseconds); |
| 355 return program; | 425 return program; |
| 356 } | 426 } |
| OLD | NEW |