| 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 |