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

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

Issue 2989083002: Add memory-dashboard page to Observatory (Closed)
Patch Set: Addressed 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 /// This Element is part of MemoryDashboardElement.
6 ///
7 /// The Element is stripped down version of AllocationProfileElement where
8 /// concepts like old and new space has been hidden away.
9 ///
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
12 /// created since the last reset, the memory used by these instances.
13 ///
14 /// When a GC event is received the profile is reloaded.
15
16 import 'dart:async';
17 import 'dart:html';
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';
22 import 'package:observatory/src/elements/helpers/tag.dart';
23 import 'package:observatory/utils.dart';
24
25 enum _SortingField {
26 accumulatedSize,
27 accumulatedInstances,
28 currentSize,
29 currentInstances,
30 className,
31 }
32
33 enum _SortingDirection { ascending, descending }
34
35 class MemoryProfileElement extends HtmlElement implements Renderable {
36 static const tag = const Tag<MemoryProfileElement>('memory-profile',
37 dependencies: const [ClassRefElement.tag, VirtualCollectionElement.tag]);
38
39 RenderingScheduler<MemoryProfileElement> _r;
40
41 Stream<RenderedEvent<MemoryProfileElement>> get onRendered => _r.onRendered;
42
43 M.IsolateRef _isolate;
44 M.EventRepository _events;
45 M.AllocationProfileRepository _repository;
46 M.AllocationProfile _profile;
47 M.EditorRepository _editor;
48 StreamSubscription _gcSubscription;
49 _SortingField _sortingField = _SortingField.accumulatedInstances;
50 _SortingDirection _sortingDirection = _SortingDirection.descending;
51
52 M.IsolateRef get isolate => _isolate;
53
54 factory MemoryProfileElement(M.IsolateRef isolate, M.EditorRepository editor,
55 M.EventRepository events, M.AllocationProfileRepository repository,
56 {RenderingQueue queue}) {
57 assert(isolate != null);
58 assert(events != null);
59 assert(editor != null);
60 assert(repository != null);
61 MemoryProfileElement e = document.createElement(tag.name);
62 e._r = new RenderingScheduler(e, queue: queue);
63 e._isolate = isolate;
64 e._editor = editor;
65 e._events = events;
66 e._repository = repository;
67 return e;
68 }
69
70 MemoryProfileElement.created() : super.created();
71
72 @override
73 attached() {
74 super.attached();
75 _r.enable();
76 _refresh();
77 _gcSubscription = _events.onGCEvent.listen((e) {
78 if (e.isolate.id == _isolate.id) {
79 _refresh();
80 }
81 });
82 }
83
84 @override
85 detached() {
86 super.detached();
87 _r.disable(notify: true);
88 children = [];
89 _gcSubscription.cancel();
90 }
91
92 Future reload({bool gc = false, bool reset = false}) async {
93 return _refresh(gc: gc, reset: reset);
94 }
95
96 void render() {
97 if (_profile == null) {
98 children = [
99 new DivElement()
100 ..classes = ['content-centered-big']
101 ..children = [new HeadingElement.h2()..text = 'Loading...']
102 ];
103 } else {
104 children = [
105 new VirtualCollectionElement(
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;
120 case _SortingField.accumulatedInstances:
121 getter = _getAccumulatedInstances;
122 break;
123 case _SortingField.currentSize:
124 getter = _getCurrentSize;
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;
132 }
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
141 static HtmlElement _createCollectionLine() => new DivElement()
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
159 List<HtmlElement> _createCollectionHeader() {
160 final resetAccumulators = new ButtonElement();
161 return [
162 new DivElement()
163 ..classes = ['collection-item']
164 ..children = [
165 new SpanElement()
166 ..classes = ['group']
167 ..children = [
168 new Text('Since Last '),
169 resetAccumulators
170 ..text = 'Reset↺'
171 ..title = 'Reset'
172 ..onClick.listen((_) async {
173 resetAccumulators.disabled = true;
174 await _refresh(reset: true);
175 resetAccumulators.disabled = false;
176 })
177 ],
178 new SpanElement()
179 ..classes = ['group']
180 ..text = 'Current'
181 ],
182 new DivElement()
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 ];
197 }
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 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/memory/graph.dart ('k') | runtime/observatory/lib/src/elements/memory_dashboard.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698