| Index: runtime/bin/vmservice/client/lib/src/elements/heap_profile.dart
|
| diff --git a/runtime/bin/vmservice/client/lib/src/elements/heap_profile.dart b/runtime/bin/vmservice/client/lib/src/elements/heap_profile.dart
|
| index cd64321d4fdae122604ec370dd5f136be3373435..7901dee4e69d3fdc8d53172f5485dd789aee1e4c 100644
|
| --- a/runtime/bin/vmservice/client/lib/src/elements/heap_profile.dart
|
| +++ b/runtime/bin/vmservice/client/lib/src/elements/heap_profile.dart
|
| @@ -6,10 +6,10 @@ library heap_profile_element;
|
|
|
| import 'dart:html';
|
| import 'observatory_element.dart';
|
| +import 'package:observatory/app.dart';
|
| import 'package:observatory/service.dart';
|
| import 'package:logging/logging.dart';
|
| import 'package:polymer/polymer.dart';
|
| -import 'package:observatory/app.dart';
|
|
|
| /// Displays an Error response.
|
| @CustomTag('heap-profile')
|
| @@ -32,103 +32,69 @@ class HeapProfileElement extends ObservatoryElement {
|
| var _oldPieDataTable;
|
| var _oldPieChart;
|
|
|
| - // The combined chart has old and new space merged.
|
| - var _combinedDataTable;
|
| - var _combinedChart;
|
| -
|
| - // The full chart has separate columns for new and old space.
|
| - var _fullDataTable;
|
| - var _fullChart;
|
| + @observable SortedTable classTable;
|
|
|
| @published ServiceMap profile;
|
|
|
| HeapProfileElement.created() : super.created() {
|
| - _fullDataTable = new DataTable();
|
| - _fullDataTable.addColumn('string', 'Class');
|
| - _fullDataTable.addColumn('number', 'Current (new)');
|
| - _fullDataTable.addColumn('number', 'Allocated Since GC (new)');
|
| - _fullDataTable.addColumn('number', 'Total before GC (new)');
|
| - _fullDataTable.addColumn('number', 'Survivors (new)');
|
| - _fullDataTable.addColumn('number', 'Current (old)');
|
| - _fullDataTable.addColumn('number', 'Allocated Since GC (old)');
|
| - _fullDataTable.addColumn('number', 'Total before GC (old)');
|
| - _fullDataTable.addColumn('number', 'Survivors (old)');
|
| _newPieDataTable = new DataTable();
|
| _newPieDataTable.addColumn('string', 'Type');
|
| _newPieDataTable.addColumn('number', 'Size');
|
| _oldPieDataTable = new DataTable();
|
| _oldPieDataTable.addColumn('string', 'Type');
|
| _oldPieDataTable.addColumn('number', 'Size');
|
| - _combinedDataTable = new DataTable();
|
| - _combinedDataTable.addColumn('string', 'Class');
|
| - _combinedDataTable.addColumn('number', 'Accumulator');
|
| - _combinedDataTable.addColumn('number', 'Accumulator Instances');
|
| - _combinedDataTable.addColumn('number', 'Current');
|
| - _combinedDataTable.addColumn('number', 'Allocated Since GC');
|
| - _combinedDataTable.addColumn('number', 'Total before GC');
|
| - _combinedDataTable.addColumn('number', 'Survivors after GC');
|
| + var columns = [
|
| + new SortedTableColumn('Class'),
|
| + new SortedTableColumn.withFormatter('Accumulator',
|
| + Utils.formatSize),
|
| + new SortedTableColumn.withFormatter('Accumulator',
|
| + Utils.formatCommaSeparated),
|
| + new SortedTableColumn.withFormatter('Accumulator (Old space)',
|
| + Utils.formatSize),
|
| + new SortedTableColumn.withFormatter('Accumulator (Old space)',
|
| + Utils.formatCommaSeparated),
|
| + new SortedTableColumn.withFormatter('Current',
|
| + Utils.formatSize),
|
| + new SortedTableColumn.withFormatter('Current',
|
| + Utils.formatCommaSeparated)
|
| + ];
|
| + classTable = new SortedTable(columns);
|
| + classTable.sortColumnIndex = 1;
|
| }
|
|
|
| void enteredView() {
|
| super.enteredView();
|
| - _fullChart = new Chart('Table',
|
| - shadowRoot.querySelector('#table'));
|
| - _fullChart.options['allowHtml'] = true;
|
| - _fullChart.options['sortColumn'] = 1;
|
| - _fullChart.options['sortAscending'] = false;
|
| _newPieChart = new Chart('PieChart',
|
| shadowRoot.querySelector('#newPieChart'));
|
| _newPieChart.options['title'] = 'New Space';
|
| _oldPieChart = new Chart('PieChart',
|
| shadowRoot.querySelector('#oldPieChart'));
|
| _oldPieChart.options['title'] = 'Old Space';
|
| - _combinedChart = new Chart('Table',
|
| - shadowRoot.querySelector('#simpleTable'));
|
| - _combinedChart.options['allowHtml'] = true;
|
| - _combinedChart.options['sortColumn'] = 1;
|
| - _combinedChart.options['sortAscending'] = false;
|
| _draw();
|
| }
|
|
|
| - bool _first = true;
|
| -
|
| void _updateChartData() {
|
| if ((profile == null) || (profile['members'] is! List) ||
|
| (profile['members'].length == 0)) {
|
| return;
|
| }
|
| - assert(_fullDataTable != null);
|
| - assert(_combinedDataTable != null);
|
| - _fullDataTable.clearRows();
|
| - _combinedDataTable.clearRows();
|
| + assert(classTable != null);
|
| + classTable.clearRows();
|
| for (ServiceMap cls in profile['members']) {
|
| if (_classHasNoAllocations(cls)) {
|
| // If a class has no allocations, don't display it.
|
| continue;
|
| }
|
| - var vm_name = cls['class']['name'];
|
| - var url = cls['class'].hashLink;
|
| - _fullDataTable.addRow([
|
| - '<a title="$vm_name" href="$url">'
|
| - '${_fullTableColumnValue(cls, 0)}</a>',
|
| - _fullTableColumnValue(cls, 1),
|
| - _fullTableColumnValue(cls, 2),
|
| - _fullTableColumnValue(cls, 3),
|
| - _fullTableColumnValue(cls, 4),
|
| - _fullTableColumnValue(cls, 5),
|
| - _fullTableColumnValue(cls, 6),
|
| - _fullTableColumnValue(cls, 7),
|
| - _fullTableColumnValue(cls, 8)]);
|
| - _combinedDataTable.addRow([
|
| - '<a title="$vm_name" href="$url">'
|
| - '${_combinedTableColumnValue(cls, 0)}</a>',
|
| - _combinedTableColumnValue(cls, 1),
|
| - _combinedTableColumnValue(cls, 2),
|
| - _combinedTableColumnValue(cls, 3),
|
| - _combinedTableColumnValue(cls, 4),
|
| - _combinedTableColumnValue(cls, 5),
|
| - _combinedTableColumnValue(cls, 6)]);
|
| + var row = [cls['class'],
|
| + _combinedTableColumnValue(cls, 1),
|
| + _combinedTableColumnValue(cls, 2),
|
| + _combinedTableColumnValue(cls, 3),
|
| + _combinedTableColumnValue(cls, 4),
|
| + _combinedTableColumnValue(cls, 5),
|
| + _combinedTableColumnValue(cls, 6)];
|
| + classTable.addRow(new SortedTableRow(row));
|
| }
|
| + classTable.sort();
|
| _newPieDataTable.clearRows();
|
| var heap = profile['heaps']['new'];
|
| _newPieDataTable.addRow(['Used', heap['used']]);
|
| @@ -143,17 +109,22 @@ class HeapProfileElement extends ObservatoryElement {
|
| }
|
|
|
| void _draw() {
|
| - if ((_fullChart == null) || (_combinedChart == null)) {
|
| + if (_newPieChart == null) {
|
| return;
|
| }
|
| - _combinedChart.refreshOptionsSortInfo();
|
| - _combinedChart.draw(_combinedDataTable);
|
| - _fullChart.refreshOptionsSortInfo();
|
| - _fullChart.draw(_fullDataTable);
|
| _newPieChart.draw(_newPieDataTable);
|
| _oldPieChart.draw(_oldPieDataTable);
|
| }
|
|
|
| + @observable void changeSort(Event e, var detail, Element target) {
|
| + if (target is TableCellElement) {
|
| + if (classTable.sortColumnIndex != target.cellIndex) {
|
| + classTable.sortColumnIndex = target.cellIndex;
|
| + classTable.sort();
|
| + }
|
| + }
|
| + }
|
| +
|
| bool _classHasNoAllocations(Map v) {
|
| var newSpace = v['new'];
|
| var oldSpace = v['old'];
|
| @@ -170,32 +141,6 @@ class HeapProfileElement extends ObservatoryElement {
|
| return true;
|
| }
|
|
|
| - dynamic _fullTableColumnValue(Map v, int index) {
|
| - assert(index >= 0);
|
| - assert(index < 9);
|
| - switch (index) {
|
| - case 0:
|
| - return v['class']['user_name'];
|
| - case 1:
|
| - return v['new'][LIVE_AFTER_GC_SIZE] + v['new'][ALLOCATED_SINCE_GC_SIZE];
|
| - case 2:
|
| - return v['new'][ALLOCATED_SINCE_GC_SIZE];
|
| - case 3:
|
| - return v['new'][ALLOCATED_BEFORE_GC_SIZE];
|
| - case 4:
|
| - return v['new'][LIVE_AFTER_GC_SIZE];
|
| - case 5:
|
| - return v['old'][LIVE_AFTER_GC_SIZE] + v['old'][ALLOCATED_SINCE_GC_SIZE];
|
| - case 6:
|
| - return v['old'][ALLOCATED_SINCE_GC_SIZE];
|
| - case 7:
|
| - return v['old'][ALLOCATED_BEFORE_GC_SIZE];
|
| - case 8:
|
| - return v['old'][LIVE_AFTER_GC_SIZE];
|
| - }
|
| - throw new FallThroughError();
|
| - }
|
| -
|
| dynamic _combinedTableColumnValue(Map v, int index) {
|
| assert(index >= 0);
|
| assert(index < 7);
|
| @@ -209,18 +154,19 @@ class HeapProfileElement extends ObservatoryElement {
|
| return v['new'][ACCUMULATED] +
|
| v['old'][ACCUMULATED];
|
| case 3:
|
| + return v['old'][ACCUMULATED_SIZE];
|
| + case 4:
|
| + return v['old'][ACCUMULATED];
|
| + case 5:
|
| return v['new'][LIVE_AFTER_GC_SIZE] +
|
| v['new'][ALLOCATED_SINCE_GC_SIZE] +
|
| v['old'][LIVE_AFTER_GC_SIZE] +
|
| v['old'][ALLOCATED_SINCE_GC_SIZE];
|
| - case 4:
|
| - return v['new'][ALLOCATED_SINCE_GC_SIZE] +
|
| - v['old'][ALLOCATED_SINCE_GC_SIZE];
|
| - case 5:
|
| - return v['new'][ALLOCATED_BEFORE_GC_SIZE] +
|
| - v['old'][ALLOCATED_BEFORE_GC_SIZE];
|
| case 6:
|
| - return v['new'][LIVE_AFTER_GC_SIZE] + v['old'][LIVE_AFTER_GC_SIZE];
|
| + return v['new'][LIVE_AFTER_GC] +
|
| + v['new'][ALLOCATED_SINCE_GC] +
|
| + v['old'][LIVE_AFTER_GC] +
|
| + v['old'][ALLOCATED_SINCE_GC];
|
| }
|
| throw new FallThroughError();
|
| }
|
| @@ -229,7 +175,8 @@ class HeapProfileElement extends ObservatoryElement {
|
| if (profile == null) {
|
| return;
|
| }
|
| - profile.isolate.get('/allocationprofile').then((ServiceMap response) {
|
| + var isolate = profile.isolate;
|
| + isolate.get('/allocationprofile').then((ServiceMap response) {
|
| assert(response['type'] == 'AllocationProfile');
|
| profile = response;
|
| }).catchError((e, st) {
|
| @@ -237,7 +184,20 @@ class HeapProfileElement extends ObservatoryElement {
|
| }).whenComplete(done);
|
| }
|
|
|
| - void resetAccumulator(Event e, var detail, Node target) {
|
| + void refreshGC(var done) {
|
| + if (profile == null) {
|
| + return;
|
| + }
|
| + var isolate = profile.isolate;
|
| + isolate.get('/allocationprofile?gc=full').then((ServiceMap response) {
|
| + assert(response['type'] == 'AllocationProfile');
|
| + profile = response;
|
| + }).catchError((e, st) {
|
| + Logger.root.info('$e $st');
|
| + }).whenComplete(done);
|
| + }
|
| +
|
| + void resetAccumulator(var done) {
|
| if (profile == null) {
|
| return;
|
| }
|
| @@ -247,11 +207,15 @@ class HeapProfileElement extends ObservatoryElement {
|
| profile = response;
|
| }).catchError((e, st) {
|
| Logger.root.info('$e $st');
|
| - });
|
| + }).whenComplete(done);
|
| }
|
|
|
| void profileChanged(oldValue) {
|
| - _updateChartData();
|
| + try {
|
| + _updateChartData();
|
| + } catch (e, st) {
|
| + Logger.root.info('$e $st');
|
| + }
|
| notifyPropertyChange(#formattedAverage, [], formattedAverage);
|
| notifyPropertyChange(#formattedTotalCollectionTime, [],
|
| formattedTotalCollectionTime);
|
| @@ -283,6 +247,6 @@ class HeapProfileElement extends ObservatoryElement {
|
| }
|
| String space = newSpace ? 'new' : 'old';
|
| Map heap = profile['heaps'][space];
|
| - return '${formatSeconds(heap['time'])} secs';
|
| + return '${Utils.formatSeconds(heap['time'])} secs';
|
| }
|
| }
|
|
|