Chromium Code Reviews| Index: runtime/bin/vmservice/client/lib/src/observatory_elements/heap_profile.dart |
| diff --git a/runtime/bin/vmservice/client/lib/src/observatory_elements/heap_profile.dart b/runtime/bin/vmservice/client/lib/src/observatory_elements/heap_profile.dart |
| index 15eb2d609e3d04403240bd165fdc8898082e63c5..af84aa3648e74e1e4b3d82812c97c7d212fdb64c 100644 |
| --- a/runtime/bin/vmservice/client/lib/src/observatory_elements/heap_profile.dart |
| +++ b/runtime/bin/vmservice/client/lib/src/observatory_elements/heap_profile.dart |
| @@ -4,7 +4,9 @@ |
| library heap_profile_element; |
| +import 'dart:async'; |
| import 'dart:html'; |
| +import 'dart:js'; |
| import 'package:logging/logging.dart'; |
| import 'package:polymer/polymer.dart'; |
| import 'observatory_element.dart'; |
| @@ -20,26 +22,108 @@ class HeapProfileElement extends ObservatoryElement { |
| static const ALLOCATED_SINCE_GC = 4; |
| static const ALLOCATED_SINCE_GC_SIZE = 5; |
| + var _newPieOptions; |
| + var _newPieDataTable; |
| + var _newPieChart; |
|
turnidge
2014/01/28 18:28:08
Instead of a making Chart all static, why not make
Cutch
2014/01/28 23:23:19
Refactored Chart wrapper.
|
| + |
| + var _oldPieOptions; |
| + var _oldPieDataTable; |
| + var _oldPieChart; |
| + |
| + var _tableOptions; |
| + var _tableDataTable; |
| + var _tableChart; |
| + |
| @published Map profile; |
| @published List sortedProfile; |
| int _sortColumnIndex = 1; |
| - HeapProfileElement.created() : super.created(); |
| - |
| - // Display columns. |
| - @observable final List<String> columns = [ |
| - 'Class', |
| - 'Current (new)', |
| - 'Allocated Since GC (new)', |
| - 'Total before GC (new)', |
| - 'Survivors (new)', |
| - 'Current (old)', |
| - 'Allocated Since GC (old)', |
| - 'Total before GC (old)', |
| - 'Survivors (old)', |
| - ]; |
| + HeapProfileElement.created() : super.created() { |
| + _tableOptions = new JsObject.jsify({ |
| + 'allowHtml': 'true', |
| + 'sortColumn': 1, |
| + 'sortAscending': false, |
| + }); |
| + _newPieOptions = new JsObject.jsify({ |
| + 'title': 'New Space' |
| + }); |
| + _oldPieOptions = new JsObject.jsify({ |
| + 'title': 'Old Space' |
| + }); |
| + _tableDataTable = Chart.createDataTable(); |
| + Chart.addColumn(_tableDataTable, 'string', 'Class'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Current (new)'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Allocated Since GC (new)'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Total before GC (new)'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Survivors (new)'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Current (old)'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Allocated Since GC (old)'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Total before GC (old)'); |
| + Chart.addColumn(_tableDataTable, 'number', 'Survivors (old)'); |
| + _newPieDataTable = Chart.createDataTable(); |
| + Chart.addColumn(_newPieDataTable, 'string', 'Type'); |
| + Chart.addColumn(_newPieDataTable, 'number', 'Size'); |
| + _oldPieDataTable = Chart.createDataTable(); |
| + Chart.addColumn(_oldPieDataTable, 'string', 'Type'); |
| + Chart.addColumn(_oldPieDataTable, 'number', 'Size'); |
| + } |
| + |
| + void enteredView() { |
| + super.enteredView(); |
| + _tableChart = Chart.createChart('Table', |
| + shadowRoot.querySelector('#table')); |
| + _newPieChart = Chart.createChart('PieChart', |
| + shadowRoot.querySelector('#newPieChart')); |
| + _oldPieChart = Chart.createChart('PieChart', |
| + shadowRoot.querySelector('#oldPieChart')); |
| + _draw(); |
| + } |
| + |
| + void _updateChartData() { |
| + if ((profile == null) || (profile['members'] is! List) || |
| + (profile['members'].length == 0)) { |
| + sortedProfile = toObservable([]); |
| + return; |
| + } |
| + assert(_tableDataTable != null); |
| + Chart.clearRows(_tableDataTable); |
| + for (Map cls in profile['members']) { |
| + var url = |
| + app.locationManager.currentIsolateRelativeLink(cls['class']['id']); |
| + Chart.addRow(_tableDataTable, |
| + ['<a href="$url">${_columnValue(cls, 0)}</a>', |
| + _columnValue(cls, 1), |
| + _columnValue(cls, 2), |
| + _columnValue(cls, 3), |
| + _columnValue(cls, 4), |
| + _columnValue(cls, 5), |
| + _columnValue(cls, 6), |
| + _columnValue(cls, 7), |
| + _columnValue(cls, 8)]); |
| + } |
| + Chart.clearRows(_newPieDataTable); |
| + var heap = profile['heaps']['new']; |
| + Chart.addRow(_newPieDataTable, ['Used', heap['used']]); |
| + Chart.addRow(_newPieDataTable, ['Free', heap['capacity'] - heap['used']]); |
| + Chart.clearRows(_oldPieDataTable); |
| + heap = profile['heaps']['old']; |
| + Chart.addRow(_oldPieDataTable, ['Used', heap['used']]); |
| + Chart.addRow(_oldPieDataTable, ['Free', heap['capacity'] - heap['used']]); |
| + _draw(); |
| + } |
| + |
| + void _draw() { |
| + if (_tableChart == null) { |
| + return; |
| + } |
| + Chart.refreshTableChartDrawOptions(_tableChart, _tableOptions); |
| + Chart.draw(_tableChart, _tableDataTable, _tableOptions); |
| + Chart.draw(_newPieChart, _newPieDataTable, _newPieOptions); |
| + Chart.draw(_oldPieChart, _oldPieDataTable, _oldPieOptions); |
| + } |
| dynamic _columnValue(Map v, int index) { |
| - assert(columns.length == 9); |
| + assert(index >= 0); |
| + assert(index < 9); |
| switch (index) { |
| case 0: |
| return v['class']['user_name']; |
| @@ -62,43 +146,6 @@ class HeapProfileElement extends ObservatoryElement { |
| } |
| } |
| - int _sortColumn(Map a, Map b, int index) { |
| - var aValue = _columnValue(a, index); |
| - var bValue = _columnValue(b, index); |
| - return Comparable.compare(bValue, aValue); |
| - } |
| - |
| - _sort() { |
| - if ((profile == null) || (profile['members'] is! List) || |
| - (profile['members'].length == 0)) { |
| - sortedProfile = toObservable([]); |
| - return; |
| - } |
| - sortedProfile = profile['members'].toList(); |
| - sortedProfile.sort((a, b) => _sortColumn(a, b, _sortColumnIndex)); |
| - sortedProfile = toObservable(sortedProfile); |
| - notifyPropertyChange(#sortedProfile, [], sortedProfile); |
| - notifyPropertyChange(#current, 0, 1); |
| - notifyPropertyChange(#allocated, 0, 1); |
| - notifyPropertyChange(#beforeGC, 0, 1); |
| - notifyPropertyChange(#afterGC, 0, 1); |
| - } |
| - |
| - void changeSortColumn(Event e, var detail, Element target) { |
| - var message = target.attributes['data-msg']; |
| - var index; |
| - try { |
| - index = int.parse(message); |
| - } catch (e) { |
| - return; |
| - } |
| - assert(index is int); |
| - assert(index > 0); |
| - assert(index < columns.length); |
| - _sortColumnIndex = index; |
| - _sort(); |
| - } |
| - |
| void refreshData(Event e, var detail, Node target) { |
| var isolateId = app.locationManager.currentIsolateId(); |
| var isolate = app.isolateManager.getIsolate(isolateId); |
| @@ -116,84 +163,38 @@ class HeapProfileElement extends ObservatoryElement { |
| } |
| void profileChanged(oldValue) { |
| - _sort(); |
| - notifyPropertyChange(#status, [], status); |
| + _updateChartData(); |
| + notifyPropertyChange(#formattedAverage, [], formattedAverage); |
| + notifyPropertyChange(#formattedTotalCollectionTime, [], |
| + formattedTotalCollectionTime); |
| + notifyPropertyChange(#formattedCollections, [], formattedCollections); |
| } |
| - String status(bool new_space) { |
| + @observable String formattedAverage(bool newSpace) { |
| if (profile == null) { |
| return ''; |
| } |
| - String space = new_space ? 'new' : 'old'; |
| + String space = newSpace ? 'new' : 'old'; |
| Map heap = profile['heaps'][space]; |
| - var usage = '${ObservatoryApplication.scaledSizeUnits(heap['used'])} / ' |
| - '${ObservatoryApplication.scaledSizeUnits(heap['capacity'])}'; |
| - var timings = '${ObservatoryApplication.timeUnits(heap['time'])} secs'; |
| - var collections = '${heap['collections']} collections'; |
| - var avgTime = '${(heap['time'] * 1000.0) / heap['collections']} ms'; |
| - return '$usage ($timings) [$collections] $avgTime'; |
| - } |
| - |
| - String current(Map cls, bool new_space, [bool instances = false]) { |
| - if (cls is !Map) { |
| - return ''; |
| - } |
| - List data = cls[new_space ? 'new' : 'old']; |
| - if (data == null) { |
| - return ''; |
| - } |
| - int current = data[instances ? LIVE_AFTER_GC : LIVE_AFTER_GC_SIZE] + |
| - data[instances ? ALLOCATED_SINCE_GC : ALLOCATED_SINCE_GC_SIZE]; |
| - if (instances) { |
| - return '$current'; |
| - } |
| - return ObservatoryApplication.scaledSizeUnits(current); |
| - } |
| - |
| - String allocated(Map cls, bool new_space, [bool instances = false]) { |
| - if (cls is !Map) { |
| - return ''; |
| - } |
| - List data = cls[new_space ? 'new' : 'old']; |
| - if (data == null) { |
| - return ''; |
| - } |
| - int current = |
| - data[instances ? ALLOCATED_SINCE_GC : ALLOCATED_SINCE_GC_SIZE]; |
| - if (instances) { |
| - return '$current'; |
| - } |
| - return ObservatoryApplication.scaledSizeUnits(current); |
| + var r = ((heap['time'] * 1000.0) / heap['collections']).toStringAsFixed(2); |
| + return '$r ms'; |
| } |
| - String beforeGC(Map cls, bool new_space, [bool instances = false]) { |
| - if (cls is! Map) { |
| - return ''; |
| - } |
| - List data = cls[new_space ? 'new' : 'old']; |
| - if (data == null) { |
| + @observable String formattedCollections(bool newSpace) { |
| + if (profile == null) { |
| return ''; |
| } |
| - int current = |
| - data[instances ? ALLOCATED_BEFORE_GC : ALLOCATED_BEFORE_GC_SIZE]; |
| - if (instances) { |
| - return '$current'; |
| - } |
| - return ObservatoryApplication.scaledSizeUnits(current); |
| + String space = newSpace ? 'new' : 'old'; |
| + Map heap = profile['heaps'][space]; |
| + return '${heap['collections']}'; |
| } |
| - String afterGC(Map cls, bool new_space, [bool instances = false]) { |
| - if (cls is! Map) { |
| - return ''; |
| - } |
| - List data = cls[new_space ? 'new' : 'old']; |
| - if (data == null) { |
| + @observable String formattedTotalCollectionTime(bool newSpace) { |
| + if (profile == null) { |
| return ''; |
| } |
| - int current = data[instances ? LIVE_AFTER_GC : LIVE_AFTER_GC_SIZE]; |
| - if (instances) { |
| - return '$current'; |
| - } |
| - return ObservatoryApplication.scaledSizeUnits(current); |
| + String space = newSpace ? 'new' : 'old'; |
| + Map heap = profile['heaps'][space]; |
| + return '${ObservatoryApplication.timeUnits(heap['time'])} secs'; |
| } |
| } |