add tool to get breakdown of deferred libraries by size
R=sigmund@google.com
Review URL: https://codereview.chromium.org//2201903004 .
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 @@
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 @@
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 @@
[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 <query>');
print(' where <query> can be:');
@@ -42,14 +41,7 @@
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 @@
}
// 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<String> args) async {
@@ -56,11 +55,6 @@
if (failures.isNotEmpty) exitCode = 1;
}
-Future<AllInfo> 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<String, int> sizeByImport, int programSize) {
+ var importSizes = <ImportSize>[];
+ 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<String, int> getSizeByImport(AllInfo info) {
+ var sizeByImport = <String, int>{};
+ 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 '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 @@
helper(metric);
return sb.toString();
}
+
+Future<AllInfo> 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 @@
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 @@
# Verify that the libraries are error free.
dartanalyzer --fatal-warnings \
- lib/info.dart \
+ lib/**/*.dart \
test/*.dart
# Run the tests.