| 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 a3ce8d236baf38dd6be1acd44fda19d092886c91..2fd6e7882247f5d014aa80cb3cb8b53602f3f691 100644
|
| --- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
|
| +++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
|
| @@ -24,22 +24,19 @@ 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, groupByClass }
|
|
|
| -class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| - static const tag = const Tag<HeapSnapshotElement>('heap-snapshot',
|
| - dependencies: const [
|
| - ClassRefElement.tag,
|
| - NavTopMenuElement.tag,
|
| - NavVMMenuElement.tag,
|
| - NavIsolateMenuElement.tag,
|
| - NavRefreshElement.tag,
|
| - NavNotifyElement.tag,
|
| - VirtualTreeElement.tag,
|
| - ]);
|
| +class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| + static const tag =
|
| + const Tag<HeapSnapshotElement>('heap-snapshot', dependencies: const [
|
| + ClassRefElement.tag,
|
| + NavTopMenuElement.tag,
|
| + NavVMMenuElement.tag,
|
| + NavIsolateMenuElement.tag,
|
| + NavRefreshElement.tag,
|
| + NavNotifyElement.tag,
|
| + VirtualTreeElement.tag,
|
| + ]);
|
|
|
| RenderingScheduler<HeapSnapshotElement> _r;
|
|
|
| @@ -56,18 +53,19 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| M.HeapSnapshotLoadingProgress _progress;
|
| HeapSnapshotTreeMode _mode = HeapSnapshotTreeMode.dominatorTree;
|
|
|
| -
|
| M.IsolateRef get isolate => _isolate;
|
| M.NotificationRepository get notifications => _notifications;
|
| M.HeapSnapshotRepository get profiles => _snapshots;
|
| M.VMRef get vm => _vm;
|
|
|
| - factory HeapSnapshotElement(M.VM vm, M.IsolateRef isolate,
|
| - M.EventRepository events,
|
| - M.NotificationRepository notifications,
|
| - M.HeapSnapshotRepository snapshots,
|
| - M.InstanceRepository instances,
|
| - {RenderingQueue queue}) {
|
| + factory HeapSnapshotElement(
|
| + M.VM vm,
|
| + M.IsolateRef isolate,
|
| + M.EventRepository events,
|
| + M.NotificationRepository notifications,
|
| + M.HeapSnapshotRepository snapshots,
|
| + M.InstanceRepository instances,
|
| + {RenderingQueue queue}) {
|
| assert(vm != null);
|
| assert(isolate != null);
|
| assert(events != null);
|
| @@ -109,10 +107,10 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
|
| navMenu('heap snapshot'),
|
| new NavRefreshElement(queue: _r.queue)
|
| - ..disabled = M.isHeapSnapshotProgressRunning(_progress?.status)
|
| - ..onRefresh.listen((e) {
|
| - _refresh();
|
| - }),
|
| + ..disabled = M.isHeapSnapshotProgressRunning(_progress?.status)
|
| + ..onRefresh.listen((e) {
|
| + _refresh();
|
| + }),
|
| new NavNotifyElement(_notifications, queue: _r.queue)
|
| ]),
|
| ];
|
| @@ -121,12 +119,12 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| return;
|
| }
|
| switch (_progress.status) {
|
| - case M.HeapSnapshotLoadingStatus.fetching :
|
| + case M.HeapSnapshotLoadingStatus.fetching:
|
| content.addAll(_createStatusMessage('Fetching snapshot from VM...',
|
| description: _progress.stepDescription,
|
| progress: _progress.progress));
|
| break;
|
| - case M.HeapSnapshotLoadingStatus.loading :
|
| + case M.HeapSnapshotLoadingStatus.loading:
|
| content.addAll(_createStatusMessage('Loading snapshot...',
|
| description: _progress.stepDescription,
|
| progress: _progress.progress));
|
| @@ -158,15 +156,20 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| static List<Element> _createStatusMessage(String message,
|
| {String description: '', double progress: 0.0}) {
|
| return [
|
| - new DivElement()..classes = ['content-centered-big']
|
| + new DivElement()
|
| + ..classes = ['content-centered-big']
|
| ..children = [
|
| - new DivElement()..classes = ['statusBox', 'shadow', 'center']
|
| + new DivElement()
|
| + ..classes = ['statusBox', 'shadow', 'center']
|
| ..children = [
|
| - new DivElement()..classes = ['statusMessage']
|
| + new DivElement()
|
| + ..classes = ['statusMessage']
|
| ..text = message,
|
| - new DivElement()..classes = ['statusDescription']
|
| + new DivElement()
|
| + ..classes = ['statusDescription']
|
| ..text = description,
|
| - new DivElement()..style.background = '#0489c3'
|
| + new DivElement()
|
| + ..style.background = '#0489c3'
|
| ..style.width = '$progress%'
|
| ..style.height = '15px'
|
| ..style.borderRadius = '4px'
|
| @@ -179,43 +182,60 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
|
|
| List<Element> _createReport() {
|
| var report = [
|
| - new DivElement()..classes = ['content-centered-big']
|
| + new DivElement()
|
| + ..classes = ['content-centered-big']
|
| ..children = [
|
| - new DivElement()..classes = ['memberList']
|
| + new DivElement()
|
| + ..classes = ['memberList']
|
| ..children = [
|
| - new DivElement()..classes = ['memberItem']
|
| + new DivElement()
|
| + ..classes = ['memberItem']
|
| ..children = [
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = 'Refreshed ',
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = Utils.formatDateTime(_snapshot.timestamp)
|
| ],
|
| - new DivElement()..classes = ['memberItem']
|
| + new DivElement()
|
| + ..classes = ['memberItem']
|
| ..children = [
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = 'Objects ',
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = '${_snapshot.objects}'
|
| ],
|
| - new DivElement()..classes = ['memberItem']
|
| + new DivElement()
|
| + ..classes = ['memberItem']
|
| ..children = [
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = 'References ',
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = '${_snapshot.references}'
|
| ],
|
| - new DivElement()..classes = ['memberItem']
|
| + new DivElement()
|
| + ..classes = ['memberItem']
|
| ..children = [
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = 'Size ',
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = Utils.formatSize(_snapshot.size)
|
| ],
|
| - new DivElement()..classes = ['memberItem']
|
| + new DivElement()
|
| + ..classes = ['memberItem']
|
| ..children = [
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..text = 'Analysis ',
|
| - new DivElement()..classes = ['memberName']
|
| + new DivElement()
|
| + ..classes = ['memberName']
|
| ..children = _createModeSelect()
|
| ]
|
| ]
|
| @@ -223,23 +243,24 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| ];
|
| switch (_mode) {
|
| case HeapSnapshotTreeMode.dominatorTree:
|
| - _tree = new VirtualTreeElement(_createDominator, _updateDominator,
|
| - _getChildrenDominator,
|
| + _tree = new VirtualTreeElement(
|
| + _createDominator, _updateDominator, _getChildrenDominator,
|
| items: _getChildrenDominator(_snapshot.dominatorTree),
|
| queue: _r.queue);
|
| _tree.expand(_snapshot.dominatorTree);
|
| 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 '
|
| - 'plus its own shallow size, and is the amount of memory '
|
| - 'that would be freed if the object became garbage.';
|
| + '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 '
|
| + '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']
|
| + new DivElement()
|
| + ..classes = ['content-centered-big', 'explanation']
|
| ..text = text
|
| ..title = text,
|
| _tree
|
| @@ -248,8 +269,9 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| case HeapSnapshotTreeMode.groupByClass:
|
| final items = _snapshot.classReferences.toList();
|
| items.sort((a, b) => b.shallowSize - a.shallowSize);
|
| - _tree = new VirtualTreeElement(_createGroup, _updateGroup,
|
| - _getChildrenGroup, items: items, queue: _r.queue);
|
| + _tree = new VirtualTreeElement(
|
| + _createGroup, _updateGroup, _getChildrenGroup,
|
| + items: items, queue: _r.queue);
|
| _tree.expand(_snapshot.dominatorTree);
|
| report.add(_tree);
|
| break;
|
| @@ -263,12 +285,15 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| return new DivElement()
|
| ..classes = ['tree-item']
|
| ..children = [
|
| - new SpanElement()..classes = ['size']
|
| + new SpanElement()
|
| + ..classes = ['size']
|
| ..title = 'retained size',
|
| new SpanElement()..classes = ['lines'],
|
| - new ButtonElement()..classes = ['expander']
|
| + new ButtonElement()
|
| + ..classes = ['expander']
|
| ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
|
| - new SpanElement()..classes = ['percentage']
|
| + new SpanElement()
|
| + ..classes = ['percentage']
|
| ..title = 'percentage of heap being retained',
|
| new SpanElement()..classes = ['name']
|
| ];
|
| @@ -278,12 +303,15 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| return new DivElement()
|
| ..classes = ['tree-item']
|
| ..children = [
|
| - new SpanElement()..classes = ['size']
|
| + new SpanElement()
|
| + ..classes = ['size']
|
| ..title = 'shallow size',
|
| new SpanElement()..classes = ['lines'],
|
| - new ButtonElement()..classes = ['expander']
|
| + new ButtonElement()
|
| + ..classes = ['expander']
|
| ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
|
| - new SpanElement()..classes = ['count']
|
| + new SpanElement()
|
| + ..classes = ['count']
|
| ..title = 'shallow size',
|
| new SpanElement()..classes = ['name']
|
| ];
|
| @@ -295,8 +323,9 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| static _getChildrenDominator(M.HeapSnapshotDominatorNode node) {
|
| final list = node.children.toList();
|
| list.sort((a, b) => b.retainedSize - a.retainedSize);
|
| - return list.where((child) => child.retainedSize >= kMinRetainedSize)
|
| - .take(kMaxChildren);
|
| + return list
|
| + .where((child) => child.retainedSize >= kMinRetainedSize)
|
| + .take(kMaxChildren);
|
| }
|
|
|
| static _getChildrenGroup(item) {
|
| @@ -310,8 +339,8 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| return const [];
|
| }
|
|
|
| - void _updateDominator(HtmlElement element, M.HeapSnapshotDominatorNode node,
|
| - int depth) {
|
| + void _updateDominator(
|
| + HtmlElement element, M.HeapSnapshotDominatorNode node, int depth) {
|
| element.children[0].text = Utils.formatSize(node.retainedSize);
|
| _updateLines(element.children[1].children, depth);
|
| if (_getChildrenDominator(node).isNotEmpty) {
|
| @@ -319,13 +348,15 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| } 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[3].text =
|
| + Utils.formatPercentNormalized(node.retainedSize * 1.0 / _snapshot.size);
|
| + final wrapper = new SpanElement()
|
| + ..classes = ['name']
|
| + ..text = 'Loading...';
|
| element.children[4] = wrapper;
|
| node.object.then((object) {
|
| - wrapper..text = ''
|
| + wrapper
|
| + ..text = ''
|
| ..children = [anyRef(_isolate, object, _instances, queue: _r.queue)];
|
| });
|
| }
|
| @@ -351,29 +382,29 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| references += referenceGroup.count;
|
| }
|
| if (item is Iterable<M.HeapSnapshotClassInbound>) {
|
| - element.children[4] = new SpanElement()..classes = ['name']
|
| - ..text = '$references incoming references';
|
| + element.children[4] = new SpanElement()
|
| + ..classes = ['name']
|
| + ..text = '$references incoming references';
|
| } else {
|
| - element.children[4] = new SpanElement()..classes = ['name']
|
| - ..text = '$references outgoing references';
|
| + element.children[4] = new SpanElement()
|
| + ..classes = ['name']
|
| + ..text = '$references outgoing references';
|
| }
|
| } else {
|
| element.children[0].text = '';
|
| element.children[2].text = '';
|
| element.children[3].text = '';
|
| element.children[4] = new SpanElement()..classes = ['name'];
|
| - if (item is M.HeapSnapshotClassInbound){
|
| + if (item is M.HeapSnapshotClassInbound) {
|
| element.children[3].text =
|
| '${item.count} references from instances of ';
|
| element.children[4].children = [
|
| - new ClassRefElement(_isolate, item.source,
|
| - queue: _r.queue)
|
| + new ClassRefElement(_isolate, item.source, queue: _r.queue)
|
| ];
|
| - } else if (item is M.HeapSnapshotClassOutbound){
|
| + } else if (item is M.HeapSnapshotClassOutbound) {
|
| element.children[3]..text = '${item.count} references to instances of ';
|
| element.children[4].children = [
|
| - new ClassRefElement(_isolate, item.target,
|
| - queue: _r.queue)
|
| + new ClassRefElement(_isolate, item.target, queue: _r.queue)
|
| ];
|
| }
|
| }
|
| @@ -391,8 +422,10 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
|
|
| static String modeToString(HeapSnapshotTreeMode mode) {
|
| switch (mode) {
|
| - case HeapSnapshotTreeMode.dominatorTree: return 'Dominator tree';
|
| - case HeapSnapshotTreeMode.groupByClass: return 'Group by class';
|
| + case HeapSnapshotTreeMode.dominatorTree:
|
| + return 'Dominator tree';
|
| + case HeapSnapshotTreeMode.groupByClass:
|
| + return 'Group by class';
|
| }
|
| throw new Exception('Unknown ProfileTreeMode');
|
| }
|
| @@ -400,17 +433,18 @@ class HeapSnapshotElement extends HtmlElement implements Renderable {
|
| List<Element> _createModeSelect() {
|
| var s;
|
| return [
|
| - s = new SelectElement()..classes = ['analysis-select']
|
| + s = new SelectElement()
|
| + ..classes = ['analysis-select']
|
| ..value = modeToString(_mode)
|
| ..children = HeapSnapshotTreeMode.values.map((mode) {
|
| - return new OptionElement(value: modeToString(mode),
|
| - selected: _mode == mode)
|
| - ..text = modeToString(mode);
|
| - }).toList(growable: false)
|
| + return new OptionElement(
|
| + value: modeToString(mode),
|
| + selected: _mode == mode)..text = modeToString(mode);
|
| + }).toList(growable: false)
|
| ..onChange.listen((_) {
|
| - _mode = HeapSnapshotTreeMode.values[s.selectedIndex];
|
| - _r.dirty();
|
| - })
|
| + _mode = HeapSnapshotTreeMode.values[s.selectedIndex];
|
| + _r.dirty();
|
| + })
|
| ];
|
| }
|
| }
|
|
|