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

Unified Diff: runtime/observatory/lib/src/cpu_profile/cpu_profile.dart

Issue 1013563002: CPU profile displayed in three tables with a tree (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 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/observatory/lib/src/cpu_profile/cpu_profile.dart
diff --git a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
index 359117128c674a4ef626cfa580dd5d2fa0209996..4393b1299c6ae19f045fc74ef8a3e6b55679612f 100644
--- a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
+++ b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
@@ -41,6 +41,24 @@ class CodeCallTree {
_setCodePercentage(node, child);
}
}
+
+ _markCodeCallsInner(CodeCallTreeNode caller,
+ CodeCallTreeNode callee) {
+ if (caller != null) {
+ caller.profileCode._noteCallee(callee.profileCode, callee.count);
+ callee.profileCode._noteCaller(caller.profileCode, callee.count);
+ }
+
+ for (var child in callee.children) {
+ _markCodeCallsInner(callee, child);
+ }
+ }
+
+ _markCodeCalls() {
turnidge 2015/04/07 21:24:31 What does "marking" mean here? Is there another n
Cutch 2015/04/14 21:45:15 Went with _recordCallerAndCallees. The class is n
+ for (var child in root.children) {
+ _markCodeCallsInner(null, child);
+ }
+ }
}
class FunctionCallTreeNodeCode {
@@ -129,6 +147,108 @@ class FunctionCallTreeNode {
}
}
+typedef bool FunctionCallTreeNodeFilter(FunctionCallTreeNode node);
+
+class _FilteredTreeBuilder {
turnidge 2015/04/07 21:24:31 Can you make some of the functions in this class p
Cutch 2015/04/14 21:45:15 Done.
+ final FunctionCallTreeNodeFilter filter;
+ final FunctionCallTree tree;
+ final FunctionCallTree filtered;
+ final List currentPath = [];
+
+ _FilteredTreeBuilder(this.filter, FunctionCallTree tree)
+ : tree = tree,
+ filtered =
+ new FunctionCallTree(
+ tree.inclusive,
+ new FunctionCallTreeNode(
+ tree.root.profileFunction,
+ tree.root.count));
+
+ FunctionCallTreeNode findFunctionInChildren(FunctionCallTreeNode current,
+ FunctionCallTreeNode needle) {
+ for (var child in current.children) {
+ if (child.profileFunction == needle.profileFunction) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ FunctionCallTreeNode addCurrentPath() {
+ FunctionCallTreeNode current = filtered.root;
+ // Tree root is always the first element of the current path.
+ assert(tree.root == currentPath[0]);
+ // Assert that tree and filtered are different.
+ assert(tree.root != current);
+ for (var i = 1; i < currentPath.length; i++) {
+ var toAdd = currentPath[i];
+ var child = findFunctionInChildren(current, toAdd);
+ if (child == null) {
+ child = new FunctionCallTreeNode(toAdd.profileFunction, toAdd.count);
+ current.children.add(child);
+ }
+ current = child;
+ assert(current.count == toAdd.count);
+ }
+ return current;
+ }
+
+ appendTree(FunctionCallTreeNode current, FunctionCallTreeNode next) {
+ if (next == null) {
+ return;
+ }
+ var child = findFunctionInChildren(current, next);
+ if (child == null) {
+ child = new FunctionCallTreeNode(next.profileFunction, next.count);
+ current.children.add(child);
+ }
+ current = child;
+ for (var nextChild in next.children) {
+ appendTree(current, nextChild);
+ }
+ }
+
+ addTree(FunctionCallTreeNode child) {
+ var current = addCurrentPath();
+ appendTree(current, child);
+ }
+
+ descend(FunctionCallTreeNode current) {
+ if (current == null) {
+ return;
+ }
+ currentPath.add(current);
+
+ if (filter(current)) {
+ // Filter matched.
+ if (current.children.length == 0) {
+ // Have no children. Add this path.
+ addTree(null);
+ } else {
+ // Add all child trees.
+ for (var child in current.children) {
+ addTree(child);
+ }
+ }
+ } else {
+ // Did not match, descend to each child.
+ for (var child in current.children) {
+ descend(child);
+ }
+ }
+
+ var last = currentPath.removeLast();
+ assert(current == last);
+ }
+
+ build() {
+ assert(filtered != null);
+ assert(filter != null);
+ assert(tree != null);
+ descend(tree.root);
+ }
+}
+
class FunctionCallTree {
final bool inclusive;
final FunctionCallTreeNode root;
@@ -136,6 +256,13 @@ class FunctionCallTree {
_setFunctionPercentage(null, root);
}
+ FunctionCallTree filtered(FunctionCallTreeNodeFilter filter) {
+ var treeFilter = new _FilteredTreeBuilder(filter, this);
+ treeFilter.build();
+ _setFunctionPercentage(null, treeFilter.filtered.root);
+ return treeFilter.filtered;
+ }
+
void _setFunctionPercentage(FunctionCallTreeNode parent,
FunctionCallTreeNode node) {
assert(node != null);
@@ -154,6 +281,23 @@ class FunctionCallTree {
_setFunctionPercentage(node, child);
}
}
+
+ _markFunctionCallsInner(FunctionCallTreeNode caller,
+ FunctionCallTreeNode callee) {
+ if (caller != null) {
+ caller.profileFunction._noteCallee(callee.profileFunction, callee.count);
+ callee.profileFunction._noteCaller(caller.profileFunction, callee.count);
+ }
+ for (var child in callee.children) {
+ _markFunctionCallsInner(callee, child);
+ }
+ }
+
+ _markFunctionCalls() {
+ for (var child in root.children) {
+ _markFunctionCallsInner(null, child);
+ }
+ }
}
class CodeTick {
@@ -186,6 +330,8 @@ class ProfileCode {
String formattedCpuTime = '';
String formattedOnStackTime = '';
final Set<String> attributes = new Set<String>();
+ final Map<ProfileCode, int> callers = new Map<ProfileCode, int>();
+ final Map<ProfileCode, int> callees = new Map<ProfileCode, int>();
void _processTicks(List<String> profileTicks) {
assert(profileTicks != null);
@@ -262,6 +408,22 @@ class ProfileCode {
'${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
'($exclusiveTicks)';
}
+
+ _noteCaller(ProfileCode caller, int count) {
turnidge 2015/04/07 21:24:31 Maybe _addCaller and _addCallee?
Cutch 2015/04/14 21:45:15 Done.
+ var r = callers[caller];
+ if (r == null) {
+ r = 0;
+ }
+ callers[caller] = r + count;
+ }
+
+ _noteCallee(ProfileCode callee, int count) {
+ var r = callees[callee];
+ if (r == null) {
+ r = 0;
+ }
+ callees[callee] = r + count;
+ }
}
class ProfileFunction {
@@ -269,6 +431,9 @@ class ProfileFunction {
final ServiceFunction function;
// List of compiled code objects containing this function.
final List<ProfileCode> profileCodes = new List<ProfileCode>();
+ final Map<ProfileFunction, int> callers = new Map<ProfileFunction, int>();
+ final Map<ProfileFunction, int> callees = new Map<ProfileFunction, int>();
+
// Absolute ticks:
int exclusiveTicks = 0;
int inclusiveTicks = 0;
@@ -356,6 +521,7 @@ class ProfileFunction {
}
ProfileFunction.fromMap(this.profile, this.function, Map data) {
+ function.profile = this;
for (var codeIndex in data['codes']) {
var profileCode = profile.codes[codeIndex];
profileCodes.add(profileCode);
@@ -397,6 +563,22 @@ class ProfileFunction {
'${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
'($exclusiveTicks)';
}
+
+ _noteCaller(ProfileFunction caller, int count) {
+ var r = callers[caller];
+ if (r == null) {
+ r = 0;
+ }
+ callers[caller] = r + count;
+ }
+
+ _noteCallee(ProfileFunction callee, int count) {
+ var r = callees[callee];
+ if (r == null) {
+ r = 0;
+ }
+ callees[callee] = r + count;
+ }
}
@@ -416,7 +598,9 @@ class CpuProfile {
final Map<String, List> tries = <String, List>{};
final List<ProfileCode> codes = new List<ProfileCode>();
+ bool _markedCodeCalls = false;
final List<ProfileFunction> functions = new List<ProfileFunction>();
+ bool _markedFunctionCalls = false;
CodeCallTree loadCodeTree(String name) {
if (name == 'inclusive') {
@@ -434,7 +618,25 @@ class CpuProfile {
}
}
- void clear() {
+ markCodeCalls() {
+ if (_markedCodeCalls) {
+ return;
+ }
+ _markedCodeCalls = true;
+ var tree = loadCodeTree('inclusive');
+ tree._markCodeCalls();
+ }
+
+ markFunctionCalls() {
+ if (_markedFunctionCalls) {
+ return;
+ }
+ _markedFunctionCalls = true;
+ var tree = loadFunctionTree('inclusive');
+ tree._markFunctionCalls();
+ }
+
+ clear() {
sampleCount = 0;
samplePeriod = 0;
sampleRate = 0.0;
@@ -443,9 +645,11 @@ class CpuProfile {
codes.clear();
functions.clear();
tries.clear();
+ _markedCodeCalls = false;
+ _markedFunctionCalls = false;
}
- void load(Isolate isolate, ServiceMap profile) {
+ load(Isolate isolate, ServiceMap profile) {
clear();
if ((isolate == null) || (profile == null)) {
return;

Powered by Google App Engine
This is Rietveld 408576698