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

Side by Side Diff: runtime/observatory/lib/src/elements/memory/profile.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
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// This Element is part of MemoryDashboardElement. 5 /// This Element is part of MemoryDashboardElement.
6 /// 6 ///
7 /// The Element is stripped down version of AllocationProfileElement where 7 /// The Element is stripped down version of AllocationProfileElement where
8 /// concepts like old and new space has been hidden away. 8 /// concepts like old and new space has been hidden away.
9 /// 9 ///
10 /// For each class in the system it is shown the Total number of instances 10 /// For each class in the system it is shown the Total number of instances
11 /// alive, the Total memory used by these instances, the number of instances 11 /// alive, the Total memory used by these instances, the number of instances
12 /// created since the last reset, the memory used by these instances. 12 /// created since the last reset, the memory used by these instances.
13 /// 13 ///
14 /// When a GC event is received the profile is reloaded. 14 /// When a GC event is received the profile is reloaded.
15 15
16 import 'dart:async'; 16 import 'dart:async';
17 import 'dart:html'; 17 import 'dart:html';
18 import 'package:observatory/models.dart' as M; 18 import 'package:observatory/models.dart' as M;
19 import 'package:observatory/src/elements/class_ref.dart';
20 import 'package:observatory/src/elements/containers/virtual_collection.dart';
21 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; 19 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
22 import 'package:observatory/src/elements/helpers/tag.dart'; 20 import 'package:observatory/src/elements/helpers/tag.dart';
23 import 'package:observatory/utils.dart'; 21 import 'package:observatory/src/elements/memory/allocations.dart';
22 import 'package:observatory/src/elements/memory/snapshot.dart';
24 23
25 enum _SortingField { 24 enum _Analysis { allocations, dominatorTree }
26 accumulatedSize,
27 accumulatedInstances,
28 currentSize,
29 currentInstances,
30 className,
31 }
32
33 enum _SortingDirection { ascending, descending }
34 25
35 class MemoryProfileElement extends HtmlElement implements Renderable { 26 class MemoryProfileElement extends HtmlElement implements Renderable {
36 static const tag = const Tag<MemoryProfileElement>('memory-profile', 27 static const tag = const Tag<MemoryProfileElement>('memory-profile',
37 dependencies: const [ClassRefElement.tag, VirtualCollectionElement.tag]); 28 dependencies: const [
29 MemoryAllocationsElement.tag,
30 MemorySnapshotElement.tag
31 ]);
38 32
39 RenderingScheduler<MemoryProfileElement> _r; 33 RenderingScheduler<MemoryProfileElement> _r;
40 34
41 Stream<RenderedEvent<MemoryProfileElement>> get onRendered => _r.onRendered; 35 Stream<RenderedEvent<MemoryProfileElement>> get onRendered => _r.onRendered;
42 36
43 M.IsolateRef _isolate; 37 M.IsolateRef _isolate;
44 M.EventRepository _events; 38 M.EventRepository _events;
45 M.AllocationProfileRepository _repository; 39 M.AllocationProfileRepository _allocations;
46 M.AllocationProfile _profile;
47 M.EditorRepository _editor; 40 M.EditorRepository _editor;
48 StreamSubscription _gcSubscription; 41 M.HeapSnapshotRepository _snapshots;
49 _SortingField _sortingField = _SortingField.accumulatedInstances; 42 M.ObjectRepository _objects;
50 _SortingDirection _sortingDirection = _SortingDirection.descending; 43
44 _Analysis _analysis = _Analysis.allocations;
51 45
52 M.IsolateRef get isolate => _isolate; 46 M.IsolateRef get isolate => _isolate;
53 47
54 factory MemoryProfileElement(M.IsolateRef isolate, M.EditorRepository editor, 48 factory MemoryProfileElement(
55 M.EventRepository events, M.AllocationProfileRepository repository, 49 M.IsolateRef isolate,
50 M.EditorRepository editor,
51 M.EventRepository events,
52 M.AllocationProfileRepository allocations,
53 M.HeapSnapshotRepository snapshots,
54 M.ObjectRepository objects,
56 {RenderingQueue queue}) { 55 {RenderingQueue queue}) {
57 assert(isolate != null); 56 assert(isolate != null);
58 assert(events != null); 57 assert(events != null);
59 assert(editor != null); 58 assert(editor != null);
60 assert(repository != null); 59 assert(allocations != null);
60 assert(snapshots != null);
61 assert(objects != null);
61 MemoryProfileElement e = document.createElement(tag.name); 62 MemoryProfileElement e = document.createElement(tag.name);
62 e._r = new RenderingScheduler(e, queue: queue); 63 e._r = new RenderingScheduler(e, queue: queue);
63 e._isolate = isolate; 64 e._isolate = isolate;
64 e._editor = editor; 65 e._editor = editor;
65 e._events = events; 66 e._events = events;
66 e._repository = repository; 67 e._allocations = allocations;
68 e._snapshots = snapshots;
69 e._objects = objects;
67 return e; 70 return e;
68 } 71 }
69 72
70 MemoryProfileElement.created() : super.created(); 73 MemoryProfileElement.created() : super.created();
71 74
72 @override 75 @override
73 attached() { 76 attached() {
74 super.attached(); 77 super.attached();
75 _r.enable(); 78 _r.enable();
76 _refresh();
77 _gcSubscription = _events.onGCEvent.listen((e) {
78 if (e.isolate.id == _isolate.id) {
79 _refresh();
80 }
81 });
82 } 79 }
83 80
84 @override 81 @override
85 detached() { 82 detached() {
86 super.detached(); 83 super.detached();
87 _r.disable(notify: true); 84 _r.disable(notify: true);
88 children = []; 85 children = [];
89 _gcSubscription.cancel();
90 }
91
92 Future reload({bool gc = false, bool reset = false}) async {
93 return _refresh(gc: gc, reset: reset);
94 } 86 }
95 87
96 void render() { 88 void render() {
97 if (_profile == null) { 89 HtmlElement current;
98 children = [ 90 var reload;
99 new DivElement() 91 switch (_analysis) {
100 ..classes = ['content-centered-big'] 92 case _Analysis.allocations:
101 ..children = [new HeadingElement.h2()..text = 'Loading...'] 93 final MemoryAllocationsElement allocations =
102 ]; 94 new MemoryAllocationsElement(
103 } else { 95 _isolate, _editor, _events, _allocations);
104 children = [ 96 current = allocations;
105 new VirtualCollectionElement( 97 reload = ({bool gc: false}) => allocations.reload(gc: gc);
106 _createCollectionLine, _updateCollectionLine,
107 createHeader: _createCollectionHeader,
108 items: _profile.members.toList()..sort(_createSorter()),
109 queue: _r.queue)
110 ];
111 }
112 }
113
114 _createSorter() {
115 var getter;
116 switch (_sortingField) {
117 case _SortingField.accumulatedSize:
118 getter = _getAccumulatedSize;
119 break; 98 break;
120 case _SortingField.accumulatedInstances: 99 case _Analysis.dominatorTree:
121 getter = _getAccumulatedInstances; 100 final MemorySnapshotElement snapshot =
122 break; 101 new MemorySnapshotElement(_isolate, _editor, _snapshots, _objects);
123 case _SortingField.currentSize: 102 current = snapshot;
124 getter = _getCurrentSize; 103 reload = ({bool gc: false}) => snapshot.reload(gc: gc);
125 break;
126 case _SortingField.currentInstances:
127 getter = _getCurrentInstances;
128 break;
129 case _SortingField.className:
130 getter = (M.ClassHeapStats s) => s.clazz.name;
131 break; 104 break;
132 } 105 }
133 switch (_sortingDirection) {
134 case _SortingDirection.ascending:
135 return (a, b) => getter(a).compareTo(getter(b));
136 case _SortingDirection.descending:
137 return (a, b) => getter(b).compareTo(getter(a));
138 }
139 }
140 106
141 static HtmlElement _createCollectionLine() => new DivElement() 107 assert(current != null);
142 ..classes = ['collection-item']
143 ..children = [
144 new SpanElement()
145 ..classes = ['bytes']
146 ..text = '0B',
147 new SpanElement()
148 ..classes = ['instances']
149 ..text = '0',
150 new SpanElement()
151 ..classes = ['bytes']
152 ..text = '0B',
153 new SpanElement()
154 ..classes = ['instances']
155 ..text = '0',
156 new SpanElement()..classes = ['name']
157 ];
158 108
159 List<HtmlElement> _createCollectionHeader() { 109 final ButtonElement bReload = new ButtonElement();
160 final resetAccumulators = new ButtonElement(); 110 final ButtonElement bGC = new ButtonElement();
161 return [ 111 children = [
162 new DivElement() 112 new DivElement()
163 ..classes = ['collection-item'] 113 ..classes = ['content-centered-big']
164 ..children = [ 114 ..children = [
165 new SpanElement() 115 new HeadingElement.h1()
166 ..classes = ['group']
167 ..children = [ 116 ..children = [
168 new Text('Since Last '), 117 new Text("Isolate ${_isolate.name}"),
169 resetAccumulators 118 bReload
170 ..text = 'Reset↺' 119 ..classes = ['link', 'big']
171 ..title = 'Reset' 120 ..text = ' ↺ '
172 ..onClick.listen((_) async { 121 ..title = 'Refresh'
173 resetAccumulators.disabled = true; 122 ..onClick.listen((e) async {
174 await _refresh(reset: true); 123 bReload.disabled = true;
175 resetAccumulators.disabled = false; 124 bGC.disabled = true;
176 }) 125 await reload();
126 bReload.disabled = false;
127 bGC.disabled = false;
128 }),
129 bGC
130 ..classes = ['link', 'big']
131 ..text = ' ♺ '
132 ..title = 'Collect Garbage'
133 ..onClick.listen((e) async {
134 bGC.disabled = true;
135 bReload.disabled = true;
136 await reload(gc: true);
137 bGC.disabled = false;
138 bReload.disabled = false;
139 }),
140 new ButtonElement()
141 ..classes = ['tab_button']
142 ..text = 'Dominator Tree'
143 ..disabled = _analysis == _Analysis.dominatorTree
144 ..onClick.listen((_) {
145 _analysis = _Analysis.dominatorTree;
146 _r.dirty();
147 }),
148 new ButtonElement()
149 ..classes = ['tab_button']
150 ..text = 'Allocations'
151 ..disabled = _analysis == _Analysis.allocations
152 ..onClick.listen((_) {
153 _analysis = _Analysis.allocations;
154 _r.dirty();
155 }),
177 ], 156 ],
178 new SpanElement()
179 ..classes = ['group']
180 ..text = 'Current'
181 ], 157 ],
182 new DivElement() 158 current
183 ..classes = ['collection-item']
184 ..children = [
185 _createHeaderButton(const ['bytes'], 'Size',
186 _SortingField.accumulatedSize, _SortingDirection.descending),
187 _createHeaderButton(const ['instances'], 'Instances',
188 _SortingField.accumulatedInstances, _SortingDirection.descending),
189 _createHeaderButton(const ['bytes'], 'Size',
190 _SortingField.currentSize, _SortingDirection.descending),
191 _createHeaderButton(const ['instances'], 'Instances',
192 _SortingField.currentInstances, _SortingDirection.descending),
193 _createHeaderButton(const ['name'], 'Class', _SortingField.className,
194 _SortingDirection.ascending)
195 ],
196 ]; 159 ];
197 } 160 }
198
199 ButtonElement _createHeaderButton(List<String> classes, String text,
200 _SortingField field, _SortingDirection direction) =>
201 new ButtonElement()
202 ..classes = classes
203 ..text = _sortingField != field
204 ? text
205 : _sortingDirection == _SortingDirection.ascending
206 ? '$text▼'
207 : '$text▲'
208 ..onClick.listen((_) => _setSorting(field, direction));
209
210 void _setSorting(_SortingField field, _SortingDirection defaultDirection) {
211 if (_sortingField == field) {
212 switch (_sortingDirection) {
213 case _SortingDirection.descending:
214 _sortingDirection = _SortingDirection.ascending;
215 break;
216 case _SortingDirection.ascending:
217 _sortingDirection = _SortingDirection.descending;
218 break;
219 }
220 } else {
221 _sortingDirection = defaultDirection;
222 _sortingField = field;
223 }
224 _r.dirty();
225 }
226
227 void _updateCollectionLine(Element e, M.ClassHeapStats item, index) {
228 e.children[0].text = Utils.formatSize(_getAccumulatedSize(item));
229 e.children[1].text = '${_getAccumulatedInstances(item)}';
230 e.children[2].text = Utils.formatSize(_getCurrentSize(item));
231 e.children[3].text = '${_getCurrentInstances(item)}';
232 e.children[4] = new ClassRefElement(_isolate, item.clazz, queue: _r.queue)
233 ..classes = ['name'];
234 Element.clickEvent.forTarget(e.children[4], useCapture: true).listen((e) {
235 if (_editor.canOpenClass) {
236 e.preventDefault();
237 _editor.openClass(isolate, item.clazz);
238 }
239 });
240 }
241
242 Future _refresh({bool gc: false, bool reset: false}) async {
243 _profile = null;
244 _r.dirty();
245 _profile = await _repository.get(_isolate, gc: gc, reset: reset);
246 _r.dirty();
247 }
248
249 static int _getAccumulatedSize(M.ClassHeapStats s) =>
250 s.newSpace.accumulated.bytes + s.oldSpace.accumulated.bytes;
251 static int _getAccumulatedInstances(M.ClassHeapStats s) =>
252 s.newSpace.accumulated.instances + s.oldSpace.accumulated.instances;
253 static int _getCurrentSize(M.ClassHeapStats s) =>
254 s.newSpace.current.bytes + s.oldSpace.current.bytes;
255 static int _getCurrentInstances(M.ClassHeapStats s) =>
256 s.newSpace.current.instances + s.oldSpace.current.instances;
257 } 161 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/memory/dashboard.dart ('k') | runtime/observatory/lib/src/elements/memory/snapshot.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698