Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Unified Diff: runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart

Issue 201213004: Use VM tag in profile and add stack trace trie (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart
diff --git a/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart b/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart
index 39092b38d45c9b63653b64d32d0a708f787956c8..1e244df0b4527370901f4e04a254fd44b427f229 100644
--- a/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart
+++ b/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart
@@ -6,10 +6,61 @@ library isolate_profile_element;
import 'dart:html';
import 'observatory_element.dart';
+import 'package:logging/logging.dart';
import 'package:observatory/service.dart';
import 'package:observatory/app.dart';
import 'package:polymer/polymer.dart';
+class ProfileCodeTrieNodeTreeRow extends TableTreeRow {
+ final ServiceMap profile;
+ @reflectable final CodeTrieNode root;
+ @reflectable final CodeTrieNode node;
+ @reflectable Code get code => node.code;
+
+ static String formatPercent(num a, num total) {
+ var percent = 100.0 * (a / total);
+ return '${percent.toStringAsFixed(2)}%';
+ }
+
+ ProfileCodeTrieNodeTreeRow(this.profile, this.root, this.node,
+ ProfileCodeTrieNodeTreeRow parent)
+ : super(parent) {
+ assert(root != null);
+ assert(node != null);
+ var totalSamples = root.count;
+ // When the row is created, fill out the columns.
+ if (parent == null) {
+ columns.add(formatPercent(node.count, root.count));
+ } else {
+ columns.add(formatPercent(node.count, parent.node.count));
+ }
+ columns.add(formatPercent(node.code.exclusiveTicks, totalSamples));
+ }
+
+ bool shouldDisplayChild(CodeTrieNode childNode, double threshold) {
+ return ((childNode.count / node.count) > threshold) ||
+ ((childNode.code.exclusiveTicks / root.count) > threshold);
+ }
+
+ void onShow() {
+ var threshold = profile['threshold'];
+ if (children.length > 0) {
+ // Child rows already created.
+ return;
+ }
+ for (var childNode in node.children) {
+ if (!shouldDisplayChild(childNode, threshold)) {
+ continue;
+ }
+ var row = new ProfileCodeTrieNodeTreeRow(profile, root, childNode, this);
+ children.add(row);
+ }
+ }
+
+ void onHide() {
+ }
+}
+
class ProfileCallerTreeRow extends TableTreeRow {
final ServiceMap profile;
@reflectable final Code code;
@@ -25,29 +76,41 @@ class ProfileCallerTreeRow extends TableTreeRow {
assert(code != null);
var totalSamples = profile['samples'];
// When the row is created, fill out the columns.
- columns.add(
- formatPercent(code.exclusiveTicks, totalSamples));
if (parent == null) {
- // Fill with dummy data.
- columns.add('');
+ var root = profile.isolate.codes.tagRoot();
+ var totalAttributedCalls = root.callersCount(code);
+ var totalParentCalls = root.sumCallersCount();
+ columns.add(formatPercent(totalAttributedCalls, totalParentCalls));
} else {
var totalAttributedCalls = parent.code.callersCount(code);
var totalParentCalls = parent.code.sumCallersCount();
columns.add(formatPercent(totalAttributedCalls, totalParentCalls));
}
+ columns.add(formatPercent(code.exclusiveTicks, totalSamples));
+ }
+
+ bool shouldDisplayChild(CodeCallCount childNode, totalSamples,
+ double threshold) {
+ var callerPercent = code.callersCount(childNode.code) /
+ code.sumCallersCount();
+ return (callerPercent > threshold) ||
+ ((childNode.code.exclusiveTicks / totalSamples) > threshold);
}
void onShow() {
+ var threshold = profile['threshold'];
+ var totalSamples = profile['samples'];
if (children.length > 0) {
// Child rows already created.
return;
}
- // Create child rows on demand.
- code.callers.forEach((CodeCallCount codeCaller) {
- var row =
- new ProfileCallerTreeRow(profile, codeCaller.code, this);
+ for (var codeCaller in code.callers) {
+ if (!shouldDisplayChild(codeCaller, totalSamples, threshold)) {
+ continue;
+ }
+ var row = new ProfileCallerTreeRow(profile, codeCaller.code, this);
children.add(row);
- });
+ }
}
void onHide() {
@@ -59,15 +122,20 @@ class ProfileCallerTreeRow extends TableTreeRow {
class IsolateProfileElement extends ObservatoryElement {
IsolateProfileElement.created() : super.created();
@published ServiceMap profile;
- @reflectable final topExclusiveCodes = new ObservableList<Code>();
- @observable int methodCountSelected = 0;
+ @observable bool callGraphChecked;
+ @observable bool hideTagsChecked;
@observable String sampleCount = '';
@observable String refreshTime = '';
+ @observable String sampleRate = '';
+ @observable String sampleDepth = '';
+ @observable String displayCutoff = '';
+ @reflectable double displayThreshold = 0.0001; // 0.5%.
- final List methodCounts = [10, 20, 50];
final _id = '#tableTree';
TableTree tree;
+ static const MICROSECONDS_PER_SECOND = 1000000.0;
+
void profileChanged(oldValue) {
if (profile == null) {
return;
@@ -76,21 +144,35 @@ class IsolateProfileElement extends ObservatoryElement {
var now = new DateTime.now();
sampleCount = totalSamples.toString();
refreshTime = now.toString();
+ sampleDepth = profile['depth'].toString();
+ var period = profile['period'];
+ sampleRate = (MICROSECONDS_PER_SECOND / period).toStringAsFixed(0);
+ displayCutoff = '${(displayThreshold * 100.0).toString()}%';
profile.isolate.processProfile(profile);
+ profile['threshold'] = displayThreshold;
_update();
}
- void enteredView() {
- tree = new TableTree(['Method', 'Exclusive', 'Caller']);
+ void callGraphCheckedChanged(oldValue) {
_update();
}
- methodCountSelectedChanged(oldValue) {
+
+ void enteredView() {
+ tree = new TableTree();
_update();
}
+ void hideTagsCheckedChanged(oldValue) {
+ refresh(null);
+ }
+
void refresh(var done) {
- profile.isolate.get('profile').then((ServiceMap m) {
+ var request = 'profile';
+ if ((hideTagsChecked != null) && hideTagsChecked) {
+ request += '?tags=hide';
+ }
+ profile.isolate.get(request).then((ServiceMap m) {
// Assert we got back the a profile.
assert(m.serviceType == 'Profile');
profile = m;
@@ -101,28 +183,46 @@ class IsolateProfileElement extends ObservatoryElement {
if (profile == null) {
return;
}
- _refreshTopMethods();
- _rebuildTree();
+ _buildTree();
}
- void _refreshTopMethods() {
+ void _buildCallersTree() {
assert(profile != null);
- var count = methodCounts[methodCountSelected];
- topExclusiveCodes.clear();
- topExclusiveCodes.addAll(profile.isolate.codes.topExclusive(count));
+ var root = profile.isolate.codes.tagRoot();
+ if (root == null) {
+ Logger.root.warning('No profile root tag.');
+ }
+ try {
+ tree.initialize(new ProfileCallerTreeRow(profile, root, null));
+ } catch (e, stackTrace) {
+ Logger.root.warning('_buildCallersTree', e, stackTrace);
+ }
+
+ notifyPropertyChange(#tree, null, tree);
}
- void _rebuildTree() {
- assert(profile != null);
- var rootChildren = [];
- for (var code in topExclusiveCodes) {
- var row = new ProfileCallerTreeRow(profile, code, null);
- rootChildren.add(row);
+ void _buildStackTree() {
+ var root = profile.isolate.profileTrieRoot;
+ if (root == null) {
+ Logger.root.warning('No profile trie root.');
+ }
+ try {
+ tree.initialize(
+ new ProfileCodeTrieNodeTreeRow(profile, root, root, null));
+ } catch (e, stackTrace) {
+ Logger.root.warning('_buildStackTree', e, stackTrace);
}
- tree.initialize(rootChildren);
notifyPropertyChange(#tree, null, tree);
}
+ void _buildTree() {
+ if ((callGraphChecked) != null && callGraphChecked) {
+ _buildCallersTree();
+ } else {
+ _buildStackTree();
+ }
+ }
+
@observable String padding(TableTreeRow row) {
return 'padding-left: ${row.depth * 16}px;';
}

Powered by Google App Engine
This is Rietveld 408576698