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