Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 88ad237

Browse files
mralephcommit-bot@chromium.org
authored andcommitted
[vm/tool] Support V8 profiles in snapshot_analysis treemap
Issue dart-lang/sdk#41249 Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-try,pkg-win-release-try,pkg-mac-release-try Change-Id: Ic5a3b4054f3eda6dfc5f9bf48dca97dd6a6deac6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151386 Commit-Queue: Vyacheslav Egorov <[email protected]> Reviewed-by: Alexander Markov <[email protected]>
1 parent 4aaf13a commit 88ad237

File tree

2 files changed

+58
-15
lines changed

2 files changed

+58
-15
lines changed

pkg/vm/lib/snapshot/commands/treemap.dart

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import 'package:path/path.dart' as p;
1919
import 'package:args/command_runner.dart';
2020

2121
import '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;
2224
import 'package:vm/snapshot/utils.dart';
2325

2426
class TreemapCommand extends Command<void> {
@@ -30,7 +32,7 @@ class TreemapCommand extends Command<void> {
3032
Create interactive treemap from snapshot profiling information.
3133
3234
This 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
3537
It will create an interactive web-page in the output-directory which can be
3638
viewed in a browser:
@@ -74,11 +76,17 @@ viewed in a browser:
7476
Future<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.
117161
String treePath(instruction_sizes.SymbolInfo symbol) {
118162
if (symbol.name.isStub) {
@@ -130,14 +174,12 @@ const kindSymbol = 's';
130174
const kindPath = 'p';
131175
const kindBucket = 'b';
132176
const 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.
136181
Map<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
}

pkg/vm/lib/snapshot/v8_profile.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,13 @@ class Node {
242242
class SnapshotInfo {
243243
final Snapshot snapshot;
244244

245-
final List<ProgramInfoNode> _infoNodes;
245+
final List<ProgramInfoNode> infoNodes;
246246
final Map<int, int> _ownerOf;
247247

248-
SnapshotInfo._(this.snapshot, this._infoNodes, this._ownerOf);
248+
SnapshotInfo._(this.snapshot, this.infoNodes, this._ownerOf);
249249

250250
ProgramInfoNode ownerOf(Node node) =>
251-
_infoNodes[_ownerOf[node.index] ?? ProgramInfo.unknownId];
251+
infoNodes[_ownerOf[node.index] ?? ProgramInfo.unknownId];
252252
}
253253

254254
ProgramInfo toProgramInfo(Snapshot snap,

0 commit comments

Comments
 (0)