| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..15eb2d609e3d04403240bd165fdc8898082e63c5
|
| --- /dev/null
|
| +++ b/runtime/bin/vmservice/client/lib/src/observatory_elements/heap_profile.dart
|
| @@ -0,0 +1,199 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library heap_profile_element;
|
| +
|
| +import 'dart:html';
|
| +import 'package:logging/logging.dart';
|
| +import 'package:polymer/polymer.dart';
|
| +import 'observatory_element.dart';
|
| +
|
| +/// Displays an Error response.
|
| +@CustomTag('heap-profile')
|
| +class HeapProfileElement extends ObservatoryElement {
|
| + // Indexes into VM provided map.
|
| + static const ALLOCATED_BEFORE_GC = 0;
|
| + static const ALLOCATED_BEFORE_GC_SIZE = 1;
|
| + static const LIVE_AFTER_GC = 2;
|
| + static const LIVE_AFTER_GC_SIZE = 3;
|
| + static const ALLOCATED_SINCE_GC = 4;
|
| + static const ALLOCATED_SINCE_GC_SIZE = 5;
|
| +
|
| + @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)',
|
| + ];
|
| +
|
| + dynamic _columnValue(Map v, int index) {
|
| + assert(columns.length == 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];
|
| + }
|
| + }
|
| +
|
| + 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);
|
| + if (isolate == null) {
|
| + Logger.root.info('No isolate found.');
|
| + return;
|
| + }
|
| + var request = '/$isolateId/allocationprofile';
|
| + app.requestManager.requestMap(request).then((Map response) {
|
| + assert(response['type'] == 'AllocationProfile');
|
| + profile = response;
|
| + }).catchError((e, st) {
|
| + Logger.root.info('$e $st');
|
| + });
|
| + }
|
| +
|
| + void profileChanged(oldValue) {
|
| + _sort();
|
| + notifyPropertyChange(#status, [], status);
|
| + }
|
| +
|
| + String status(bool new_space) {
|
| + if (profile == null) {
|
| + return '';
|
| + }
|
| + String space = new_space ? '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);
|
| + }
|
| +
|
| + 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) {
|
| + return '';
|
| + }
|
| + int current =
|
| + data[instances ? ALLOCATED_BEFORE_GC : ALLOCATED_BEFORE_GC_SIZE];
|
| + if (instances) {
|
| + return '$current';
|
| + }
|
| + return ObservatoryApplication.scaledSizeUnits(current);
|
| + }
|
| +
|
| + 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) {
|
| + return '';
|
| + }
|
| + int current = data[instances ? LIVE_AFTER_GC : LIVE_AFTER_GC_SIZE];
|
| + if (instances) {
|
| + return '$current';
|
| + }
|
| + return ObservatoryApplication.scaledSizeUnits(current);
|
| + }
|
| +}
|
|
|