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 |