@@ -19,6 +19,8 @@ import 'package:path/path.dart' as p;
1919import 'package:args/command_runner.dart' ;
2020
2121import 'package:vm/snapshot/instruction_sizes.dart' as instruction_sizes;
22+ import 'package:vm/snapshot/program_info.dart' ;
23+ import 'package:vm/snapshot/v8_profile.dart' as v8_profile;
2224import 'package:vm/snapshot/utils.dart' ;
2325
2426class TreemapCommand extends Command <void > {
@@ -30,7 +32,7 @@ class TreemapCommand extends Command<void> {
3032Create interactive treemap from snapshot profiling information.
3133
3234This tool is used to process snapshot size reports produced by
33- --print-instructions-sizes-to=symbol-sizes.json .
35+ --print-instructions-sizes-to and --write-v8-snapshot-profile-to flags .
3436
3537It will create an interactive web-page in the output-directory which can be
3638viewed in a browser:
@@ -74,11 +76,17 @@ viewed in a browser:
7476Future <void > generateTreeMap (File input, Directory outputDir) async {
7577 // Load symbols data produced by the AOT compiler and convert it to
7678 // a tree.
77- final symbols = instruction_sizes. fromJson ( await loadJson (input) );
79+ final inputJson = await loadJson (input);
7880
7981 final root = {'n' : '' , 'children' : {}, 'k' : kindPath, 'maxDepth' : 0 };
80- for (var symbol in symbols) {
81- addSymbol (root, treePath (symbol), symbol.name.scrubbed, symbol.size);
82+
83+ if (v8_profile.Snapshot .isV8HeapSnapshot (inputJson)) {
84+ treemapFromSnapshot (root, v8_profile.Snapshot .fromJson (inputJson));
85+ } else {
86+ final symbols = instruction_sizes.fromJson (inputJson);
87+ for (var symbol in symbols) {
88+ addSymbol (root, treePath (symbol), symbol.name.scrubbed, symbol.size);
89+ }
8290 }
8391 final tree = flatten (root);
8492
@@ -113,6 +121,42 @@ Future<void> generateTreeMap(File input, Directory outputDir) async {
113121 print ('Generated ${p .toUri (p .absolute (outputDir .path , 'index.html' ))}' );
114122}
115123
124+ void treemapFromSnapshot (Map <String , dynamic > root, v8_profile.Snapshot snap) {
125+ final info = v8_profile.toProgramInfo (snap);
126+
127+ final ownerPathCache = List <String >(info.snapshotInfo.infoNodes.length);
128+ ownerPathCache[info.root.id] = info.root.name;
129+
130+ String nameOf (v8_profile.Node node) {
131+ switch (node.type) {
132+ case 'Library' :
133+ case 'Class' :
134+ case 'Function' :
135+ return node.name;
136+
137+ default :
138+ return '${node .type }' ;
139+ }
140+ }
141+
142+ String ownerPath (ProgramInfoNode n) {
143+ return ownerPathCache[n.id] ?? =
144+ ((n.parent != info.root) ? '${ownerPath (n .parent )}/${n .name }' : n.name);
145+ }
146+
147+ for (var node in snap.nodes) {
148+ if (node.selfSize > 0 ) {
149+ final owner = info.snapshotInfo.ownerOf (node);
150+ final path = ownerPath (owner);
151+ final name = nameOf (node);
152+ addSymbol (root, path, name, node.selfSize,
153+ symbolType: node.type == '(RO) Instructions'
154+ ? symbolTypeGlobalText
155+ : symbolTypeGlobalInitializedData);
156+ }
157+ }
158+ }
159+
116160/// Returns a /-separated path to the given symbol within the treemap.
117161String treePath (instruction_sizes.SymbolInfo symbol) {
118162 if (symbol.name.isStub) {
@@ -130,14 +174,12 @@ const kindSymbol = 's';
130174const kindPath = 'p' ;
131175const kindBucket = 'b' ;
132176const symbolTypeGlobalText = 'T' ;
177+ const symbolTypeGlobalInitializedData = 'D' ;
133178
134179/// Create a child with the given name within the given node or return
135180/// an existing child.
136181Map <String , dynamic > addChild (
137182 Map <String , dynamic > node, String kind, String name) {
138- if (kind == kindSymbol && node['children' ].containsKey (name)) {
139- print ('Duplicate symbol ${name }' );
140- }
141183 return node['children' ].putIfAbsent (name, () {
142184 final n = < String , dynamic > {'n' : name, 'k' : kind};
143185 if (kind != kindSymbol) {
@@ -148,19 +190,20 @@ Map<String, dynamic> addChild(
148190}
149191
150192/// Add the given symbol to the tree.
151- void addSymbol (Map <String , dynamic > root, String path, String name, int size) {
193+ void addSymbol (Map <String , dynamic > root, String path, String name, int size,
194+ {String symbolType: symbolTypeGlobalText}) {
152195 var node = root;
153196 var depth = 0 ;
154197 for (var part in path.split ('/' )) {
155198 node = addChild (node, kindPath, part);
156199 depth++ ;
157200 }
158201 node['lastPathElement' ] = true ;
159- node = addChild (node, kindBucket, symbolTypeGlobalText );
160- node['t' ] = symbolTypeGlobalText ;
202+ node = addChild (node, kindBucket, symbolType );
203+ node['t' ] = symbolType ;
161204 node = addChild (node, kindSymbol, name);
162- node['t' ] = symbolTypeGlobalText ;
163- node['value' ] = size;
205+ node['t' ] = symbolType ;
206+ node['value' ] = (node[ 'value' ] ?? 0 ) + size;
164207 depth += 2 ;
165208 root['maxDepth' ] = max <int >(root['maxDepth' ], depth);
166209}
0 commit comments