@@ -59,7 +59,8 @@ class ProgramInfo {
5959 /// Recursively visit all function nodes, which have [FunctionInfo.info]
6060 /// populated.
6161 void visit (
62- void Function (String pkg, String lib, String cls, String fun, int size)
62+ void Function (
63+ String pkg, String lib, String cls, String fun, ProgramInfoNode n)
6364 callback) {
6465 final context = List <String >(NodeType .values.length);
6566
@@ -71,13 +72,11 @@ class ProgramInfo {
7172 context[node._type] = node.name;
7273 }
7374
74- if (node.size != null ) {
75- final String pkg = context[NodeType .packageNode.index];
76- final String lib = context[NodeType .libraryNode.index];
77- final String cls = context[NodeType .classNode.index];
78- final String mem = context[NodeType .functionNode.index];
79- callback (pkg, lib, cls, mem, node.size);
80- }
75+ final String pkg = context[NodeType .packageNode.index];
76+ final String lib = context[NodeType .libraryNode.index];
77+ final String cls = context[NodeType .classNode.index];
78+ final String mem = context[NodeType .functionNode.index];
79+ callback (pkg, lib, cls, mem, node);
8180
8281 for (var child in node.children.values) {
8382 recurse (child);
@@ -91,8 +90,8 @@ class ProgramInfo {
9190
9291 int get totalSize {
9392 var result = 0 ;
94- visit ((pkg, lib, cls, fun, size ) {
95- result += size;
93+ visit ((pkg, lib, cls, fun, node ) {
94+ result += node. size ?? 0 ;
9695 });
9796 return result;
9897 }
@@ -181,13 +180,11 @@ Iterable<T> _allKeys<T>(Map<T, dynamic> a, Map<T, dynamic> b) {
181180 return < T > {...? a? .keys, ...? b? .keys};
182181}
183182
184- /// Histogram of sizes based on a [ProgramInfo] bucketed using one of the
185- /// [HistogramType] rules.
186- class SizesHistogram {
183+ class Histogram {
187184 /// Rule used to produce this histogram. Specifies how bucket names
188185 /// are constructed given (library-uri,class-name,function-name) tuples and
189186 /// how these bucket names can be deconstructed back into human readable form.
190- final Bucketing bucketing ;
187+ final BucketInfo bucketInfo ;
191188
192189 /// Histogram buckets.
193190 final Map <String , int > buckets;
@@ -200,24 +197,77 @@ class SizesHistogram {
200197
201198 int get length => bySize.length;
202199
203- SizesHistogram ._(this .bucketing, this .buckets, this .bySize, this .totalSize);
200+ Histogram ._(this .bucketInfo, this .buckets)
201+ : bySize = buckets.keys.toList (growable: false )
202+ ..sort ((a, b) => buckets[b] - buckets[a]),
203+ totalSize = buckets.values.fold (0 , (sum, size) => sum + size);
204+
205+ static Histogram fromIterable <T >(
206+ Iterable <T > entries, {
207+ @required int Function (T ) sizeOf,
208+ @required String Function (T ) bucketFor,
209+ @required BucketInfo bucketInfo,
210+ }) {
211+ final buckets = < String , int > {};
212+
213+ for (var e in entries) {
214+ final bucket = bucketFor (e);
215+ final size = sizeOf (e);
216+ buckets[bucket] = (buckets[bucket] ?? 0 ) + size;
217+ }
218+
219+ return Histogram ._(bucketInfo, buckets);
220+ }
221+ }
222+
223+ /// Construct the histogram of specific [type] given a [ProgramInfo] .
224+ Histogram computeHistogram (ProgramInfo info, HistogramType type,
225+ {String filter}) {
226+ bool Function (String , String , String ) matchesFilter;
227+
228+ if (filter != null ) {
229+ final re = RegExp (filter.replaceAll ('*' , '.*' ), caseSensitive: false );
230+ matchesFilter = (lib, cls, fun) => re.hasMatch ("${lib }::${cls }.${fun }" );
231+ } else {
232+ matchesFilter = (_, __, ___) => true ;
233+ }
234+
235+ if (type == HistogramType .byNodeType) {
236+ final Set <int > filteredNodes = {};
237+ if (filter != null ) {
238+ info.visit ((pkg, lib, cls, fun, node) {
239+ if (matchesFilter (lib, cls, fun)) {
240+ filteredNodes.add (node.id);
241+ }
242+ });
243+ }
204244
205- /// Construct the histogram of specific [type] given a [ProgramInfo] .
206- static SizesHistogram from (ProgramInfo info, HistogramType type) {
245+ return Histogram .fromIterable <Node >(
246+ info.snapshotInfo.snapshot.nodes.where ((n) =>
247+ filter == null ||
248+ filteredNodes.contains (info.snapshotInfo.ownerOf (n).id)),
249+ sizeOf: (n) {
250+ return n.selfSize;
251+ },
252+ bucketFor: (n) => n.type,
253+ bucketInfo: const BucketInfo (nameComponents: ['Type' ]));
254+ } else {
207255 final buckets = < String , int > {};
208256 final bucketing = Bucketing ._forType[type];
209257
210- var totalSize = 0 ;
211- info.visit ((pkg, lib, cls, fun, size) {
258+ info.visit ((pkg, lib, cls, fun, node) {
259+ if (node.size == null || node.size == 0 ) {
260+ return ;
261+ }
262+
212263 final bucket = bucketing.bucketFor (pkg, lib, cls, fun);
213- buckets[bucket] = (buckets[bucket] ?? 0 ) + size;
214- totalSize += size;
264+ if (! matchesFilter (lib, cls, fun)) {
265+ return ;
266+ }
267+ buckets[bucket] = (buckets[bucket] ?? 0 ) + node.size;
215268 });
216269
217- final bySize = buckets.keys.toList (growable: false );
218- bySize.sort ((a, b) => buckets[b] - buckets[a]);
219-
220- return SizesHistogram ._(bucketing, buckets, bySize, totalSize);
270+ return Histogram ._(bucketing, buckets);
221271 }
222272}
223273
@@ -226,22 +276,28 @@ enum HistogramType {
226276 byClass,
227277 byLibrary,
228278 byPackage,
279+ byNodeType,
229280}
230281
231- abstract class Bucketing {
282+ class BucketInfo {
232283 /// Specifies which human readable name components can be extracted from
233284 /// the bucket name.
234- List <String > get nameComponents;
285+ final List <String > nameComponents;
235286
287+ /// Deconstructs bucket name into human readable components (the order matches
288+ /// one returned by [nameComponents] ).
289+ List <String > namesFromBucket (String bucket) => [bucket];
290+
291+ const BucketInfo ({@required this .nameComponents});
292+ }
293+
294+ abstract class Bucketing extends BucketInfo {
236295 /// Constructs the bucket name from the given library name [lib] , class name
237296 /// [cls] and function name [fun] .
238297 String bucketFor (String pkg, String lib, String cls, String fun);
239298
240- /// Deconstructs bucket name into human readable components (the order matches
241- /// one returned by [nameComponents] ).
242- List <String > namesFromBucket (String bucket);
243-
244- const Bucketing ();
299+ const Bucketing ({@required List <String > nameComponents})
300+ : super (nameComponents: nameComponents);
245301
246302 static const _forType = {
247303 HistogramType .bySymbol: _BucketBySymbol (),
@@ -255,9 +311,6 @@ abstract class Bucketing {
255311const String _nameSeparator = ';;;' ;
256312
257313class _BucketBySymbol extends Bucketing {
258- @override
259- List <String > get nameComponents => const ['Library' , 'Symbol' ];
260-
261314 @override
262315 String bucketFor (String pkg, String lib, String cls, String fun) {
263316 if (fun == null ) {
@@ -269,13 +322,10 @@ class _BucketBySymbol extends Bucketing {
269322 @override
270323 List <String > namesFromBucket (String bucket) => bucket.split (_nameSeparator);
271324
272- const _BucketBySymbol ();
325+ const _BucketBySymbol () : super (nameComponents : const [ 'Library' , 'Symbol' ]) ;
273326}
274327
275328class _BucketByClass extends Bucketing {
276- @override
277- List <String > get nameComponents => ['Library' , 'Class' ];
278-
279329 @override
280330 String bucketFor (String pkg, String lib, String cls, String fun) {
281331 if (cls == null ) {
@@ -287,34 +337,22 @@ class _BucketByClass extends Bucketing {
287337 @override
288338 List <String > namesFromBucket (String bucket) => bucket.split (_nameSeparator);
289339
290- const _BucketByClass ();
340+ const _BucketByClass () : super (nameComponents : const [ 'Library' , 'Class' ]) ;
291341}
292342
293343class _BucketByLibrary extends Bucketing {
294- @override
295- List <String > get nameComponents => ['Library' ];
296-
297344 @override
298345 String bucketFor (String pkg, String lib, String cls, String fun) => '$lib ' ;
299346
300- @override
301- List <String > namesFromBucket (String bucket) => [bucket];
302-
303- const _BucketByLibrary ();
347+ const _BucketByLibrary () : super (nameComponents: const ['Library' ]);
304348}
305349
306350class _BucketByPackage extends Bucketing {
307- @override
308- List <String > get nameComponents => ['Package' ];
309-
310351 @override
311352 String bucketFor (String pkg, String lib, String cls, String fun) =>
312353 pkg ?? lib;
313354
314- @override
315- List <String > namesFromBucket (String bucket) => [bucket];
316-
317- const _BucketByPackage ();
355+ const _BucketByPackage () : super (nameComponents: const ['Package' ]);
318356}
319357
320358String packageOf (String lib) {
0 commit comments