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

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

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

Powered by Google App Engine
This is Rietveld 408576698