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