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

Unified Diff: tools/profview/profview.js

Issue 2737083003: [tools/profview] Add individual function timeline view (Closed)
Patch Set: Rebase 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
« tools/profview/profile-utils.js ('K') | « tools/profview/profview.css ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/profview/profview.js
diff --git a/tools/profview/profview.js b/tools/profview/profview.js
index 6186c09742b827e651daae6093e7ca9231c7bbc9..98b536e3c0c156f7cd0ebd3c8e490a1f8dde29a8 100644
--- a/tools/profview/profview.js
+++ b/tools/profview/profview.js
@@ -151,6 +151,14 @@ let main = {
}
},
+ setCurrentCode(codeId) {
+ if (codeId != main.currentState.currentCodeId) {
+ main.currentState = Object.assign({}, main.currentState);
+ main.currentState.currentCodeId = codeId;
+ main.delayRender();
+ }
+ },
+
onResize() {
main.setTimeLineDimensions(
window.innerWidth - 20, window.innerHeight / 5);
@@ -241,6 +249,73 @@ function bucketFromKind(kind) {
return null;
}
+function codeTypeToText(type) {
+ switch (type) {
+ case "UNKNOWN":
+ return "Unknown";
+ case "CPPCOMP":
+ return "C++ (compiler)";
+ case "CPPGC":
+ return "C++";
+ case "CPPEXT":
+ return "C++ External";
+ case "CPP":
+ return "C++";
+ case "LIB":
+ return "Library";
+ case "IC":
+ return "IC";
+ case "BC":
+ return "Bytecode";
+ case "STUB":
+ return "Stub";
+ case "BUILTIN":
+ return "Builtin";
+ case "REGEXP":
+ return "RegExp";
+ case "JSOPT":
+ return "JS opt";
+ case "JSUNOPT":
+ return "JS unopt";
+ }
+ console.error("Unknown type: " + type);
+}
+
+function createTypeDiv(type) {
+ if (type === "CAT") {
+ return document.createTextNode("");
+ }
+ let div = document.createElement("div");
+ div.classList.add("code-type-chip");
+
+ let span = document.createElement("span");
+ span.classList.add("code-type-chip");
+ span.textContent = codeTypeToText(type);
+ div.appendChild(span);
+
+ span = document.createElement("span");
+ span.classList.add("code-type-chip-space");
+ div.appendChild(span);
+
+ return div;
+}
+
+function isBytecodeHandler(kind) {
+ return kind === "BytecodeHandler";
+}
+
+function filterFromFilterId(id) {
+ switch (id) {
+ case "full-tree":
+ return (type, kind) => true;
+ case "js-funs":
+ return (type, kind) => type !== 'CODE';
+ case "js-exclude-bc":
+ return (type, kind) =>
+ type !== 'CODE' || !isBytecodeHandler(kind);
+ }
+}
+
class CallTreeView {
constructor() {
this.element = $("calltree");
@@ -264,18 +339,6 @@ class CallTreeView {
this.currentState = null;
}
- filterFromFilterId(id) {
- switch (id) {
- case "full-tree":
- return (type, kind) => true;
- case "js-funs":
- return (type, kind) => type !== 'CODE';
- case "js-exclude-bc":
- return (type, kind) =>
- type !== 'CODE' || !CallTreeView.IsBytecodeHandler(kind);
- }
- }
-
sortFromId(id) {
switch (id) {
case "time":
@@ -305,10 +368,6 @@ class CallTreeView {
}
}
- static IsBytecodeHandler(kind) {
- return kind === "BytecodeHandler";
- }
-
createExpander(indent) {
let div = document.createElement("div");
div.style.width = (1 + indent) + "em";
@@ -317,55 +376,17 @@ class CallTreeView {
return div;
}
- codeTypeToText(type) {
- switch (type) {
- case "UNKNOWN":
- return "Unknown";
- case "CPPCOMP":
- return "C++ (compiler)";
- case "CPPGC":
- return "C++";
- case "CPPEXT":
- return "C++ External";
- case "CPP":
- return "C++";
- case "LIB":
- return "Library";
- case "IC":
- return "IC";
- case "BC":
- return "Bytecode";
- case "STUB":
- return "Stub";
- case "BUILTIN":
- return "Builtin";
- case "REGEXP":
- return "RegExp";
- case "JSOPT":
- return "JS opt";
- case "JSUNOPT":
- return "JS unopt";
- }
- console.error("Unknown type: " + type);
- }
-
- createTypeDiv(type) {
- if (type === "CAT") {
- return document.createTextNode("");
+ createFunctionNode(name, codeId) {
+ if (codeId == -1) {
+ return document.createTextNode(name);
}
- let div = document.createElement("div");
- div.classList.add("code-type-chip");
-
- let span = document.createElement("span");
- span.classList.add("code-type-chip");
- span.textContent = this.codeTypeToText(type);
- div.appendChild(span);
-
- span = document.createElement("span");
- span.classList.add("code-type-chip-space");
- div.appendChild(span);
-
- return div;
+ let nameElement = document.createElement("span");
+ nameElement.classList.add("codeid-link")
+ nameElement.onclick = function() {
+ main.setCurrentCode(codeId);
+ };
+ nameElement.appendChild(document.createTextNode(name));
+ return nameElement;
}
expandTree(tree, indent) {
@@ -392,7 +413,7 @@ class CallTreeView {
// Collect the children, and sort them by ticks.
let children = [];
let filter =
- this.filterFromFilterId(this.currentState.callTree.attribution);
+ filterFromFilterId(this.currentState.callTree.attribution);
for (let childId in tree.children) {
let child = tree.children[childId];
if (child.ticks > 0) {
@@ -432,8 +453,8 @@ class CallTreeView {
let nameCell = row.insertCell();
let expander = this.createExpander(indent);
nameCell.appendChild(expander);
- nameCell.appendChild(this.createTypeDiv(node.type));
- nameCell.appendChild(document.createTextNode(node.name));
+ nameCell.appendChild(createTypeDiv(node.type));
+ nameCell.appendChild(this.createFunctionNode(node.name, node.codeId));
// Inclusive ticks cell.
c = row.insertCell();
@@ -573,7 +594,7 @@ class CallTreeView {
// Build the tree.
let stackProcessor;
- let filter = this.filterFromFilterId(this.currentState.callTree.attribution);
+ let filter = filterFromFilterId(this.currentState.callTree.attribution);
if (mode === "top-down") {
stackProcessor =
new PlainCallTreeProcessor(filter, false);
@@ -619,6 +640,7 @@ class TimelineView {
this.element = $("timeline");
this.canvas = $("timeline-canvas");
this.legend = $("timeline-legend");
+ this.currentCode = $("timeline-currentCode");
this.canvas.onmousedown = this.onMouseDown.bind(this);
this.canvas.onmouseup = this.onMouseUp.bind(this);
@@ -630,6 +652,7 @@ class TimelineView {
this.fontSize = 12;
this.imageOffset = this.fontSize * 1.2;
+ this.functionTimelineHeight = 12;
this.currentState = null;
}
@@ -698,9 +721,9 @@ class TimelineView {
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
left = Math.min(this.selectionStart, this.selectionEnd);
right = Math.max(this.selectionStart, this.selectionEnd);
- ctx.fillRect(0, this.imageOffset, left, this.buffer.height);
- ctx.fillRect(right, this.imageOffset, this.buffer.width - right,
- this.buffer.height);
+ let height = this.buffer.height - this.functionTimelineHeight;
+ ctx.fillRect(0, this.imageOffset, left, height);
+ ctx.fillRect(right, this.imageOffset, this.buffer.width - right, height);
} else {
left = 0;
right = this.buffer.width;
@@ -763,6 +786,7 @@ class TimelineView {
if (newState.timeLine.width === oldState.timeLine.width &&
newState.timeLine.height === oldState.timeLine.height &&
newState.file === oldState.file &&
+ newState.currentCodeId === oldState.currentCodeId &&
newState.start === oldState.start &&
newState.end === oldState.end) {
// No change, nothing to do.
@@ -784,6 +808,8 @@ class TimelineView {
let file = this.currentState.file;
if (!file) return;
+ let currentCodeId = this.currentState.currentCodeId;
+
let firstTime = file.ticks[0].tm;
let lastTime = file.ticks[file.ticks.length - 1].tm;
let start = Math.max(this.currentState.start, firstTime);
@@ -801,6 +827,10 @@ class TimelineView {
let stackProcessor = new CategorySampler(file, bucketCount);
generateTree(file, 0, Infinity, stackProcessor);
+ let codeIdProcessor = new FunctionTimelineProcessor(
+ currentCodeId,
+ filterFromFilterId(this.currentState.callTree.attribution));
+ generateTree(file, 0, Infinity, codeIdProcessor);
Jarin 2017/03/08 16:35:56 One thought: for delayed expansions we already hav
let buffer = document.createElement("canvas");
@@ -808,7 +838,7 @@ class TimelineView {
buffer.height = height;
// Calculate the bar heights for each bucket.
- let graphHeight = height;
+ let graphHeight = height - this.functionTimelineHeight;
let buckets = stackProcessor.buckets;
let bucketsGraph = [];
for (let i = 0; i < buckets.length; i++) {
@@ -842,6 +872,24 @@ class TimelineView {
ctx.fill();
}
}
+ let functionTimelineYOffset = graphHeight;
+ let functionTimelineHeight = this.functionTimelineHeight;
+ let timestampScaler = width / (lastTime - firstTime);
+ ctx.fillStyle = "white";
+ ctx.fillRect(
+ 0,
+ functionTimelineYOffset,
+ buffer.width,
+ functionTimelineHeight);
+ for (let i = 0; i < codeIdProcessor.blocks.length; i++) {
+ let block = codeIdProcessor.blocks[i];
+ ctx.fillStyle = "#000000";
+ ctx.fillRect(
+ Math.round((block.start - firstTime) * timestampScaler),
+ functionTimelineYOffset,
+ Math.max(1, Math.round((block.end - block.start) * timestampScaler)),
+ block.topOfStack ? functionTimelineHeight : functionTimelineHeight / 2);
+ }
// Remember stuff for later.
this.buffer = buffer;
@@ -871,6 +919,18 @@ class TimelineView {
cell.appendChild(div);
cell.appendChild(document.createTextNode(" " + desc.text));
}
+
+ while (this.currentCode.firstChild) {
+ this.currentCode.removeChild(this.currentCode.firstChild);
+ }
+ if (currentCodeId) {
+ let currentCode = file.code[currentCodeId];
+ this.currentCode.appendChild(createTypeDiv(resolveCodeKind(currentCode)));
+ this.currentCode.appendChild(document.createTextNode(currentCode.name));
+
+ } else {
+ this.currentCode.appendChild(document.createTextNode("<none>"));
+ }
}
}
« tools/profview/profile-utils.js ('K') | « tools/profview/profview.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698