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..7389daa2aaea72ea8b4da9e9362cce68612f9534 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,23 @@ 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 = 'A heap dominator tree, where siblings with the same class' |
+ ' have been merged into a single node.'; |
+ 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 +316,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 +362,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 +403,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 +491,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'; |
} |