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

Side by Side Diff: runtime/bin/vmservice/observatory/lib/src/elements/heap_profile.dart

Issue 810623005: Build Observatory with runtime (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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 library heap_profile_element;
6
7 import 'dart:html';
8 import 'observatory_element.dart';
9 import 'package:observatory/app.dart';
10 import 'package:observatory/service.dart';
11 import 'package:observatory/elements.dart';
12 import 'package:polymer/polymer.dart';
13
14 class ClassSortedTable extends SortedTable {
15
16 ClassSortedTable(columns) : super(columns);
17
18 @override
19 dynamic getSortKeyFor(int row, int col) {
20 if (col == 0) {
21 // Use class name as sort key.
22 return rows[row].values[col].name;
23 }
24 return super.getSortKeyFor(row, col);
25 }
26 }
27
28 /// Displays an Error response.
29 @CustomTag('heap-profile')
30 class HeapProfileElement extends ObservatoryElement {
31 @observable String lastServiceGC = '---';
32 @observable String lastAccumulatorReset = '---';
33
34 // Pie chart of new space usage.
35 var _newPieDataTable;
36 var _newPieChart;
37
38 // Pie chart of old space usage.
39 var _oldPieDataTable;
40 var _oldPieChart;
41
42 @observable ClassSortedTable classTable;
43 var _classTableBody;
44
45 @published ServiceMap profile;
46 @published bool autoRefresh = false;
47 var _subscription;
48
49 @observable Isolate isolate;
50
51 HeapProfileElement.created() : super.created() {
52 // Create pie chart models.
53 _newPieDataTable = new DataTable();
54 _newPieDataTable.addColumn('string', 'Type');
55 _newPieDataTable.addColumn('number', 'Size');
56 _oldPieDataTable = new DataTable();
57 _oldPieDataTable.addColumn('string', 'Type');
58 _oldPieDataTable.addColumn('number', 'Size');
59
60 // Create class table model.
61 var columns = [
62 new SortedTableColumn('Class'),
63 new SortedTableColumn(''), // Spacer column.
64 new SortedTableColumn.withFormatter('Accumulated Size (New)',
65 Utils.formatSize),
66 new SortedTableColumn.withFormatter('Accumulated Instances',
67 Utils.formatCommaSeparated),
68 new SortedTableColumn.withFormatter('Current Size',
69 Utils.formatSize),
70 new SortedTableColumn.withFormatter('Current Instances',
71 Utils.formatCommaSeparated),
72 new SortedTableColumn(''), // Spacer column.
73 new SortedTableColumn.withFormatter('Accumulator Size (Old)',
74 Utils.formatSize),
75 new SortedTableColumn.withFormatter('Accumulator Instances',
76 Utils.formatCommaSeparated),
77 new SortedTableColumn.withFormatter('Current Size',
78 Utils.formatSize),
79 new SortedTableColumn.withFormatter('Current Instances',
80 Utils.formatCommaSeparated)
81 ];
82 classTable = new ClassSortedTable(columns);
83 // By default, start with accumulated new space bytes.
84 classTable.sortColumnIndex = 2;
85 }
86
87 @override
88 void attached() {
89 super.attached();
90 // Grab the pie chart divs.
91 _newPieChart = new Chart('PieChart',
92 shadowRoot.querySelector('#newPieChart'));
93 _oldPieChart = new Chart('PieChart',
94 shadowRoot.querySelector('#oldPieChart'));
95 _classTableBody = shadowRoot.querySelector('#classTableBody');
96 _subscription = app.vm.events.stream.where(
97 (event) => event.isolate == isolate).listen(_onEvent);
98 }
99
100 @override
101 void detached() {
102 _subscription.cancel((){});
103 super.detached();
104 }
105
106 void _onEvent(ServiceEvent event) {
107 if (autoRefresh && event.eventType == 'GC') {
108 refresh((){});
109 }
110 }
111
112 void _updatePieCharts() {
113 assert(profile != null);
114 _newPieDataTable.clearRows();
115 var isolate = profile.isolate;
116 _newPieDataTable.addRow(['Used', isolate.newSpace.used]);
117 _newPieDataTable.addRow(['Free',
118 isolate.newSpace.capacity - isolate.newSpace.used]);
119 _newPieDataTable.addRow(['External', isolate.newSpace.external]);
120 _oldPieDataTable.clearRows();
121 _oldPieDataTable.addRow(['Used', isolate.oldSpace.used]);
122 _oldPieDataTable.addRow(['Free',
123 isolate.oldSpace.capacity - isolate.oldSpace.used]);
124 _oldPieDataTable.addRow(['External', isolate.oldSpace.external]);
125 }
126
127 void _updateClasses() {
128 for (ServiceMap clsAllocations in profile['members']) {
129 Class cls = clsAllocations['class'];
130 if (cls == null) {
131 continue;
132 }
133 cls.newSpace.update(clsAllocations['new']);
134 cls.oldSpace.update(clsAllocations['old']);
135 }
136 }
137
138 void _updateClassTable() {
139 classTable.clearRows();
140 for (ServiceMap clsAllocations in profile['members']) {
141 Class cls = clsAllocations['class'];
142 if (cls == null) {
143 continue;
144 }
145 if (cls.hasNoAllocations) {
146 // If a class has no allocations, don't display it.
147 continue;
148 }
149 var row = [cls,
150 '', // Spacer column.
151 cls.newSpace.accumulated.bytes,
152 cls.newSpace.accumulated.instances,
153 cls.newSpace.current.bytes,
154 cls.newSpace.current.instances,
155 '', // Spacer column.
156 cls.oldSpace.accumulated.bytes,
157 cls.oldSpace.accumulated.instances,
158 cls.oldSpace.current.bytes,
159 cls.oldSpace.current.instances];
160 classTable.addRow(new SortedTableRow(row));
161 }
162 classTable.sort();
163 }
164
165 void _addClassTableDomRow() {
166 assert(_classTableBody != null);
167 var tr = new TableRowElement();
168
169 // Add class ref.
170 var cell = tr.insertCell(-1);
171 ClassRefElement classRef = new Element.tag('class-ref');
172 cell.children.add(classRef);
173
174 // Add spacer.
175 cell = tr.insertCell(-1);
176 cell.classes.add('left-border-spacer');
177
178 // Add new space.
179 cell = tr.insertCell(-1);
180 cell = tr.insertCell(-1);
181 cell = tr.insertCell(-1);
182 cell = tr.insertCell(-1);
183
184 // Add spacer.
185 cell = tr.insertCell(-1);
186 cell.classes.add('left-border-spacer');
187
188 // Add old space.
189 cell = tr.insertCell(-1);
190 cell = tr.insertCell(-1);
191 cell = tr.insertCell(-1);
192 cell = tr.insertCell(-1);
193
194 // Add row to table.
195 _classTableBody.children.add(tr);
196 }
197
198 void _fillClassTableDomRow(TableRowElement tr, int rowIndex) {
199 const SPACER_COLUMNS = const [1, 6];
200
201 var row = classTable.rows[rowIndex];
202 // Add class ref.
203 ClassRefElement classRef = tr.children[0].children[0];
204 classRef.ref = row.values[0];
205
206 for (var i = 1; i < row.values.length; i++) {
207 if (SPACER_COLUMNS.contains(i)) {
208 // Skip spacer columns.
209 continue;
210 }
211 var cell = tr.children[i];
212 cell.title = row.values[i].toString();
213 cell.text = classTable.getFormattedValue(rowIndex, i);
214 }
215 }
216
217 void _updateClassTableInDom() {
218 assert(_classTableBody != null);
219 // Resize DOM table.
220 if (_classTableBody.children.length > classTable.sortedRows.length) {
221 // Shrink the table.
222 var deadRows =
223 _classTableBody.children.length - classTable.sortedRows.length;
224 for (var i = 0; i < deadRows; i++) {
225 _classTableBody.children.removeLast();
226 }
227 } else if (_classTableBody.children.length < classTable.sortedRows.length) {
228 // Grow table.
229 var newRows =
230 classTable.sortedRows.length - _classTableBody.children.length;
231 for (var i = 0; i < newRows; i++) {
232 _addClassTableDomRow();
233 }
234 }
235 assert(_classTableBody.children.length == classTable.sortedRows.length);
236 // Fill table.
237 for (var i = 0; i < classTable.sortedRows.length; i++) {
238 var rowIndex = classTable.sortedRows[i];
239 var tr = _classTableBody.children[i];
240 _fillClassTableDomRow(tr, rowIndex);
241 }
242 }
243
244 void _drawCharts() {
245 _newPieChart.draw(_newPieDataTable);
246 _oldPieChart.draw(_oldPieDataTable);
247 }
248
249 @observable void changeSort(Event e, var detail, Element target) {
250 if (target is TableCellElement) {
251 if (classTable.sortColumnIndex != target.cellIndex) {
252 classTable.sortColumnIndex = target.cellIndex;
253 classTable.sortDescending = true;
254 } else {
255 classTable.sortDescending = !classTable.sortDescending;
256 }
257 classTable.sort();
258 _updateClassTableInDom();
259 }
260 }
261
262 void refresh(var done) {
263 if (profile == null) {
264 return;
265 }
266 var isolate = profile.isolate;
267 isolate.get('/allocationprofile').then(_update).whenComplete(done);
268 }
269
270 void refreshGC(var done) {
271 if (profile == null) {
272 return;
273 }
274 var isolate = profile.isolate;
275 isolate.get('/allocationprofile?gc=full').then(_update).whenComplete(done);
276 }
277
278 void resetAccumulator(var done) {
279 if (profile == null) {
280 return;
281 }
282 var isolate = profile.isolate;
283 isolate.get('/allocationprofile?reset=true').then(_update).
284 whenComplete(done);
285 }
286
287 void _update(ServiceMap newProfile) {
288 profile = newProfile;
289 }
290
291 void profileChanged(oldValue) {
292 if (profile == null) {
293 return;
294 }
295 isolate = profile.isolate;
296 isolate.updateHeapsFromMap(profile['heaps']);
297 var millis = int.parse(profile['dateLastAccumulatorReset']);
298 if (millis != 0) {
299 lastAccumulatorReset =
300 new DateTime.fromMillisecondsSinceEpoch(millis).toString();
301 }
302 millis = int.parse(profile['dateLastServiceGC']);
303 if (millis != 0) {
304 lastServiceGC =
305 new DateTime.fromMillisecondsSinceEpoch(millis).toString();
306 }
307 _updatePieCharts();
308 _updateClasses();
309 _updateClassTable();
310 _updateClassTableInDom();
311 _drawCharts();
312 notifyPropertyChange(#formattedAverage, 0, 1);
313 notifyPropertyChange(#formattedTotalCollectionTime, 0, 1);
314 notifyPropertyChange(#formattedCollections, 0, 1);
315 }
316
317 @observable String formattedAverage(bool newSpace) {
318 if (profile == null) {
319 return '';
320 }
321 var heap = newSpace ? profile.isolate.newSpace : profile.isolate.oldSpace;
322 var avg = ((heap.totalCollectionTimeInSeconds * 1000.0) / heap.collections);
323 return '${avg.toStringAsFixed(2)} ms';
324 }
325
326 @observable String formattedCollections(bool newSpace) {
327 if (profile == null) {
328 return '';
329 }
330 var heap = newSpace ? profile.isolate.newSpace : profile.isolate.oldSpace;
331 return heap.collections.toString();
332 }
333
334 @observable String formattedTotalCollectionTime(bool newSpace) {
335 if (profile == null) {
336 return '';
337 }
338 var heap = newSpace ? profile.isolate.newSpace : profile.isolate.oldSpace;
339 return '${Utils.formatSeconds(heap.totalCollectionTimeInSeconds)} secs';
340 }
341 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698