Chromium Code Reviews| Index: runtime/observatory/lib/src/elements/heap_snapshot.dart |
| diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.dart b/runtime/observatory/lib/src/elements/heap_snapshot.dart |
| index 2fd6e7882247f5d014aa80cb3cb8b53602f3f691..03e981ce09dbdc1c12d33b1efb9732e0df5787c7 100644 |
| --- a/runtime/observatory/lib/src/elements/heap_snapshot.dart |
| +++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart |
| @@ -24,7 +24,7 @@ import 'package:observatory/src/elements/nav/top_menu.dart'; |
| import 'package:observatory/src/elements/nav/vm_menu.dart'; |
| import 'package:observatory/utils.dart'; |
| -enum HeapSnapshotTreeMode { dominatorTree, groupByClass } |
| +enum HeapSnapshotTreeMode { dominatorTree, mergedDominatorTree, groupByClass } |
| class HeapSnapshotElement extends HtmlElement implements Renderable { |
| static const tag = |
| @@ -266,6 +266,31 @@ class HeapSnapshotElement extends HtmlElement implements Renderable { |
| _tree |
| ]); |
| break; |
| + case HeapSnapshotTreeMode.mergedDominatorTree: |
| + _tree = new VirtualTreeElement( |
| + _createMergedDominator, _updateMergedDominator, |
| + _getChildrenMergedDominator, |
| + items: _getChildrenMergedDominator(_snapshot.mergedDominatorTree), |
| + queue: _r.queue); |
| + _tree.expand(_snapshot.mergedDominatorTree); |
| + final text = 'In a heap dominator tree, an object X is a parent of ' |
| + 'object Y if every path from the root to Y goes through ' |
| + 'X. This allows you to find "choke points" that are ' |
| + 'holding onto a lot of memory. If an object becomes ' |
| + 'garbage, all its children in the dominator tree become ' |
| + 'garbage as well. ' |
| + 'The retained size of an object is the sum of the ' |
| + 'retained sizes of its children in the dominator tree ' |
|
Cutch
2016/11/14 17:24:13
This text should explain what "merge" means in mor
rmacnak
2016/11/15 00:44:15
Done.
|
| + 'plus its own shallow size, and is the amount of memory ' |
| + 'that would be freed if the object became garbage.'; |
| + report.addAll([ |
| + new DivElement() |
| + ..classes = ['content-centered-big', 'explanation'] |
| + ..text = text |
| + ..title = text, |
| + _tree |
| + ]); |
| + break; |
| case HeapSnapshotTreeMode.groupByClass: |
| final items = _snapshot.classReferences.toList(); |
| items.sort((a, b) => b.shallowSize - a.shallowSize); |
| @@ -299,6 +324,24 @@ class HeapSnapshotElement extends HtmlElement implements Renderable { |
| ]; |
| } |
| + static Element _createMergedDominator(toggle) { |
| + return new DivElement() |
| + ..classes = ['tree-item'] |
| + ..children = [ |
| + new SpanElement() |
| + ..classes = ['size'] |
| + ..title = 'retained size', |
| + new SpanElement()..classes = ['lines'], |
| + new ButtonElement() |
| + ..classes = ['expander'] |
| + ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
| + new SpanElement() |
| + ..classes = ['percentage'] |
| + ..title = 'percentage of heap being retained', |
| + new SpanElement()..classes = ['name'] |
| + ]; |
| + } |
| + |
| static Element _createGroup(toggle) { |
| return new DivElement() |
| ..classes = ['tree-item'] |
| @@ -327,6 +370,13 @@ class HeapSnapshotElement extends HtmlElement implements Renderable { |
| .where((child) => child.retainedSize >= kMinRetainedSize) |
| .take(kMaxChildren); |
| } |
| + static _getChildrenMergedDominator(M.HeapSnapshotMergedDominatorNode node) { |
| + final list = node.children.toList(); |
| + list.sort((a, b) => b.retainedSize - a.retainedSize); |
| + return list |
| + .where((child) => child.retainedSize >= kMinRetainedSize) |
| + .take(kMaxChildren); |
| + } |
| static _getChildrenGroup(item) { |
| if (item is M.HeapSnapshotClassReferences) { |
| @@ -361,6 +411,31 @@ class HeapSnapshotElement extends HtmlElement implements Renderable { |
| }); |
| } |
| + void _updateMergedDominator( |
| + HtmlElement element, M.HeapSnapshotMergedDominatorNode node, int depth) { |
| + element.children[0].text = Utils.formatSize(node.retainedSize); |
| + _updateLines(element.children[1].children, depth); |
| + if (_getChildrenMergedDominator(node).isNotEmpty) { |
| + element.children[2].text = _tree.isExpanded(node) ? '▼' : '►'; |
| + } else { |
| + element.children[2].text = ''; |
| + } |
| + element.children[3].text = |
| + Utils.formatPercentNormalized(node.retainedSize * 1.0 / _snapshot.size); |
| + final wrapper = new SpanElement() |
| + ..classes = ['name'] |
| + ..text = 'Loading...'; |
| + element.children[4] = wrapper; |
| + node.klass.then((klass) { |
| + wrapper |
| + ..text = '' |
| + ..children = [ |
| + new SpanElement()..text = '${node.instanceCount} instances of ', |
| + anyRef(_isolate, klass, _instances, queue: _r.queue) |
| + ]; |
| + }); |
| + } |
| + |
| void _updateGroup(HtmlElement element, item, int depth) { |
| _updateLines(element.children[1].children, depth); |
| if (item is M.HeapSnapshotClassReferences) { |
| @@ -424,6 +499,8 @@ class HeapSnapshotElement extends HtmlElement implements Renderable { |
| switch (mode) { |
| case HeapSnapshotTreeMode.dominatorTree: |
| return 'Dominator tree'; |
| + case HeapSnapshotTreeMode.mergedDominatorTree: |
| + return 'Dominator tree (merged siblings by class)'; |
| case HeapSnapshotTreeMode.groupByClass: |
| return 'Group by class'; |
| } |