Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2447)

Unified Diff: runtime/observatory/lib/src/elements/heap_snapshot.dart

Issue 2266343002: Converted Observatory heap-snapshot element (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Removed debug code Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 fbfb9eb4c56647f572b0ca2a604d2843db96c996..0b1ffcfdc2c236bff55ae2417b9645451a73136e 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
@@ -2,469 +2,416 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library heap_snapshot_element;
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:html';
-import 'class_ref_wrapper.dart';
-import 'observatory_element.dart';
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/elements.dart';
-import 'package:observatory/object_graph.dart';
-import 'package:polymer/polymer.dart';
-import 'package:logging/logging.dart';
-
-class DominatorTreeRow extends TableTreeRow {
- final ObjectVertex vertex;
- final HeapSnapshot snapshot;
-
- var _domTreeChildren;
- get domTreeChildren {
- if (_domTreeChildren == null) {
- _domTreeChildren = vertex.dominatorTreeChildren();
- }
- return _domTreeChildren;
- }
-
- DominatorTreeRow(TableTree tree,
- TableTreeRow parent,
- this.vertex,
- this.snapshot)
- : super(tree, parent) {
- }
-
- bool hasChildren() {
- return domTreeChildren.length > 0;
- }
-
- static const int kMaxChildren = 100;
- static const int kMinRetainedSize = 4096;
-
- void onShow() {
- super.onShow();
- if (children.length == 0) {
- domTreeChildren.sort((a, b) => b.retainedSize - a.retainedSize);
- int includedChildren = 0;
- for (var childVertex in domTreeChildren) {
- if (childVertex.retainedSize >= kMinRetainedSize) {
- if (++includedChildren <= kMaxChildren) {
- var row = new DominatorTreeRow(tree, this, childVertex, snapshot);
- children.add(row);
- }
- }
- }
- }
-
- var firstColumn = flexColumns[0];
- firstColumn.style.justifyContent = 'flex-start';
- firstColumn.style.position = 'relative';
- firstColumn.style.alignItems = 'center';
- firstColumn.style.setProperty('overflow-x', 'hidden');
-
- var percentRetained = vertex.retainedSize / snapshot.graph.size;
- var percentNode = new SpanElement();
- percentNode.text = Utils.formatPercentNormalized(percentRetained);
- percentNode.style.minWidth = '5em';
- percentNode.style.textAlign = 'right';
- percentNode.title = "Percent of heap being retained";
- percentNode.style.display = 'inline-block';
- firstColumn.children.add(percentNode);
-
- var gap = new SpanElement();
- gap.style.minWidth = '1em';
- gap.style.display = 'inline-block';
- firstColumn.children.add(gap);
-
- AnyServiceRefElement objectRef = new Element.tag("any-service-ref");
- snapshot.isolate.getObjectByAddress(vertex.address).then((obj) {
- objectRef.ref = obj;
- });
- objectRef.style.alignSelf = 'center';
- firstColumn.children.add(objectRef);
-
- var secondColumn = flexColumns[1];
- secondColumn.style.justifyContent = 'flex-end';
- secondColumn.style.position = 'relative';
- secondColumn.style.alignItems = 'center';
- secondColumn.style.paddingRight = '0.5em';
- secondColumn.text = Utils.formatSize(vertex.retainedSize);
- }
+import 'dart:math' as Math;
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/class_ref.dart';
+import 'package:observatory/src/elements/containers/virtual_tree.dart';
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+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
}
-
-class MergedVerticesRow extends TableTreeRow {
- final Isolate isolate;
- final List<MergedVertex> mergedVertices;
-
- MergedVerticesRow(TableTree tree,
- TableTreeRow parent,
- this.isolate,
- this.mergedVertices)
- : super(tree, parent) {
- }
-
- bool hasChildren() {
- return mergedVertices.length > 0;
+class HeapSnapshotElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<HeapSnapshotElement>('heap-snapshot',
+ dependencies: const [
+ ClassRefElement.tag,
+ NavBarElement.tag,
+ NavTopMenuElement.tag,
+ NavVMMenuElement.tag,
+ NavIsolateMenuElement.tag,
+ NavMenuElement.tag,
+ NavRefreshElement.tag,
+ NavNotifyElement.tag,
+ VirtualTreeElement.tag,
+ ]);
+
+ RenderingScheduler<HeapSnapshotElement> _r;
+
+ Stream<RenderedEvent<HeapSnapshotElement>> get onRendered => _r.onRendered;
+
+ M.VM _vm;
+ M.IsolateRef _isolate;
+ M.EventRepository _events;
+ M.NotificationRepository _notifications;
+ M.HeapSnapshotRepository _snapshots;
+ M.InstanceRepository _instances;
+ M.HeapSnapshot _snapshot;
+ Stream<M.HeapSnapshotLoadingProgressEvent> _progressStream;
+ 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}) {
+ assert(vm != null);
+ assert(isolate != null);
+ assert(events != null);
+ assert(notifications != null);
+ assert(snapshots != null);
+ assert(instances != null);
+ HeapSnapshotElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._vm = vm;
+ e._isolate = isolate;
+ e._events = events;
+ e._notifications = notifications;
+ e._snapshots = snapshots;
+ e._instances = instances;
+ return e;
}
- void onShow() {
- super.onShow();
-
- if (children.length == 0) {
- mergedVertices.sort((a, b) => b.shallowSize - a.shallowSize);
- for (var mergedVertex in mergedVertices) {
- if (mergedVertex.instances > 0) {
- var row = new MergedVertexRow(tree, this, isolate, mergedVertex);
- children.add(row);
- }
- }
- }
- }
-}
-
-class MergedVertexRow extends TableTreeRow {
- final Isolate isolate;
- final MergedVertex vertex;
+ HeapSnapshotElement.created() : super.created();
- MergedVertexRow(TableTree tree,
- TableTreeRow parent,
- this.isolate,
- this.vertex)
- : super(tree, parent) {
+ @override
+ attached() {
+ super.attached();
+ _r.enable();
+ _refresh();
}
- bool hasChildren() {
- return vertex.outgoingEdges.length > 0 ||
- vertex.incomingEdges.length > 0;
+ @override
+ detached() {
+ super.detached();
+ _r.disable(notify: true);
+ children = [];
}
- void onShow() {
- super.onShow();
- if (children.length == 0) {
- children.add(new MergedEdgesRow(tree, this, isolate, vertex, true));
- children.add(new MergedEdgesRow(tree, this, isolate, vertex, false));
+ void render() {
+ final content = [
+ new NavBarElement(queue: _r.queue)
+ ..children = [
+ new NavTopMenuElement(queue: _r.queue),
+ new NavVMMenuElement(_vm, _events, queue: _r.queue),
+ new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+ new NavMenuElement('heap snapshot', link: Uris.profiler(_isolate),
+ last: true, queue: _r.queue),
+ new NavRefreshElement(queue: _r.queue)
+ ..disabled = M.isHeapSnapshotProgressRunning(_progress?.status)
+ ..onRefresh.listen((e) {
+ _refresh();
+ }),
+ new NavNotifyElement(_notifications, queue: _r.queue)
+ ],
+ ];
+ if (_progress == null) {
+ children = content;
+ return;
}
-
-
- var firstColumn = flexColumns[0];
- firstColumn.style.justifyContent = 'flex-start';
- firstColumn.style.position = 'relative';
- firstColumn.style.alignItems = 'center';
-
- var percentNode = new SpanElement();
- percentNode.text = "${vertex.instances} instances of";
- percentNode.style.minWidth = '5em';
- percentNode.style.textAlign = 'right';
- firstColumn.children.add(percentNode);
-
- var gap = new SpanElement();
- gap.style.minWidth = '1em';
- gap.style.display = 'inline-block';
- firstColumn.children.add(gap);
-
- ClassRefElementWrapper classRef = new Element.tag("class-ref");
- classRef.ref = isolate.getClassByCid(vertex.cid);
- classRef.style.alignSelf = 'center';
- firstColumn.children.add(classRef);
-
- var secondColumn = flexColumns[1];
- secondColumn.style.justifyContent = 'flex-end';
- secondColumn.style.position = 'relative';
- secondColumn.style.alignItems = 'center';
- secondColumn.style.paddingRight = '0.5em';
- secondColumn.text = Utils.formatSize(vertex.shallowSize);
+ switch (_progress.status) {
+ case M.HeapSnapshotLoadingStatus.fetching :
+ content.addAll(_createStatusMessage('Fetching snapshot from VM...',
+ description: _progress.stepDescription,
+ progress: _progress.progress));
+ break;
+ case M.HeapSnapshotLoadingStatus.loading :
+ content.addAll(_createStatusMessage('Loading snapshot...',
+ description: _progress.stepDescription,
+ progress: _progress.progress));
+ break;
+ case M.HeapSnapshotLoadingStatus.loaded:
+ content.addAll(_createReport());
+ break;
+ }
+ children = content;
}
-}
-class MergedEdgesRow extends TableTreeRow {
- final Isolate isolate;
- final MergedVertex vertex;
- final bool outgoing;
-
- MergedEdgesRow(TableTree tree,
- TableTreeRow parent,
- this.isolate,
- this.vertex,
- this.outgoing)
- : super(tree, parent) {
+ Future _refresh() async {
+ _progress = null;
+ _progressStream = _snapshots.get(isolate);
+ _r.dirty();
+ _progressStream.listen((e) {
+ _progress = e.progress;
+ _r.dirty();
+ });
+ _progress = (await _progressStream.first).progress;
+ _r.dirty();
+ if (M.isHeapSnapshotProgressRunning(_progress.status)) {
+ _progress = (await _progressStream.last).progress;
+ _snapshot = _progress.snapshot;
+ _r.dirty();
+ }
}
- bool hasChildren() {
- return outgoing
- ? vertex.outgoingEdges.length > 0
- : vertex.incomingEdges.length > 0;
+ static List<Element> _createStatusMessage(String message,
+ {String description: '', double progress: 0.0}) {
+ return [
+ new DivElement()..classes = ['content-centered-big']
+ ..children = [
+ new DivElement()..classes = ['statusBox', 'shadow', 'center']
+ ..children = [
+ new DivElement()..classes = ['statusMessage']
+ ..text = message,
+ new DivElement()..classes = ['statusDescription']
+ ..text = description,
+ new DivElement()..style.background = '#0489c3'
+ ..style.width = '$progress%'
+ ..style.height = '15px'
+ ..style.borderRadius = '4px'
+ ]
+ ]
+ ];
}
- void onShow() {
- super.onShow();
- if (children.length == 0) {
- if (outgoing) {
- var outgoingEdges = vertex.outgoingEdges.values.toList();
- outgoingEdges.sort((a, b) => b.shallowSize - a.shallowSize);
- for (var edge in outgoingEdges) {
- if (edge.count > 0) {
- var row = new MergedEdgeRow(tree, this, isolate, edge, true);
- children.add(row);
- }
- }
- } else {
- vertex.incomingEdges.sort((a, b) => b.shallowSize - a.shallowSize);
- for (var edge in vertex.incomingEdges) {
- if (edge.count > 0) {
- var row = new MergedEdgeRow(tree, this, isolate, edge, false);
- children.add(row);
- }
- }
- }
+ VirtualTreeElement _tree;
+
+ List<Element> _createReport() {
+ var report = [
+ new DivElement()..classes = ['content-centered-big']
+ ..children = [
+ new DivElement()..classes = ['memberList']
+ ..children = [
+ new DivElement()..classes = ['memberItem']
+ ..children = [
+ new DivElement()..classes = ['memberName']
+ ..text = 'Refreshed ',
+ new DivElement()..classes = ['memberName']
+ ..text = Utils.formatDateTime(_snapshot.timestamp)
+ ],
+ new DivElement()..classes = ['memberItem']
+ ..children = [
+ new DivElement()..classes = ['memberName']
+ ..text = 'Objects ',
+ new DivElement()..classes = ['memberName']
+ ..text = '${_snapshot.objects}'
+ ],
+ new DivElement()..classes = ['memberItem']
+ ..children = [
+ new DivElement()..classes = ['memberName']
+ ..text = 'References ',
+ new DivElement()..classes = ['memberName']
+ ..text = '${_snapshot.references}'
+ ],
+ new DivElement()..classes = ['memberItem']
+ ..children = [
+ new DivElement()..classes = ['memberName']
+ ..text = 'Size ',
+ new DivElement()..classes = ['memberName']
+ ..text = Utils.formatSize(_snapshot.size)
+ ],
+ new DivElement()..classes = ['memberItem']
+ ..children = [
+ new DivElement()..classes = ['memberName']
+ ..text = 'Analysis ',
+ new DivElement()..classes = ['memberName']
+ ..children = _createModeSelect()
+ ]
+ ]
+ ],
+ ];
+ switch (_mode) {
+ case HeapSnapshotTreeMode.dominatorTree:
+ _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.';
+ 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);
+ _tree = new VirtualTreeElement(_createGroup, _updateGroup,
+ _getChildrenGroup, items: items, queue: _r.queue);
+ _tree.expand(_snapshot.dominatorTree);
+ report.add(_tree);
+ break;
+ default:
+ break;
}
-
- var count = 0;
- var shallowSize = 0;
- var edges = outgoing ? vertex.outgoingEdges.values : vertex.incomingEdges;
- for (var edge in edges) {
- count += edge.count;
- shallowSize += edge.shallowSize;
- }
-
- var firstColumn = flexColumns[0];
- firstColumn.style.justifyContent = 'flex-start';
- firstColumn.style.position = 'relative';
- firstColumn.style.alignItems = 'center';
-
- var countNode = new SpanElement();
- countNode.text = "$count";
- countNode.style.minWidth = '5em';
- countNode.style.textAlign = 'right';
- firstColumn.children.add(countNode);
-
- var gap = new SpanElement();
- gap.style.minWidth = '1em';
- gap.style.display = 'inline-block';
- firstColumn.children.add(gap);
-
- var labelNode = new SpanElement();
- labelNode.text = outgoing ? "Outgoing references" : "Incoming references";
- firstColumn.children.add(labelNode);
-
- var secondColumn = flexColumns[1];
- secondColumn.style.justifyContent = 'flex-end';
- secondColumn.style.position = 'relative';
- secondColumn.style.alignItems = 'center';
- secondColumn.style.paddingRight = '0.5em';
- secondColumn.text = Utils.formatSize(shallowSize);
+ return report;
}
-}
-class MergedEdgeRow extends TableTreeRow {
- final Isolate isolate;
- final MergedEdge edge;
- final bool outgoing;
-
- MergedEdgeRow(TableTree tree,
- TableTreeRow parent,
- this.isolate,
- this.edge,
- this.outgoing)
- : super(tree, parent) {
+ static Element _createDominator(toggle) {
+ return new DivElement()
+ ..classes = const ['tree-item']
+ ..children = [
+ new SpanElement()..classes = const ['size']
+ ..title = 'retained size',
+ new SpanElement()..classes = const ['lines'],
+ new ButtonElement()..classes = const ['expander']
+ ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
+ new SpanElement()..classes = const ['percentage']
+ ..title = 'percentage of heap being retained',
+ new SpanElement()..classes = const ['name']
+ ];
}
- bool hasChildren() => false;
-
- void onShow() {
- super.onShow();
-
- var firstColumn = flexColumns[0];
- firstColumn.style.justifyContent = 'flex-start';
- firstColumn.style.position = 'relative';
- firstColumn.style.alignItems = 'center';
-
- var percentNode = new SpanElement();
- var preposition = outgoing ? "to" : "from";
- percentNode.text = "${edge.count} references $preposition instances of";
- percentNode.style.minWidth = '5em';
- percentNode.style.textAlign = 'right';
- firstColumn.children.add(percentNode);
-
- var gap = new SpanElement();
- gap.style.minWidth = '1em';
- gap.style.display = 'inline-block';
- firstColumn.children.add(gap);
-
- MergedVertex v = outgoing ? edge.target : edge.source;
- if (v.cid == 0) {
- var rootName = new SpanElement();
- rootName.text = '<root>';
- firstColumn.children.add(rootName);
- } else {
- ClassRefElementWrapper classRef = new Element.tag("class-ref");
- classRef.ref = isolate.getClassByCid(v.cid);
- classRef.style.alignSelf = 'center';
- firstColumn.children.add(classRef);
- }
-
- var secondColumn = flexColumns[1];
- secondColumn.style.justifyContent = 'flex-end';
- secondColumn.style.position = 'relative';
- secondColumn.style.alignItems = 'center';
- secondColumn.style.paddingRight = '0.5em';
- secondColumn.text = Utils.formatSize(edge.shallowSize);
+ static Element _createGroup(toggle) {
+ return new DivElement()
+ ..classes = const ['tree-item']
+ ..children = [
+ new SpanElement()..classes = const ['size']
+ ..title = 'shallow size',
+ new SpanElement()..classes = const ['lines'],
+ new ButtonElement()..classes = const ['expander']
+ ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
+ new SpanElement()..classes = const ['count']
+ ..title = 'shallow size',
+ new SpanElement()..classes = const ['name']
+ ];
}
-}
-
-
-class MergedEdge {
- final MergedVertex source;
- final MergedVertex target;
- int count = 0;
- int shallowSize = 0;
- int retainedSize = 0;
- MergedEdge(this.source, this.target);
-}
-
-class MergedVertex {
- final int cid;
- int instances = 0;
- int shallowSize = 0;
- int retainedSize = 0;
-
- List<MergedEdge> incomingEdges = new List<MergedEdge>();
- Map<int, MergedEdge> outgoingEdges = new Map<int, MergedEdge>();
-
- MergedVertex(this.cid);
-}
-
-
-Future<List<MergedVertex>> buildMergedVertices(ObjectGraph graph) async {
- Logger.root.info("Start merge vertices");
-
- var cidToMergedVertex = {};
-
- for (var vertex in graph.vertices) {
- var cid = vertex.vmCid;
- MergedVertex source = cidToMergedVertex[cid];
- if (source == null) {
- cidToMergedVertex[cid] = source = new MergedVertex(cid);
- }
+ static const int kMaxChildren = 100;
+ static const int kMinRetainedSize = 4096;
- source.instances++;
- source.shallowSize += (vertex.shallowSize == null ? 0 : vertex.shallowSize);
+ 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);
+ }
- for (var vertex2 in vertex.successors) {
- var cid2 = vertex2.vmCid;
- MergedEdge edge = source.outgoingEdges[cid2];
- if (edge == null) {
- MergedVertex target = cidToMergedVertex[cid2];
- if (target == null) {
- cidToMergedVertex[cid2] = target = new MergedVertex(cid2);
- }
- edge = new MergedEdge(source, target);
- source.outgoingEdges[cid2] = edge;
- target.incomingEdges.add(edge);
+ static _getChildrenGroup(item) {
+ if (item is M.HeapSnapshotClassReferences) {
+ if (item.inbounds.isNotEmpty || item.outbounds.isNotEmpty) {
+ return [item.inbounds, item.outbounds];
}
- edge.count++;
- // An over-estimate if there are multiple references to the same object.
- edge.shallowSize += vertex2.shallowSize == null ? 0 : vertex2.shallowSize;
+ } else if (item is Iterable) {
+ return item.toList()..sort((a, b) => b.shallowSize - a.shallowSize);
}
+ return const [];
}
- Logger.root.info("End merge vertices");
-
- return cidToMergedVertex.values.toList();
-}
-
-@CustomTag('heap-snapshot')
-class HeapSnapshotElement extends ObservatoryElement {
- @published Isolate isolate;
- @observable HeapSnapshot snapshot;
-
- @published String state = 'Requested';
- @published String analysisSelector = 'DominatorTree';
-
- HeapSnapshotElement.created() : super.created();
-
- void analysisSelectorChanged(oldValue) {
- _update();
- }
-
- void isolateChanged(oldValue) {
- if (isolate == null) return;
-
- if (isolate.latestSnapshot == null) {
- _getHeapSnapshot();
+ 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) {
+ element.children[2].text = _tree.isExpanded(node) ? '▼' : '►';
} else {
- snapshot = isolate.latestSnapshot;
- state = 'Loaded';
- _update();
+ element.children[2].text = '';
}
+ element.children[3].text = Utils.formatPercentNormalized(
+ node.retainedSize * 1.0 / _snapshot.size);
+ final wrapper = new SpanElement()..classes = const ['name']
+ ..text = 'Loading...';
+ element.children[4] = wrapper;
+ node.object.then((object) {
+ wrapper..text = ''
+ ..children = [anyRef(_isolate, object, _instances, queue: _r.queue)];
+ });
}
- Future refresh() {
- return _getHeapSnapshot();
- }
-
- Future _getHeapSnapshot() {
- var completer = new Completer();
- state = "Requesting heap snapshot...";
- isolate.getClassRefs();
-
- bool collectGarbage =
- app.locationManager.getBoolParameter('collectGarbage', true);
-
- var stopwatch = new Stopwatch()..start();
- isolate.fetchHeapSnapshot(collectGarbage).listen((event) {
- if (event is String) {
- print("${stopwatch.elapsedMilliseconds} $event");
- state = event;
- } else if (event is HeapSnapshot) {
- snapshot = event;
- state = 'Loaded';
- completer.complete(snapshot);
- _update();
+ void _updateGroup(HtmlElement element, item, int depth) {
+ _updateLines(element.children[1].children, depth);
+ if (item is M.HeapSnapshotClassReferences) {
+ element.children[0].text = Utils.formatSize(item.shallowSize);
+ element.children[2].text = _tree.isExpanded(item) ? '▼' : '►';
+ element.children[3].text = '${item.instances} instances of ';
+ element.children[4] = new ClassRefElement(_isolate, item.clazz,
+ queue: _r.queue)..classes = const ['name'];
+ } else if (item is Iterable) {
+ element.children[0].text = '';
+ if (item.isNotEmpty) {
+ element.children[2].text = _tree.isExpanded(item) ? '▼' : '►';
} else {
- throw "Unexpected event $event";
+ element.children[2].text = '';
}
- });
- return completer.future;
+ element.children[3].text = '';
+ if (item is Iterable<M.HeapSnapshotClassInbound>) {
+ element.children[4] = new SpanElement()..classes = const ['name']
+ ..text = '${item.length} Ingoing references';
+ } else {
+ element.children[4] = new SpanElement()..classes = const ['name']
+ ..text = '${item.length} Outgoing references';
+ }
+ } else {
+ element.children[0].text = '';
+ element.children[2].text = '';
+ element.children[3].text = '';
+ element.children[4] = new SpanElement()..classes = const ['name'];
+ 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)
+ ];
+ } 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)
+ ];
+ }
+ }
}
- void _update() {
- if (snapshot == null) {
- return;
+ static _updateLines(List<Element> lines, int n) {
+ n = Math.max(0, n);
+ while (lines.length > n) {
+ lines.removeLast();
}
-
- switch(analysisSelector) {
- case 'DominatorTree':
- _buildDominatorTree();
- break;
- case 'MergeByClass':
- _buildMergedVertices();
- break;
+ while (lines.length < n) {
+ lines.add(new SpanElement());
}
}
- void _buildDominatorTree() {
- var tableBody = shadowRoot.querySelector('#treeBody');
- var tree = new TableTree(tableBody, 2);
- var rootRow =
- new DominatorTreeRow(tree, null, snapshot.graph.root, snapshot);
- tree.initialize(rootRow);
- return;
+ static String modeToString(HeapSnapshotTreeMode mode) {
+ switch (mode) {
+ case HeapSnapshotTreeMode.dominatorTree: return 'Dominator tree';
+ case HeapSnapshotTreeMode.groupByClass: return 'Group by class';
+ }
+ throw new Exception('Unknown ProfileTreeMode');
}
- void _buildMergedVertices() {
- state = 'Grouping...';
- var tableBody = shadowRoot.querySelector('#treeBody');
- var tree = new TableTree(tableBody, 2);
- tableBody.children.clear();
-
- new Future.delayed(const Duration(milliseconds: 500), () {
- buildMergedVertices(snapshot.graph).then((vertices) {
- state = 'Loaded';
- var rootRow = new MergedVerticesRow(tree, null, isolate, vertices);
- tree.initialize(rootRow);
- });
- });
+ List<Element> _createModeSelect() {
+ var s;
+ return [
+ 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)
+ ..onChange.listen((_) {
+ _mode = HeapSnapshotTreeMode.values[s.selectedIndex];
+ _r.dirty();
+ })
+ ];
}
}
« no previous file with comments | « runtime/observatory/lib/src/elements/css/shared.css ('k') | runtime/observatory/lib/src/elements/heap_snapshot.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698