| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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 /// Command-line tool to show the size distribution of generated code among | 5 /// Command-line tool to show the size distribution of generated code among |
| 6 /// libraries. Libraries can be grouped using regular expressions. You can | 6 /// libraries. Libraries can be grouped using regular expressions. You can |
| 7 /// specify what regular expressions to use by providing a `grouping.yaml` file. | 7 /// specify what regular expressions to use by providing a `grouping.yaml` file. |
| 8 /// The format of the `grouping.yaml` file is as follows: | 8 /// The format of the `grouping.yaml` file is as follows: |
| 9 /// ```yaml | 9 /// ```yaml |
| 10 /// groups: | 10 /// groups: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 /// specification implicitly defines several groups, one per observed name. | 23 /// specification implicitly defines several groups, one per observed name. |
| 24 /// | 24 /// |
| 25 /// * cluster (optional): a clustering index for how data is shown in a table. | 25 /// * cluster (optional): a clustering index for how data is shown in a table. |
| 26 /// Groups with higher cluster indices are shown later in the table after a | 26 /// Groups with higher cluster indices are shown later in the table after a |
| 27 /// dividing line. If missing, the cluster index defaults to 0. | 27 /// dividing line. If missing, the cluster index defaults to 0. |
| 28 /// | 28 /// |
| 29 /// Here is an example configuration, with comments about what each entry does: | 29 /// Here is an example configuration, with comments about what each entry does: |
| 30 /// | 30 /// |
| 31 /// ```yaml | 31 /// ```yaml |
| 32 /// groups: | 32 /// groups: |
| 33 /// # This group shows the total size of all libraries together, it is shown in | |
| 34 /// # cluster #3, which happens to be the last cluster in this example: | |
| 35 /// - name: "Total (excludes preambles, statics & consts)" | |
| 36 /// regexp: ".*" | |
| 37 /// cluster: 3 | |
| 38 /// | |
| 39 /// # This group shows the total size for all libraries that were loaded from | 33 /// # This group shows the total size for all libraries that were loaded from |
| 40 /// # file:// urls: | 34 /// # file:// urls, it is shown in cluster #2, which happens to be the last |
| 35 /// # cluster in this example before the totals are shown: |
| 41 /// - { name: "Loose files", regexp: "file://.*", cluster: 2} | 36 /// - { name: "Loose files", regexp: "file://.*", cluster: 2} |
| 42 /// | 37 /// |
| 43 /// # This group shows the total size of all code loaded from packages: | 38 /// # This group shows the total size of all code loaded from packages: |
| 44 /// - { name: "All packages", regexp: "package:.*", cluster: 2} | 39 /// - { name: "All packages", regexp: "package:.*", cluster: 2} |
| 45 /// | 40 /// |
| 46 /// # This group shows the total size of all code loaded from core libraries: | 41 /// # This group shows the total size of all code loaded from core libraries: |
| 47 /// - { name: "Core libs", regexp: "dart:.*", cluster: 2} | 42 /// - { name: "Core libs", regexp: "dart:.*", cluster: 2} |
| 48 /// | 43 /// |
| 49 /// # This group shows the total size of all libraries in a single package. Here | 44 /// # This group shows the total size of all libraries in a single package. Here |
| 50 /// # we omitted the `name` entry, instead we extract it from the regexp | 45 /// # we omitted the `name` entry, instead we extract it from the regexp |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 ? new File(args[1]).readAsStringSync() : defaultGrouping; | 81 ? new File(args[1]).readAsStringSync() : defaultGrouping; |
| 87 var groupingYaml = loadYaml(groupingText); | 82 var groupingYaml = loadYaml(groupingText); |
| 88 var groups = []; | 83 var groups = []; |
| 89 for (var group in groupingYaml['groups']) { | 84 for (var group in groupingYaml['groups']) { |
| 90 groups.add(new _Group(group['name'], | 85 groups.add(new _Group(group['name'], |
| 91 new RegExp(group['regexp']), | 86 new RegExp(group['regexp']), |
| 92 group['cluster'] ?? 0)); | 87 group['cluster'] ?? 0)); |
| 93 } | 88 } |
| 94 | 89 |
| 95 var sizes = {}; | 90 var sizes = {}; |
| 91 var allLibs = 0; |
| 96 for (LibraryInfo lib in info.libraries) { | 92 for (LibraryInfo lib in info.libraries) { |
| 93 allLibs += lib.size; |
| 97 groups.forEach((group) { | 94 groups.forEach((group) { |
| 98 var match = group.matcher.firstMatch('${lib.uri}'); | 95 var match = group.matcher.firstMatch('${lib.uri}'); |
| 99 if (match != null) { | 96 if (match != null) { |
| 100 var name = group.name; | 97 var name = group.name; |
| 101 if (name == null && match.groupCount > 0) name = match.group(1); | 98 if (name == null && match.groupCount > 0) name = match.group(1); |
| 102 if (name == null) name = match.group(0); | 99 if (name == null) name = match.group(0); |
| 103 sizes.putIfAbsent(name, () => new _SizeEntry(name, group.cluster)); | 100 sizes.putIfAbsent(name, () => new _SizeEntry(name, group.cluster)); |
| 104 sizes[name].size += lib.size; | 101 sizes[name].size += lib.size; |
| 105 } | 102 } |
| 106 }); | 103 }); |
| 107 } | 104 } |
| 108 | 105 |
| 106 var allConstants = 0; |
| 107 for (var constant in info.constants) { |
| 108 allConstants += constant.size; |
| 109 } |
| 110 |
| 109 var all = sizes.keys.toList(); | 111 var all = sizes.keys.toList(); |
| 110 all.sort((a, b) => sizes[a].compareTo(sizes[b])); | 112 all.sort((a, b) => sizes[a].compareTo(sizes[b])); |
| 111 var realTotal = info.program.size; | 113 var realTotal = info.program.size; |
| 112 var longest = all.fold(0, (count, value) => max(count, value.length)); | 114 var longest = 0; |
| 113 longest = max(longest, 'Program Size'.length); | 115 var rows = []; |
| 116 _addRow(String label, int value) { |
| 117 rows.add(new _Row(label, value)); |
| 118 longest = max(longest, label.length); |
| 119 } |
| 120 |
| 121 _printRow(_Row row) { |
| 122 if (row is _Divider) { |
| 123 print(' ' + ('-' * (longest + 18))); |
| 124 return; |
| 125 } |
| 126 |
| 127 var percent = row.value == realTotal ? '100' |
| 128 : (row.value * 100 / realTotal).toStringAsFixed(2); |
| 129 print(' ${_pad(row.label, longest + 1, right: true)}' |
| 130 ' ${_pad(row.value, 8)} ${_pad(percent, 6)}%'); |
| 131 } |
| 132 |
| 114 var lastCluster = 0; | 133 var lastCluster = 0; |
| 115 for (var name in all) { | 134 for (var name in all) { |
| 116 var entry = sizes[name]; | 135 var entry = sizes[name]; |
| 117 if (lastCluster < entry.cluster) { | 136 if (lastCluster < entry.cluster) { |
| 118 print(' ' + ('-' * (longest + 18))); | 137 rows.add(const _Divider()); |
| 119 lastCluster = entry.cluster; | 138 lastCluster = entry.cluster; |
| 120 } | 139 } |
| 121 var size = entry.size; | 140 var size = entry.size; |
| 122 var percent = (size * 100 / realTotal).toStringAsFixed(2); | 141 _addRow(name, size); |
| 123 print(' ${_pad(name, longest + 1, right: true)}' | |
| 124 ' ${_pad(size, 8)} ${_pad(percent, 6)}%'); | |
| 125 } | 142 } |
| 126 print(' ${_pad("Program Size", longest + 1, right: true)}' | 143 rows.add(const _Divider()); |
| 127 ' ${_pad(realTotal, 8)} ${_pad(100, 6)}%'); | 144 _addRow("All libraries (excludes preambles, statics & consts)", allLibs); |
| 145 _addRow("Shared consts", allConstants); |
| 146 _addRow("Total accounted", allLibs + allConstants); |
| 147 _addRow("Program Size", realTotal); |
| 148 rows.forEach(_printRow); |
| 128 } | 149 } |
| 129 | 150 |
| 130 /// A group defined in the configuration. | 151 /// A group defined in the configuration. |
| 131 class _Group { | 152 class _Group { |
| 132 /// Name of the group. May be null if the name is derived from the matcher. In | 153 /// Name of the group. May be null if the name is derived from the matcher. In |
| 133 /// that case, the name would be group(1) of the matched expression if it | 154 /// that case, the name would be group(1) of the matched expression if it |
| 134 /// exist, or group(0) otherwise. | 155 /// exist, or group(0) otherwise. |
| 135 final String name; | 156 final String name; |
| 136 | 157 |
| 137 /// Regular expression matching members of the group. | 158 /// Regular expression matching members of the group. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 149 final String name; | 170 final String name; |
| 150 final int cluster; | 171 final int cluster; |
| 151 int size = 0; | 172 int size = 0; |
| 152 | 173 |
| 153 _SizeEntry(this.name, this.cluster); | 174 _SizeEntry(this.name, this.cluster); |
| 154 | 175 |
| 155 int compareTo(_SizeEntry other) => | 176 int compareTo(_SizeEntry other) => |
| 156 cluster == other.cluster ? size - other.size : cluster - other.cluster; | 177 cluster == other.cluster ? size - other.size : cluster - other.cluster; |
| 157 } | 178 } |
| 158 | 179 |
| 180 class _Row { |
| 181 final String label; |
| 182 final int value; |
| 183 const _Row(this.label, this.value); |
| 184 } |
| 185 |
| 186 class _Divider extends _Row { |
| 187 const _Divider() : super('', 0); |
| 188 } |
| 189 |
| 159 _pad(value, n, {bool right: false}) { | 190 _pad(value, n, {bool right: false}) { |
| 160 var s = '$value'; | 191 var s = '$value'; |
| 161 if (s.length >= n) return s; | 192 if (s.length >= n) return s; |
| 162 var pad = ' ' * (n - s.length); | 193 var pad = ' ' * (n - s.length); |
| 163 return right ? '$s$pad' : '$pad$s'; | 194 return right ? '$s$pad' : '$pad$s'; |
| 164 } | 195 } |
| 165 | 196 |
| 166 /// Default grouping specification that includes an entry per library, and | 197 /// Default grouping specification that includes an entry per library, and |
| 167 /// grouping entries for each package, all packages, all core libs, and loose | 198 /// grouping entries for each package, all packages, all core libs, and loose |
| 168 /// files. | 199 /// files. |
| 169 final defaultGrouping = """ | 200 final defaultGrouping = """ |
| 170 groups: | 201 groups: |
| 171 - { name: "Total (excludes preambles, statics & consts)", regexp: ".*", cluster:
3} | |
| 172 - { name: "Loose files", regexp: "file://.*", cluster: 2} | 202 - { name: "Loose files", regexp: "file://.*", cluster: 2} |
| 173 - { name: "All packages", regexp: "package:.*", cluster: 2} | 203 - { name: "All packages", regexp: "package:.*", cluster: 2} |
| 174 - { name: "Core libs", regexp: "dart:.*", cluster: 2} | 204 - { name: "Core libs", regexp: "dart:.*", cluster: 2} |
| 175 # We omitted `name` to extract the group name from the regexp directly. | 205 # We omitted `name` to extract the group name from the regexp directly. |
| 176 # Here the name is the name of the package: | 206 # Here the name is the name of the package: |
| 177 - { regexp: "package:([^/]*)", cluster: 1} | 207 - { regexp: "package:([^/]*)", cluster: 1} |
| 178 # Here the name is the url of the package and dart core libraries: | 208 # Here the name is the url of the package and dart core libraries: |
| 179 - { regexp: "package:.*"} | 209 - { regexp: "package:.*"} |
| 180 - { regexp: "dart:.*"} | 210 - { regexp: "dart:.*"} |
| 181 # Here the name is the relative path of loose files: | 211 # Here the name is the relative path of loose files: |
| 182 - { regexp: "file://${Directory.current.path}/(.*)" } | 212 - { regexp: "file://${Directory.current.path}/(.*)" } |
| 183 """; | 213 """; |
| OLD | NEW |