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

Unified Diff: tools/profview/profile-utils.js

Issue 2730293002: [profiler] This adds function butterflies to the function list. (Closed)
Patch Set: Formatting Created 3 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
« no previous file with comments | « no previous file | tools/profview/profview.css » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/profview/profile-utils.js
diff --git a/tools/profview/profile-utils.js b/tools/profview/profile-utils.js
index e6fb58c5646a9dd173c1cba85531dc791cc76cb2..02e7483fb8f8ba9009fab61523ee94c03d601876 100644
--- a/tools/profview/profile-utils.js
+++ b/tools/profview/profile-utils.js
@@ -79,6 +79,89 @@ function createNodeFromStackEntry(code) {
children : [], ownTicks : 0, ticks : 0 };
}
+function childIdFromCode(codeId, code) {
+ // For JavaScript function, pretend there is one instance of optimized
+ // function and one instance of unoptimized function per SFI.
+ // Otherwise, just compute the id from code id.
+ let type = resolveCodeKind(code);
+ if (type === "JSOPT") {
+ return code.func * 4 + 1;
+ } else if (type === "JSUNOPT") {
+ return code.func * 4 + 2;
+ } else {
+ return codeId * 4;
+ }
+}
+
+// We store list of ticks and positions within the ticks stack by
+// storing flattened triplets of { tickIndex, depth, count }.
+// Triplet { 123, 2, 3 } encodes positions in ticks 123, 124, 125,
+// all of them at depth 2. The flattened array is used to encode
+// position within the call-tree.
+
+// The following function helps to encode such triplets.
+function addFrameToFrameList(paths, pathIndex, depth) {
+ // Try to combine with the previous code run.
+ if (paths.length > 0 &&
+ paths[paths.length - 3] + 1 === pathIndex &&
+ paths[paths.length - 2] === depth) {
+ paths[paths.length - 1]++;
+ } else {
+ paths.push(pathIndex, depth, 1);
+ }
+}
+
+// This expands a tree node (direct children only).
+function expandTreeNode(file, node, filter) {
+ let { frameList, ascending } = node.delayedExpansion;
+
+ let step = ascending ? 2 : -2;
+
+ for (let i = 0; i < frameList.length; i+= 3) {
+ let stackIndex = frameList[i];
+ let depth = frameList[i + 1];
+ let count = frameList[i + 2];
+ for (let j = 0; j < count; j++) {
+ let tick = file.ticks[stackIndex + j];
+ let stack = tick.s;
+
+ // Get to the next frame that has not been filtered out.
+ let k = depth + step;
+ let codeId = -1;
+ let code = null;
+ while (k >= 0 && k < stack.length) {
+ codeId = stack[k];
+ code = codeId >= 0 ? file.code[codeId] : undefined;
+ if (filter) {
+ let type = code ? code.type : undefined;
+ let kind = code ? code.kind : undefined;
+ if (filter(type, kind)) break;
+ }
+ k += step;
+ }
+ if (k < 0 || k >= stack.length) {
+ // We reached the end without finding the next step.
+ // If we are doing top-down call tree, update own ticks.
+ if (!ascending) {
+ node.ownTicks++;
+ }
+ } else {
+ // We found a child node.
+ let childId = childIdFromCode(codeId, code);
+ let child = node.children[childId];
+ if (!child) {
+ child = createNodeFromStackEntry(code);
+ child.delayedExpansion = { frameList : [], ascending };
+ node.children[childId] = child;
+ }
+ child.ticks++;
+ addFrameToFrameList(child.delayedExpansion.frameList, stackIndex, k);
+ }
+ }
+ }
+ node.delayedExpansion = null;
+}
+
function addStackToTree(file, stack, tree, filter, ascending, start) {
if (start === undefined) {
start = ascending ? 0 : stack.length - 2;
@@ -97,15 +180,7 @@ function addStackToTree(file, stack, tree, filter, ascending, start) {
// For JavaScript function, pretend there is one instance of optimized
// function and one instance of unoptimized function per SFI.
- let type = resolveCodeKind(code);
- let childId;
- if (type === "JSOPT") {
- childId = code.func * 4 + 1;
- } else if (type === "JSUNOPT") {
- childId = code.func * 4 + 2;
- } else {
- childId = codeId * 4;
- }
+ let childId = childIdFromCode(codeId, code);
let child = tree.children[childId];
if (!child) {
child = createNodeFromStackEntry(code);
@@ -134,40 +209,49 @@ class PlainCallTreeProcessor {
this.isBottomUp = isBottomUp;
}
- addStack(file, timestamp, vmState, stack) {
+ addStack(file, tickIndex) {
+ let stack = file.ticks[tickIndex].s;
addStackToTree(file, stack, this.tree, this.filter, this.isBottomUp);
}
}
+function buildCategoryTreeAndLookup() {
+ let root = createEmptyNode("root");
+ let categories = {};
+ function addCategory(name, types) {
+ let n = createEmptyNode(name);
+ for (let i = 0; i < types.length; i++) {
+ categories[types[i]] = n;
+ }
+ root.children.push(n);
+ }
+ addCategory("JS Optimized", [ "JSOPT" ]);
+ addCategory("JS Unoptimized", [ "JSUNOPT", "BC" ]);
+ addCategory("IC", [ "IC" ]);
+ addCategory("RegExp", [ "REGEXP" ]);
+ addCategory("Other generated", [ "STUB", "BUILTIN" ]);
+ addCategory("C++", [ "CPP", "LIB" ]);
+ addCategory("C++/GC", [ "CPPGC" ]);
+ addCategory("C++/Compiler", [ "CPPCOMP" ]);
+ addCategory("C++/External", [ "CPPEXT" ]);
+ addCategory("Unknown", [ "UNKNOWN" ]);
+
+ return { categories, root };
+}
+
class CategorizedCallTreeProcessor {
constructor(filter, isBottomUp) {
this.filter = filter;
- let root = createEmptyNode("root");
- let categories = {};
- function addCategory(name, types) {
- let n = createEmptyNode(name);
- for (let i = 0; i < types.length; i++) {
- categories[types[i]] = n;
- }
- root.children.push(n);
- }
- addCategory("JS Optimized", [ "JSOPT" ]);
- addCategory("JS Unoptimized", [ "JSUNOPT", "BC" ]);
- addCategory("IC", [ "IC" ]);
- addCategory("RegExp", [ "REGEXP" ]);
- addCategory("Other generated", [ "STUB", "BUILTIN" ]);
- addCategory("C++", [ "CPP", "LIB" ]);
- addCategory("C++/GC", [ "CPPGC" ]);
- addCategory("C++/Compiler", [ "CPPCOMP" ]);
- addCategory("C++/External", [ "CPPEXT" ]);
- addCategory("Unknown", [ "UNKNOWN" ]);
+ let { categories, root } = buildCategoryTreeAndLookup();
this.tree = root;
this.categories = categories;
this.isBottomUp = isBottomUp;
}
- addStack(file, timestamp, vmState, stack) {
+ addStack(file, tickIndex) {
+ let stack = file.ticks[tickIndex].s;
+ let vmState = file.ticks[tickIndex].vm;
if (stack.length === 0) return;
let codeId = stack[0];
let code = codeId >= 0 ? file.code[codeId] : undefined;
@@ -183,15 +267,27 @@ class CategorizedCallTreeProcessor {
}
class FunctionListTree {
- constructor(filter) {
- this.tree = { name : "root", children : [], ownTicks : 0, ticks : 0 };
+ constructor(filter, withCategories) {
+ if (withCategories) {
+ let { categories, root } = buildCategoryTreeAndLookup();
+ this.tree = root;
+ this.categories = categories;
+ } else {
+ this.tree = { name : "root", children : [], ownTicks : 0, ticks : 0 };
+ this.categories = null;
+ }
+
this.codeVisited = [];
this.filter = filter;
}
- addStack(file, timestamp, vmState, stack) {
+ addStack(file, tickIndex) {
+ let stack = file.ticks[tickIndex].s;
+ let vmState = file.ticks[tickIndex].vm;
+
this.tree.ticks++;
let child = null;
+ let tree = null;
for (let i = stack.length - 2; i >= 0; i -= 2) {
let codeId = stack[i];
if (codeId < 0 || this.codeVisited[codeId]) continue;
@@ -202,16 +298,38 @@ class FunctionListTree {
let kind = code ? code.kind : undefined;
if (!this.filter(type, kind)) continue;
}
- child = this.tree.children[codeId];
+ let childId = childIdFromCode(codeId, code);
+ if (this.categories) {
+ let kind = resolveCodeKindAndVmState(code, vmState);
+ tree = this.categories[kind];
+ } else {
+ tree = this.tree;
+ }
+ child = tree.children[childId];
if (!child) {
child = createNodeFromStackEntry(code);
- this.tree.children[codeId] = child;
+ child.children[0] = createEmptyNode("Top-down tree");
+ child.children[0].delayedExpansion =
+ { frameList : [], ascending : false };
+ child.children[1] = createEmptyNode("Bottom-up tree");
+ child.children[1].delayedExpansion =
+ { frameList : [], ascending : true };
+ tree.children[childId] = child;
}
child.ticks++;
+ child.children[0].ticks++;
+ addFrameToFrameList(
+ child.children[0].delayedExpansion.frameList, tickIndex, i);
+ child.children[1].ticks++;
+ addFrameToFrameList(
+ child.children[1].delayedExpansion.frameList, tickIndex, i);
this.codeVisited[codeId] = true;
}
if (child) {
child.ownTicks++;
+ console.assert(tree !== null);
+ tree.ticks++;
+ console.assert(tree.type === "CAT");
}
for (let i = 0; i < stack.length; i += 2) {
@@ -240,7 +358,9 @@ class CategorySampler {
}
}
- addStack(file, timestamp, vmState, stack) {
+ addStack(file, tickIndex) {
+ let { tm : timestamp, vm : vmState, s : stack } = file.ticks[tickIndex];
+
let i = Math.floor((timestamp - this.firstTime) / this.step);
if (i == this.buckets.length) i--;
console.assert(i >= 0 && i < this.buckets.length);
@@ -269,7 +389,7 @@ function generateTree(
let tickCount = 0;
while (i < ticks.length && ticks[i].tm < endTime) {
- tree.addStack(file, ticks[i].tm, ticks[i].vm, ticks[i].s);
+ tree.addStack(file, i);
i++;
tickCount++;
}
« no previous file with comments | « no previous file | tools/profview/profview.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698