diff --git a/.gitignore b/.gitignore index cec5b50..cb088b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .buildlog .DS_Store .idea +*.iml .pub/ .settings/ build/ diff --git a/README.md b/README.md index 667ac96..e04a96b 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,10 @@ The following tools are a available today: was split into deferred parts as expected. This tool takes a specification of the expected layout of code into deferred parts, and checks that the output from `dart2js` meets the specification. + + * [`deferred_library_size`][deferred_size]: a tool that gives a breakdown of + the sizes of the deferred parts of the program. This can show how much of + your total code size can be loaded deferred. * [`function_size_analysis`][function_analysis]: a tool that shows how much code was attributed to each function. This tool also uses dependency @@ -240,6 +244,32 @@ are the same as the name given to the deferred import in the dart file. For instance, if you have `import 'package:foo/bar.dart' deferred as baz;` in your dart file, then the corresponding name in the specification file is 'baz'. +### Deferred library size tool + +This tool gives a breakdown of all of the deferred code in the program by size. +It can show how much of the total code size is deferred. It can be run as +follows: + +```bash +pub global activate dart2js_info # only needed once +dart2js_info_deferred_library_size out.js.info.json +``` + +The tool will output a table listing all of the deferred imports in the program +as well as the "main" chunk, which is not deferred. The output looks like: + +``` +Size by library +------------------------------------------------ +main 12345678 +foo 7654321 +bar 1234567 +------------------------------------------------ +Main chunk size 12345678 +Deferred code size 8888888 +Percent of code deferred 41.86% +``` + ### Function size analysis tool This command-line tool presents how much each function contributes to the total @@ -321,6 +351,7 @@ bugs at the [issue tracker][tracker]. [code_deps]: https://github.com/dart-lang/dart2js_info/blob/master/bin/code_deps.dart [lib_split]: https://github.com/dart-lang/dart2js_info/blob/master/bin/library_size_split.dart [deferred_lib]: https://github.com/dart-lang/dart2js_info/blob/master/bin/deferred_library_check.dart +[deferred_size]: https://github.com/dart-lang/dart2js_info/blob/master/bin/deferred_library_size.dart [coverage]: https://github.com/dart-lang/dart2js_info/blob/master/bin/coverage_log_server.dart [live]: https://github.com/dart-lang/dart2js_info/blob/master/bin/live_code_size_analysis.dart [function_analysis]: https://github.com/dart-lang/dart2js_info/blob/master/bin/function_size_analysis.dart diff --git a/bin/code_deps.dart b/bin/code_deps.dart index 9899e8d..a90df78 100644 --- a/bin/code_deps.dart +++ b/bin/code_deps.dart @@ -26,14 +26,13 @@ library dart2js_info.bin.code_deps; import 'dart:collection'; -import 'dart:convert'; import 'dart:io'; import 'package:dart2js_info/info.dart'; import 'package:dart2js_info/src/graph.dart'; import 'package:dart2js_info/src/util.dart'; -main(args) { +main(args) async { if (args.length < 2) { print('usage: dart2js_info_code_deps path-to.info.json '); print(' where can be:'); @@ -42,14 +41,7 @@ main(args) { exit(1); } - var json; - try { - json = JSON.decode(new File(args[0]).readAsStringSync()); - } catch (e) { - print('error: could not read ${args[0]}'); - exit(1); - } - var info = new AllInfoJsonCodec().decode(json); + var info = await infoFromFile(args.first); var graph = graphFromInfo(info); var queryName = args[1]; diff --git a/bin/coverage_log_server.dart b/bin/coverage_log_server.dart index c19ae7a..cbab8c6 100644 --- a/bin/coverage_log_server.dart +++ b/bin/coverage_log_server.dart @@ -136,7 +136,7 @@ class _Server { } // Handle POST requests to record coverage data, and GET requests to display - // the currently coverage resutls. + // the currently coverage results. if (urlPath == _expectedPath('coverage')) { if (request.method == 'GET') { return new shelf.Response.ok(_serializedData, headers: TEXT_HEADERS); diff --git a/bin/debug_info.dart b/bin/debug_info.dart index f0dd47b..3c09114 100644 --- a/bin/debug_info.dart +++ b/bin/debug_info.dart @@ -6,23 +6,20 @@ /// that it is consistent and that it covers all the data we expect it to cover. library dart2js_info.bin.debug_info; -import 'dart:convert'; import 'dart:io'; import 'package:dart2js_info/info.dart'; import 'package:dart2js_info/src/graph.dart'; import 'package:dart2js_info/src/util.dart'; -main(args) { +main(args) async { if (args.length < 1) { print('usage: dart tool/debug_info.dart path-to-info.json ' '[--show-library libname]'); exit(1); } - var filename = args[0]; - var json = JSON.decode(new File(filename).readAsStringSync()); - var info = new AllInfoJsonCodec().decode(json); + var info = await infoFromFile(args.first); var debugLibName; if (args.length > 2 && args[1] == '--show-library') { diff --git a/bin/deferred_library_check.dart b/bin/deferred_library_check.dart index d9cd151..19cceef 100644 --- a/bin/deferred_library_check.dart +++ b/bin/deferred_library_check.dart @@ -36,11 +36,10 @@ library dart2js_info.bin.deferred_library_check; import 'dart:async'; -import 'dart:convert'; import 'dart:io'; -import 'package:dart2js_info/info.dart'; import 'package:dart2js_info/deferred_library_check.dart'; +import 'package:dart2js_info/src/util.dart'; import 'package:yaml/yaml.dart'; Future main(List args) async { @@ -56,11 +55,6 @@ Future main(List args) async { if (failures.isNotEmpty) exitCode = 1; } -Future infoFromFile(String fileName) async { - var file = await new File(fileName).readAsString(); - return new AllInfoJsonCodec().decode(JSON.decode(file)); -} - Future manifestFromFile(String fileName) async { var file = await new File(fileName).readAsString(); return loadYaml(file); diff --git a/bin/deferred_library_size.dart b/bin/deferred_library_size.dart new file mode 100644 index 0000000..349459c --- /dev/null +++ b/bin/deferred_library_size.dart @@ -0,0 +1,76 @@ +// 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. + +/// This tool gives a breakdown of code size by deferred part in the program. +library dart2js_info.bin.deferred_library_size; + +import 'dart:math'; + +import 'package:dart2js_info/info.dart'; +import 'package:dart2js_info/src/util.dart'; + +main(args) async { + // TODO(het): Would be faster to only parse the 'outputUnits' part + var info = await infoFromFile(args.first); + var sizeByImport = getSizeByImport(info); + printSizes(sizeByImport, info.program.size); +} + +class ImportSize { + final String import; + final int size; + + const ImportSize(this.import, this.size); + + String toString() { + return '$import: $size'; + } +} + +void printSizes(Map sizeByImport, int programSize) { + var importSizes = []; + sizeByImport.forEach((import, size) { + importSizes.add(new ImportSize(import, size)); + }); + // Sort by size, largest first. + importSizes.sort((a, b) => b.size - a.size); + var longest = importSizes.fold('Percent of code deferred'.length, + (longest, importSize) => max(longest, importSize.import.length)); + + _printRow(label, data, {int width: 15}) { + print('${label.toString().padRight(longest + 1)}' + '${data.toString().padLeft(width)}'); + } + + print(''); + print('Size by library'); + print('-' * (longest + 16)); + for (var importSize in importSizes) { + // TODO(het): split into specific and shared size + _printRow(importSize.import, importSize.size); + } + print('-' * (longest + 16)); + + var mainChunkSize = sizeByImport['main']; + var deferredSize = programSize - mainChunkSize; + var percentDeferred = (deferredSize * 100 / programSize).toStringAsFixed(2); + _printRow('Main chunk size', mainChunkSize); + _printRow('Deferred code size', deferredSize); + _printRow('Percent of code deferred', '$percentDeferred%'); +} + +Map getSizeByImport(AllInfo info) { + var sizeByImport = {}; + for (var outputUnit in info.outputUnits) { + if (outputUnit.name == 'main' || outputUnit.name == null) { + sizeByImport['main'] = outputUnit.size; + } else { + for (var import in outputUnit.imports) { + sizeByImport.putIfAbsent(import, () => 0); + sizeByImport[import] += outputUnit.size; + } + } + } + return sizeByImport; +} diff --git a/bin/function_size_analysis.dart b/bin/function_size_analysis.dart index 3606310..e97166d 100644 --- a/bin/function_size_analysis.dart +++ b/bin/function_size_analysis.dart @@ -6,17 +6,14 @@ /// code. library compiler.tool.live_code_size_analysis; -import 'dart:convert'; -import 'dart:io'; import 'dart:math' as math; import 'package:dart2js_info/info.dart'; import 'package:dart2js_info/src/graph.dart'; import 'package:dart2js_info/src/util.dart'; -main(args) { - var json = JSON.decode(new File(args[0]).readAsStringSync()); - var info = new AllInfoJsonCodec().decode(json); +main(args) async { + var info = await infoFromFile(args.first); showCodeDistribution(info); } diff --git a/bin/library_size_split.dart b/bin/library_size_split.dart index 8dd419a..9221bf4 100644 --- a/bin/library_size_split.dart +++ b/bin/library_size_split.dart @@ -59,23 +59,21 @@ /// This example is very similar to [defaultGrouping]. library dart2js_info.bin.library_size_split; -import 'dart:convert'; import 'dart:io'; import 'dart:math' show max; import 'package:dart2js_info/info.dart'; +import 'package:dart2js_info/src/util.dart'; import 'package:yaml/yaml.dart'; -main(args) { +main(args) async { if (args.length < 1) { print('usage: dart tool/library_size_split.dart ' 'path-to-info.json [grouping.yaml]'); exit(1); } - var filename = args[0]; - var json = JSON.decode(new File(filename).readAsStringSync()); - var info = new AllInfoJsonCodec().decode(json); + var info = await infoFromFile(args.first); var groupingText = args.length > 1 ? new File(args[1]).readAsStringSync() : defaultGrouping; diff --git a/bin/live_code_size_analysis.dart b/bin/live_code_size_analysis.dart index 333f5c4..5520ff1 100644 --- a/bin/live_code_size_analysis.dart +++ b/bin/live_code_size_analysis.dart @@ -39,17 +39,17 @@ import 'dart:io'; import 'package:dart2js_info/info.dart'; import 'package:dart2js_info/src/util.dart'; + import 'function_size_analysis.dart'; -main(args) { +main(args) async { if (args.length < 2) { print('usage: dart tool/live_code_size_analysis.dart path-to-info.json ' 'path-to-coverage.json [-v]'); exit(1); } - var json = JSON.decode(new File(args[0]).readAsStringSync()); - var info = new AllInfoJsonCodec().decode(json); + var info = await infoFromFile(args.first); var coverage = JSON.decode(new File(args[1]).readAsStringSync()); var verbose = args.length > 2 && args[2] == '-v'; diff --git a/lib/src/util.dart b/lib/src/util.dart index 1b8a084..b00f434 100644 --- a/lib/src/util.dart +++ b/lib/src/util.dart @@ -4,7 +4,12 @@ library dart2js_info.src.util; +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + import 'package:dart2js_info/info.dart'; + import 'graph.dart'; /// Computes a graph of dependencies from [info]. @@ -124,3 +129,8 @@ String recursiveDiagnosticString(Measurements measurements, Metric metric) { helper(metric); return sb.toString(); } + +Future infoFromFile(String fileName) async { + var file = await new File(fileName).readAsString(); + return new AllInfoJsonCodec().decode(JSON.decode(file)); +} diff --git a/pubspec.yaml b/pubspec.yaml index 1a43066..0ea5855 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: dart2js_info -version: 0.2.5 +version: 0.2.6 description: > Libraries and tools to process data produced when running dart2js with --dump-info. @@ -24,6 +24,7 @@ executables: dart2js_info_coverage_log_server: coverage_log_server dart2js_info_debug_info: debug_info dart2js_info_deferred_library_check: deferred_library_check + dart2js_info_deferred_library_size: deferred_library_size dart2js_info_function_size_analysis: function_size_analysis dart2js_info_library_size_split: library_size_split dart2js_info_live_code_size_analysis: live_code_size_analysis diff --git a/tool/travis.sh b/tool/travis.sh index ca28b04..e0a8098 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -9,7 +9,7 @@ set -e # Verify that the libraries are error free. dartanalyzer --fatal-warnings \ - lib/info.dart \ + lib/**/*.dart \ test/*.dart # Run the tests.