| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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 library heap_profile_element; | 5 library heap_profile_element; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 import 'observatory_element.dart'; | 9 import 'observatory_element.dart'; |
| 10 import 'package:charted/charted.dart'; |
| 10 import 'package:observatory/app.dart'; | 11 import 'package:observatory/app.dart'; |
| 11 import 'package:observatory/service.dart'; | 12 import 'package:observatory/service.dart'; |
| 12 import 'package:observatory/elements.dart'; | 13 import 'package:observatory/elements.dart'; |
| 13 import 'package:polymer/polymer.dart'; | 14 import 'package:polymer/polymer.dart'; |
| 14 | 15 |
| 15 class ClassSortedTable extends SortedTable { | 16 class ClassSortedTable extends SortedTable { |
| 16 | 17 |
| 17 ClassSortedTable(columns) : super(columns); | 18 ClassSortedTable(columns) : super(columns); |
| 18 | 19 |
| 19 @override | 20 @override |
| 20 dynamic getSortKeyFor(int row, int col) { | 21 dynamic getSortKeyFor(int row, int col) { |
| 21 if (col == 0) { | 22 if (col == 0) { |
| 22 // Use class name as sort key. | 23 // Use class name as sort key. |
| 23 return rows[row].values[col].name; | 24 return rows[row].values[col].name; |
| 24 } | 25 } |
| 25 return super.getSortKeyFor(row, col); | 26 return super.getSortKeyFor(row, col); |
| 26 } | 27 } |
| 27 } | 28 } |
| 28 | 29 |
| 29 @CustomTag('heap-profile') | 30 @CustomTag('heap-profile') |
| 30 class HeapProfileElement extends ObservatoryElement { | 31 class HeapProfileElement extends ObservatoryElement { |
| 31 @observable String lastServiceGC = '---'; | 32 @observable String lastServiceGC = '---'; |
| 32 @observable String lastAccumulatorReset = '---'; | 33 @observable String lastAccumulatorReset = '---'; |
| 33 | 34 |
| 34 // Pie chart of new space usage. | 35 // Pie chart of new space usage. |
| 35 var _newPieDataTable; | |
| 36 var _newPieChart; | 36 var _newPieChart; |
| 37 | 37 final _newPieChartRows = []; |
| 38 // Pie chart of old space usage. | 38 // Pie chart of old space usage. |
| 39 var _oldPieDataTable; | |
| 40 var _oldPieChart; | 39 var _oldPieChart; |
| 40 final _oldPieChartRows = []; |
| 41 | 41 |
| 42 @observable ClassSortedTable classTable; | 42 @observable ClassSortedTable classTable; |
| 43 var _classTableBody; | 43 var _classTableBody; |
| 44 | 44 |
| 45 @published bool autoRefresh = false; | 45 @published bool autoRefresh = false; |
| 46 var _subscriptionFuture; | 46 var _subscriptionFuture; |
| 47 | 47 |
| 48 @published Isolate isolate; | 48 @published Isolate isolate; |
| 49 @observable ServiceMap profile; | 49 @observable ServiceMap profile; |
| 50 | 50 |
| 51 final _pieChartColumns = [ |
| 52 new ChartColumnSpec(label: 'Type', type: ChartColumnSpec.TYPE_STRING), |
| 53 new ChartColumnSpec(label: 'Size', formatter: (v) => v.toString()) |
| 54 ]; |
| 55 |
| 51 HeapProfileElement.created() : super.created() { | 56 HeapProfileElement.created() : super.created() { |
| 52 // Create pie chart models. | 57 _initPieChartData(_newPieChartRows); |
| 53 _newPieDataTable = new DataTable(); | 58 _initPieChartData(_oldPieChartRows); |
| 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 | 59 |
| 60 // Create class table model. | 60 // Create class table model. |
| 61 var columns = [ | 61 var columns = [ |
| 62 new SortedTableColumn('Class'), | 62 new SortedTableColumn('Class'), |
| 63 new SortedTableColumn(''), // Spacer column. | 63 new SortedTableColumn(''), // Spacer column. |
| 64 new SortedTableColumn.withFormatter('Accumulated Size (New)', | 64 new SortedTableColumn.withFormatter('Accumulated Size (New)', |
| 65 Utils.formatSize), | 65 Utils.formatSize), |
| 66 new SortedTableColumn.withFormatter('Accumulated Instances', | 66 new SortedTableColumn.withFormatter('Accumulated Instances', |
| 67 Utils.formatCommaSeparated), | 67 Utils.formatCommaSeparated), |
| 68 new SortedTableColumn.withFormatter('Current Size', | 68 new SortedTableColumn.withFormatter('Current Size', |
| 69 Utils.formatSize), | 69 Utils.formatSize), |
| 70 new SortedTableColumn.withFormatter('Current Instances', | 70 new SortedTableColumn.withFormatter('Current Instances', |
| 71 Utils.formatCommaSeparated), | 71 Utils.formatCommaSeparated), |
| 72 new SortedTableColumn(''), // Spacer column. | 72 new SortedTableColumn(''), // Spacer column. |
| 73 new SortedTableColumn.withFormatter('Accumulator Size (Old)', | 73 new SortedTableColumn.withFormatter('Accumulator Size (Old)', |
| 74 Utils.formatSize), | 74 Utils.formatSize), |
| 75 new SortedTableColumn.withFormatter('Accumulator Instances', | 75 new SortedTableColumn.withFormatter('Accumulator Instances', |
| 76 Utils.formatCommaSeparated), | 76 Utils.formatCommaSeparated), |
| 77 new SortedTableColumn.withFormatter('Current Size', | 77 new SortedTableColumn.withFormatter('Current Size', |
| 78 Utils.formatSize), | 78 Utils.formatSize), |
| 79 new SortedTableColumn.withFormatter('Current Instances', | 79 new SortedTableColumn.withFormatter('Current Instances', |
| 80 Utils.formatCommaSeparated) | 80 Utils.formatCommaSeparated) |
| 81 ]; | 81 ]; |
| 82 classTable = new ClassSortedTable(columns); | 82 classTable = new ClassSortedTable(columns); |
| 83 // By default, start with accumulated new space bytes. | 83 // By default, start with accumulated new space bytes. |
| 84 classTable.sortColumnIndex = 2; | 84 classTable.sortColumnIndex = 2; |
| 85 } | 85 } |
| 86 | 86 |
| 87 LayoutArea _makePieChart(String id, List rows) { |
| 88 var wrapper = shadowRoot.querySelector(id); |
| 89 var areaHost = wrapper.querySelector('.chart-host'); |
| 90 assert(areaHost != null); |
| 91 var legendHost = wrapper.querySelector('.chart-legend-host'); |
| 92 assert(legendHost != null); |
| 93 var series = new ChartSeries(id, [1], new PieChartRenderer( |
| 94 sortDataByValue: false |
| 95 )); |
| 96 var config = new ChartConfig([series], [0]); |
| 97 config.minimumSize = new Rect(300, 300); |
| 98 config.legend = new ChartLegend(legendHost, showValues: true); |
| 99 var data = new ChartData(_pieChartColumns, rows); |
| 100 var area = new LayoutArea(areaHost, |
| 101 data, |
| 102 config, |
| 103 state: new ChartState(), |
| 104 autoUpdate: false); |
| 105 area.addChartBehavior(new Hovercard()); |
| 106 area.addChartBehavior(new AxisLabelTooltip()); |
| 107 return area; |
| 108 } |
| 109 |
| 87 @override | 110 @override |
| 88 void attached() { | 111 void attached() { |
| 89 super.attached(); | 112 super.attached(); |
| 90 // Grab the pie chart divs. | 113 _newPieChart = _makePieChart('#new-pie-chart', _newPieChartRows); |
| 91 _newPieChart = new Chart('PieChart', | 114 _oldPieChart = _makePieChart('#old-pie-chart', _oldPieChartRows); |
| 92 shadowRoot.querySelector('#newPieChart')); | |
| 93 _oldPieChart = new Chart('PieChart', | |
| 94 shadowRoot.querySelector('#oldPieChart')); | |
| 95 _classTableBody = shadowRoot.querySelector('#classTableBody'); | 115 _classTableBody = shadowRoot.querySelector('#classTableBody'); |
| 96 _subscriptionFuture = | 116 _subscriptionFuture = |
| 97 app.vm.listenEventStream(VM.kGCStream, _onEvent); | 117 app.vm.listenEventStream(VM.kGCStream, _onEvent); |
| 98 } | 118 } |
| 99 | 119 |
| 100 @override | 120 @override |
| 101 void detached() { | 121 void detached() { |
| 102 cancelFutureSubscription(_subscriptionFuture); | 122 cancelFutureSubscription(_subscriptionFuture); |
| 103 _subscriptionFuture = null; | 123 _subscriptionFuture = null; |
| 104 super.detached(); | 124 super.detached(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 125 refreshAutoQueued = false; | 145 refreshAutoQueued = false; |
| 126 refresh().then((_) { | 146 refresh().then((_) { |
| 127 refreshAutoPending = false; | 147 refreshAutoPending = false; |
| 128 // Keep refreshing if at least one GC event was received while waiting. | 148 // Keep refreshing if at least one GC event was received while waiting. |
| 129 if (refreshAutoQueued) { | 149 if (refreshAutoQueued) { |
| 130 refreshAuto(); | 150 refreshAuto(); |
| 131 } | 151 } |
| 132 }).catchError(app.handleException); | 152 }).catchError(app.handleException); |
| 133 } | 153 } |
| 134 | 154 |
| 155 static const _USED_INDEX = 0; |
| 156 static const _FREE_INDEX = 1; |
| 157 static const _EXTERNAL_INDEX = 2; |
| 158 |
| 159 static const _LABEL_INDEX = 0; |
| 160 static const _VALUE_INDEX = 1; |
| 161 |
| 162 void _initPieChartData(List rows) { |
| 163 rows.add(['Used', 0]); |
| 164 rows.add(['Free', 0]); |
| 165 rows.add(['External', 0]); |
| 166 } |
| 167 |
| 168 void _updatePieChartData(List rows, HeapSpace space) { |
| 169 rows[_USED_INDEX][_VALUE_INDEX] = space.used; |
| 170 rows[_FREE_INDEX][_VALUE_INDEX] = space.capacity - space.used; |
| 171 rows[_EXTERNAL_INDEX][_VALUE_INDEX] = space.external; |
| 172 } |
| 173 |
| 135 void _updatePieCharts() { | 174 void _updatePieCharts() { |
| 136 assert(profile != null); | 175 assert(profile != null); |
| 137 _newPieDataTable.clearRows(); | 176 _updatePieChartData(_newPieChartRows, isolate.newSpace); |
| 138 _newPieDataTable.addRow(['Used', isolate.newSpace.used]); | 177 _updatePieChartData(_oldPieChartRows, isolate.oldSpace); |
| 139 _newPieDataTable.addRow(['Free', | |
| 140 isolate.newSpace.capacity - isolate.newSpace.used]); | |
| 141 _newPieDataTable.addRow(['External', isolate.newSpace.external]); | |
| 142 _oldPieDataTable.clearRows(); | |
| 143 _oldPieDataTable.addRow(['Used', isolate.oldSpace.used]); | |
| 144 _oldPieDataTable.addRow(['Free', | |
| 145 isolate.oldSpace.capacity - isolate.oldSpace.used]); | |
| 146 _oldPieDataTable.addRow(['External', isolate.oldSpace.external]); | |
| 147 } | 178 } |
| 148 | 179 |
| 149 void _updateClasses() { | 180 void _updateClasses() { |
| 150 for (ServiceMap clsAllocations in profile['members']) { | 181 for (ServiceMap clsAllocations in profile['members']) { |
| 151 Class cls = clsAllocations['class']; | 182 Class cls = clsAllocations['class']; |
| 152 if (cls == null) { | 183 if (cls == null) { |
| 153 continue; | 184 continue; |
| 154 } | 185 } |
| 155 cls.newSpace.update(clsAllocations['new']); | 186 cls.newSpace.update(clsAllocations['new']); |
| 156 cls.oldSpace.update(clsAllocations['old']); | 187 cls.oldSpace.update(clsAllocations['old']); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 assert(_classTableBody.children.length == classTable.sortedRows.length); | 292 assert(_classTableBody.children.length == classTable.sortedRows.length); |
| 262 // Fill table. | 293 // Fill table. |
| 263 for (var i = 0; i < classTable.sortedRows.length; i++) { | 294 for (var i = 0; i < classTable.sortedRows.length; i++) { |
| 264 var rowIndex = classTable.sortedRows[i]; | 295 var rowIndex = classTable.sortedRows[i]; |
| 265 var tr = _classTableBody.children[i]; | 296 var tr = _classTableBody.children[i]; |
| 266 _fillClassTableDomRow(tr, rowIndex); | 297 _fillClassTableDomRow(tr, rowIndex); |
| 267 } | 298 } |
| 268 } | 299 } |
| 269 | 300 |
| 270 void _drawCharts() { | 301 void _drawCharts() { |
| 271 _newPieChart.draw(_newPieDataTable); | 302 _newPieChart.draw(); |
| 272 _oldPieChart.draw(_oldPieDataTable); | 303 _oldPieChart.draw(); |
| 273 } | 304 } |
| 274 | 305 |
| 275 @observable void changeSort(Event e, var detail, Element target) { | 306 @observable void changeSort(Event e, var detail, Element target) { |
| 276 if (target is TableCellElement) { | 307 if (target is TableCellElement) { |
| 277 if (classTable.sortColumnIndex != target.cellIndex) { | 308 if (classTable.sortColumnIndex != target.cellIndex) { |
| 278 classTable.sortColumnIndex = target.cellIndex; | 309 classTable.sortColumnIndex = target.cellIndex; |
| 279 classTable.sortDescending = true; | 310 classTable.sortDescending = true; |
| 280 } else { | 311 } else { |
| 281 classTable.sortDescending = !classTable.sortDescending; | 312 classTable.sortDescending = !classTable.sortDescending; |
| 282 } | 313 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 } | 397 } |
| 367 | 398 |
| 368 @observable String formattedTotalCollectionTime(bool newSpace) { | 399 @observable String formattedTotalCollectionTime(bool newSpace) { |
| 369 if (profile == null) { | 400 if (profile == null) { |
| 370 return ''; | 401 return ''; |
| 371 } | 402 } |
| 372 var heap = newSpace ? isolate.newSpace : isolate.oldSpace; | 403 var heap = newSpace ? isolate.newSpace : isolate.oldSpace; |
| 373 return '${Utils.formatSeconds(heap.totalCollectionTimeInSeconds)} secs'; | 404 return '${Utils.formatSeconds(heap.totalCollectionTimeInSeconds)} secs'; |
| 374 } | 405 } |
| 375 } | 406 } |
| OLD | NEW |