OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, 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 /// Command-line tool to show the size distribution of generated code among |
| 6 /// libraries. Libraries can be grouped using regular expressions. See |
| 7 /// [defaultGrouping] for an example. |
| 8 library compiler.tool.library_size_split; |
| 9 |
| 10 import 'dart:convert'; |
| 11 import 'dart:io'; |
| 12 import 'dart:math' show max; |
| 13 |
| 14 import 'package:compiler/src/info/info.dart'; |
| 15 import 'package:yaml/yaml.dart'; |
| 16 |
| 17 main(args) { |
| 18 if (args.length < 1) { |
| 19 print('usage: dart tool/library_size_split.dart ' |
| 20 'path-to-info.json [grouping.yaml]'); |
| 21 exit(1); |
| 22 } |
| 23 |
| 24 var filename = args[0]; |
| 25 var json = JSON.decode(new File(filename).readAsStringSync()); |
| 26 var info = AllInfo.parseFromJson(json); |
| 27 |
| 28 var groupingText = args.length > 1 |
| 29 ? new File(args[1]).readAsStringSync() : defaultGrouping; |
| 30 var groupingYaml = loadYaml(groupingText); |
| 31 var groups = []; |
| 32 for (var group in groupingYaml['groups']) { |
| 33 groups.add(new _Group(group['name'], |
| 34 new RegExp(group['regexp']), |
| 35 group['cluster'] ?? 0)); |
| 36 } |
| 37 |
| 38 var sizes = {}; |
| 39 for (LibraryInfo lib in info.libraries) { |
| 40 groups.forEach((group) { |
| 41 var match = group.matcher.firstMatch('${lib.uri}'); |
| 42 if (match != null) { |
| 43 var name = group.name; |
| 44 if (name == null && match.groupCount > 0) name = match.group(1); |
| 45 if (name == null) name = match.group(0); |
| 46 sizes.putIfAbsent(name, () => new _SizeEntry(name, group.cluster)); |
| 47 sizes[name].size += lib.size; |
| 48 } |
| 49 }); |
| 50 } |
| 51 |
| 52 var all = sizes.keys.toList(); |
| 53 all.sort((a, b) => sizes[a].compareTo(sizes[b])); |
| 54 var realTotal = info.program.size; |
| 55 var longest = all.fold(0, (count, value) => max(count, value.length)); |
| 56 longest = max(longest, 'Program Size'.length); |
| 57 var lastCluster = 0; |
| 58 for (var name in all) { |
| 59 var entry = sizes[name]; |
| 60 if (lastCluster < entry.cluster) { |
| 61 print(' ' + ('-' * (longest + 18))); |
| 62 lastCluster = entry.cluster; |
| 63 } |
| 64 var size = entry.size; |
| 65 var percent = (size * 100 / realTotal).toStringAsFixed(2); |
| 66 print(' ${_pad(name, longest + 1, right: true)}' |
| 67 ' ${_pad(size, 8)} ${_pad(percent, 6)}%'); |
| 68 } |
| 69 print(' ${_pad("Program Size", longest + 1, right: true)}' |
| 70 ' ${_pad(realTotal, 8)} ${_pad(100, 6)}%'); |
| 71 } |
| 72 |
| 73 /// A group defined in the configuration. |
| 74 class _Group { |
| 75 /// Name of the group. May be null if the name is derived from the matcher. In |
| 76 /// that case, the name would be group(1) of the matched expression if it |
| 77 /// exist, or group(0) otherwise. |
| 78 final String name; |
| 79 |
| 80 /// Regular expression matching members of the group. |
| 81 final RegExp matcher; |
| 82 |
| 83 /// Index used to cluster groups together. Useful when the grouping |
| 84 /// configuration describes some coarser groups than orders (e.g. summary of |
| 85 /// packages would be in a different cluster than a summary of libraries). |
| 86 final int cluster; |
| 87 |
| 88 _Group(this.name, this.matcher, this.cluster); |
| 89 } |
| 90 |
| 91 class _SizeEntry { |
| 92 final String name; |
| 93 final int cluster; |
| 94 int size = 0; |
| 95 |
| 96 _SizeEntry(this.name, this.cluster); |
| 97 |
| 98 int compareTo(_SizeEntry other) => |
| 99 cluster == other.cluster ? size - other.size : cluster - other.cluster; |
| 100 } |
| 101 |
| 102 _pad(value, n, {bool right: false}) { |
| 103 var s = '$value'; |
| 104 if (s.length >= n) return s; |
| 105 var pad = ' ' * (n - s.length); |
| 106 return right ? '$s$pad' : '$pad$s'; |
| 107 } |
| 108 |
| 109 /// Example grouping specification: a yaml format containing a list of |
| 110 /// group specifications. A group is specified by 3 parameters: |
| 111 /// - name: the name that will be shown in the table of results |
| 112 /// - regexp: a regexp used to match entries that belong to the group |
| 113 /// - cluster: a clustering index, the higher the value, the later it will be |
| 114 /// shown in the results. |
| 115 /// Both cluster and name are optional. If cluster is omitted, the default value |
| 116 /// is 0. If the name is omitted, it is extracted from the regexp, either as |
| 117 /// group(1) if it is available or group(0) otherwise. |
| 118 final defaultGrouping = """ |
| 119 groups: |
| 120 - { name: "Total (excludes preambles, statics & consts)", regexp: ".*", cluster:
3} |
| 121 - { name: "Loose files", regexp: "file://.*", cluster: 2} |
| 122 - { name: "All packages", regexp: "package:.*", cluster: 2} |
| 123 - { name: "Core libs", regexp: "dart:.*", cluster: 2} |
| 124 # We omitted `name` to extract the group name from the regexp directly. |
| 125 # Here the name is the name of the package: |
| 126 - { regexp: "package:([^/]*)", cluster: 1} |
| 127 # Here the name is the url of the package and dart core libraries: |
| 128 - { regexp: "package:.*"} |
| 129 - { regexp: "dart:.*"} |
| 130 # Here the name is the relative path of loose files: |
| 131 - { regexp: "file://${Directory.current.path}/(.*)" } |
| 132 """; |
OLD | NEW |