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

Side by Side Diff: runtime/observatory/lib/src/elements/memory/snapshot.dart

Issue 3002843002: Introduce heap snapshot into Memory Dashboard (Closed)
Patch Set: Address CL comments Created 3 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:async';
6 import 'dart:html';
7 import 'dart:math' as Math;
8 import 'package:observatory/models.dart' as M;
9 import 'package:observatory/src/elements/class_ref.dart';
10 import 'package:observatory/src/elements/containers/virtual_tree.dart';
11 import 'package:observatory/src/elements/helpers/any_ref.dart';
12 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
13 import 'package:observatory/src/elements/helpers/tag.dart';
14 import 'package:observatory/src/elements/helpers/uris.dart';
15 import 'package:observatory/utils.dart';
16
17 class MemorySnapshotElement extends HtmlElement implements Renderable {
18 static const tag =
19 const Tag<MemorySnapshotElement>('memory-snapshot', dependencies: const [
20 ClassRefElement.tag,
21 VirtualTreeElement.tag,
22 ]);
23
24 RenderingScheduler<MemorySnapshotElement> _r;
25
26 Stream<RenderedEvent<MemorySnapshotElement>> get onRendered => _r.onRendered;
27
28 M.IsolateRef _isolate;
29 M.EditorRepository _editor;
30 M.HeapSnapshotRepository _snapshots;
31 M.ObjectRepository _objects;
32 M.HeapSnapshot _snapshot;
33 Stream<M.HeapSnapshotLoadingProgressEvent> _progressStream;
34 M.HeapSnapshotLoadingProgress _progress;
35
36 M.IsolateRef get isolate => _isolate;
37
38 factory MemorySnapshotElement(M.IsolateRef isolate, M.EditorRepository editor,
39 M.HeapSnapshotRepository snapshots, M.ObjectRepository objects,
40 {RenderingQueue queue}) {
41 assert(isolate != null);
42 assert(editor != null);
43 assert(snapshots != null);
44 assert(objects != null);
45 MemorySnapshotElement e = document.createElement(tag.name);
46 e._r = new RenderingScheduler(e, queue: queue);
47 e._isolate = isolate;
48 e._editor = editor;
49 e._snapshots = snapshots;
50 e._objects = objects;
51 return e;
52 }
53
54 MemorySnapshotElement.created() : super.created();
55
56 @override
57 attached() {
58 super.attached();
59 _r.enable();
60 _refresh();
61 }
62
63 @override
64 detached() {
65 super.detached();
66 _r.disable(notify: true);
67 children = [];
68 }
69
70 void render() {
71 if (_progress == null) {
72 children = const [];
73 return;
74 }
75 List<HtmlElement> content;
76 switch (_progress.status) {
77 case M.HeapSnapshotLoadingStatus.fetching:
78 content = _createStatusMessage('Fetching snapshot from VM...',
79 description: _progress.stepDescription,
80 progress: _progress.progress);
81 break;
82 case M.HeapSnapshotLoadingStatus.loading:
83 content = _createStatusMessage('Loading snapshot...',
84 description: _progress.stepDescription,
85 progress: _progress.progress);
86 break;
87 case M.HeapSnapshotLoadingStatus.loaded:
88 content = _createReport();
89 break;
90 }
91 children = content;
92 }
93
94 Future reload({bool gc: false}) => _refresh(gc: gc);
95
96 Future _refresh({bool gc: false}) async {
97 _progress = null;
98 _progressStream =
99 _snapshots.get(isolate, roots: M.HeapSnapshotRoots.user, gc: gc);
100 _r.dirty();
101 _progressStream.listen((e) {
102 _progress = e.progress;
103 _r.dirty();
104 });
105 _progress = (await _progressStream.first).progress;
106 _r.dirty();
107 if (M.isHeapSnapshotProgressRunning(_progress.status)) {
108 _progress = (await _progressStream.last).progress;
109 _snapshot = _progress.snapshot;
110 _r.dirty();
111 }
112 }
113
114 static List<Element> _createStatusMessage(String message,
115 {String description: '', double progress: 0.0}) {
116 return [
117 new DivElement()
118 ..classes = ['content-centered-big']
119 ..children = [
120 new DivElement()
121 ..classes = ['statusBox', 'shadow', 'center']
122 ..children = [
123 new DivElement()
124 ..classes = ['statusMessage']
125 ..text = message,
126 new DivElement()
127 ..classes = ['statusDescription']
128 ..text = description,
129 new DivElement()
130 ..style.background = '#0489c3'
131 ..style.width = '$progress%'
132 ..style.height = '15px'
133 ..style.borderRadius = '4px'
134 ]
135 ]
136 ];
137 }
138
139 VirtualTreeElement _tree;
140
141 List<Element> _createReport() {
142 final List roots = _getChildrenDominator(_snapshot.dominatorTree);
143 _tree = new VirtualTreeElement(
144 _createDominator, _updateDominator, _getChildrenDominator,
145 items: roots, queue: _r.queue);
146 if (roots.length == 1) {
147 _tree.expand(roots.first, autoExpandSingleChildNodes: true);
148 }
149 final text = 'In a heap dominator tree, an object X is a parent of '
150 'object Y if every path from the root to Y goes through '
151 'X. This allows you to find "choke points" that are '
152 'holding onto a lot of memory. If an object becomes '
153 'garbage, all its children in the dominator tree become '
154 'garbage as well. '
155 'The retained size of an object is the sum of the '
156 'retained sizes of its children in the dominator tree '
157 'plus its own shallow size, and is the amount of memory '
158 'that would be freed if the object became garbage.';
159 return <HtmlElement>[
160 new DivElement()
161 ..classes = ['content-centered-big', 'explanation']
162 ..text = text
163 ..title = text,
164 _tree
165 ];
166 }
167
168 static Element _createDominator(toggle) {
169 return new DivElement()
170 ..classes = ['tree-item']
171 ..children = [
172 new SpanElement()
173 ..classes = ['size']
174 ..title = 'retained size',
175 new SpanElement()..classes = ['lines'],
176 new ButtonElement()
177 ..classes = ['expander']
178 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
179 new SpanElement()
180 ..classes = ['percentage']
181 ..title = 'percentage of heap being retained',
182 new SpanElement()..classes = ['name']
183 ];
184 }
185
186 static const int kMaxChildren = 100;
187 static const int kMinRetainedSize = 4096;
188
189 static _getChildrenDominator(M.HeapSnapshotDominatorNode node) {
190 final list = node.children.toList();
191 list.sort((a, b) => b.retainedSize - a.retainedSize);
192 return list
193 .where((child) => child.retainedSize >= kMinRetainedSize)
194 .take(kMaxChildren);
195 }
196
197 void _updateDominator(
198 HtmlElement element, M.HeapSnapshotDominatorNode node, int depth) {
199 element.children[0].text = Utils.formatSize(node.retainedSize);
200 _updateLines(element.children[1].children, depth);
201 if (_getChildrenDominator(node).isNotEmpty) {
202 element.children[2].text = _tree.isExpanded(node) ? '▼' : '►';
203 } else {
204 element.children[2].text = '';
205 }
206 element.children[3].text =
207 Utils.formatPercentNormalized(node.retainedSize * 1.0 / _snapshot.size);
208 final wrapper = new SpanElement()
209 ..classes = ['name']
210 ..text = 'Loading...';
211 element.children[4] = wrapper;
212 if (node.isStack) {
213 wrapper
214 ..text = ''
215 ..children = [
216 new AnchorElement(href: Uris.debugger(isolate))..text = 'stack frames'
217 ];
218 } else {
219 node.object.then((object) {
220 wrapper
221 ..text = ''
222 ..children = [
223 anyRef(_isolate, object, _objects,
224 queue: _r.queue, expandable: false)
225 ];
226 });
227 }
228 Element.clickEvent
229 .forTarget(element.children[4], useCapture: true)
230 .listen((e) {
231 if (_editor.isAvailable) {
232 e.preventDefault();
233 _sendNodeToEditor(node);
234 }
235 });
236 }
237
238 Future _sendNodeToEditor(M.HeapSnapshotDominatorNode node) async {
239 final object = await node.object;
240 if (node.isStack) {
241 // TODO (https://github.com/flutter/flutter-intellij/issues/1290)
242 // open debugger
243 return new Future.value();
244 }
245 _editor.openObject(_isolate, object);
246 }
247
248 static _updateLines(List<Element> lines, int n) {
249 n = Math.max(0, n);
250 while (lines.length > n) {
251 lines.removeLast();
252 }
253 while (lines.length < n) {
254 lines.add(new SpanElement());
255 }
256 }
257
258 static String rootsToString(M.HeapSnapshotRoots roots) {
259 switch (roots) {
260 case M.HeapSnapshotRoots.user:
261 return 'User';
262 case M.HeapSnapshotRoots.vm:
263 return 'VM';
264 }
265 throw new Exception('Unknown HeapSnapshotRoots');
266 }
267 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/memory/profile.dart ('k') | runtime/observatory/lib/src/models/repositories/editor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698