Commit b9cb78a7 authored by Bret Sepulveda's avatar Bret Sepulveda Committed by Commit Bot

profview: View source code of functions with samples inline.

If profiling is done with --log-source-code profview will now display
a "View source" link for each function in the tree view. Clicking this
will show a new source viewer, with sampled lines highlighted. See the
associated bug for screenshots.

This patch also fixes a bug in the profiler where the source info of
only the first code object for each function would be logged, and
includes some refactoring.

Bug: v8:6240
Change-Id: Ib96a9cfc54543d0dc9bef4657cdeb96ce28b223c
Reviewed-on: https://chromium-review.googlesource.com/1194231
Commit-Queue: Bret Sepulveda <bsep@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55542}
parent 33f2012e
......@@ -1323,7 +1323,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
// <script-offset> is the position within the script
// <inlining-id> is the offset in the <inlining> table
// <inlining> table is a sequence of strings of the form
// F<function-id>O<script-offset>[I<inlining-id>
// F<function-id>O<script-offset>[I<inlining-id>]
// where
// <function-id> is an index into the <fns> function table
// <fns> is the function table encoded as a sequence of strings
......@@ -1335,12 +1335,8 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
<< shared->EndPosition() << kNext;
SourcePositionTableIterator iterator(code->source_position_table());
bool is_first = true;
bool hasInlined = false;
for (; !iterator.done(); iterator.Advance()) {
if (is_first) {
is_first = false;
}
SourcePosition pos = iterator.source_position();
msg << "C" << iterator.code_offset() << "O" << pos.ScriptOffset();
if (pos.isInlined()) {
......@@ -1604,7 +1600,7 @@ bool Logger::EnsureLogScriptSource(Script* script) {
// Make sure the script is written to the log file.
int script_id = script->id();
if (logged_source_code_.find(script_id) != logged_source_code_.end()) {
return false;
return true;
}
// This script has not been logged yet.
logged_source_code_.insert(script_id);
......
......@@ -975,7 +975,7 @@ JsonProfile.prototype.addSourcePositions = function(
if (!entry) return;
var codeId = entry.codeId;
// Resolve the inlined fucntions list.
// Resolve the inlined functions list.
if (inlinedFunctions.length > 0) {
inlinedFunctions = inlinedFunctions.substring(1).split("S");
for (var i = 0; i < inlinedFunctions.length; i++) {
......
......@@ -22,7 +22,7 @@ found in the LICENSE file. -->
Chrome V8 profiling log processor
</h3>
<input type="file" id="fileinput" />
<input type="file" id="fileinput" /><div id="source-status"></div>
<br>
<hr>
......@@ -59,6 +59,10 @@ found in the LICENSE file. -->
</table>
<div>
Current code object: <span id="timeline-currentCode"></span>
<button id="source-viewer-hide-button">Hide source</button>
</div>
<div>
<table id="source-viewer"> </table>
</div>
</div>
......
......@@ -93,9 +93,10 @@ function codeEquals(code1, code2, allowDifferentKinds = false) {
function createNodeFromStackEntry(code, codeId, vmState) {
let name = code ? code.name : "UNKNOWN";
return { name, codeId, type : resolveCodeKindAndVmState(code, vmState),
children : [], ownTicks : 0, ticks : 0 };
let node = createEmptyNode(name);
node.codeId = codeId;
node.type = resolveCodeKindAndVmState(code, vmState);
return node;
}
function childIdFromCode(codeId, code) {
......@@ -148,29 +149,30 @@ function findNextFrame(file, stack, stackPos, step, filter) {
}
function addOrUpdateChildNode(parent, file, stackIndex, stackPos, ascending) {
let stack = file.ticks[stackIndex].s;
let vmState = file.ticks[stackIndex].vm;
let codeId = stack[stackPos];
let code = codeId >= 0 ? file.code[codeId] : undefined;
if (stackPos === -1) {
// We reached the end without finding the next step.
// If we are doing top-down call tree, update own ticks.
if (!ascending) {
parent.ownTicks++;
}
} else {
console.assert(stackPos >= 0 && stackPos < stack.length);
// We found a child node.
let childId = childIdFromCode(codeId, code);
let child = parent.children[childId];
if (!child) {
child = createNodeFromStackEntry(code, codeId, vmState);
child.delayedExpansion = { frameList : [], ascending };
parent.children[childId] = child;
}
child.ticks++;
addFrameToFrameList(child.delayedExpansion.frameList, stackIndex, stackPos);
return;
}
let stack = file.ticks[stackIndex].s;
console.assert(stackPos >= 0 && stackPos < stack.length);
let codeId = stack[stackPos];
let code = codeId >= 0 ? file.code[codeId] : undefined;
// We found a child node.
let childId = childIdFromCode(codeId, code);
let child = parent.children[childId];
if (!child) {
let vmState = file.ticks[stackIndex].vm;
child = createNodeFromStackEntry(code, codeId, vmState);
child.delayedExpansion = { frameList : [], ascending };
parent.children[childId] = child;
}
child.ticks++;
addFrameToFrameList(child.delayedExpansion.frameList, stackIndex, stackPos);
}
// This expands a tree node (direct children only).
......@@ -314,13 +316,7 @@ class FunctionListTree {
this.tree = root;
this.categories = categories;
} else {
this.tree = {
name : "root",
codeId: -1,
children : [],
ownTicks : 0,
ticks : 0
};
this.tree = createEmptyNode("root");
this.categories = null;
}
......@@ -339,7 +335,7 @@ class FunctionListTree {
let codeId = stack[i];
if (codeId < 0 || this.codeVisited[codeId]) continue;
let code = codeId >= 0 ? file.code[codeId] : undefined;
let code = file.code[codeId];
if (this.filter) {
let type = code ? code.type : undefined;
let kind = code ? code.kind : undefined;
......@@ -601,3 +597,15 @@ function computeOptimizationStats(file,
softDeoptimizations,
};
}
function normalizeLeadingWhitespace(lines) {
let regex = /^\s*/;
let minimumLeadingWhitespaceChars = Infinity;
for (let line of lines) {
minimumLeadingWhitespaceChars =
Math.min(minimumLeadingWhitespaceChars, regex.exec(line)[0].length);
}
for (let i = 0; i < lines.length; i++) {
lines[i] = lines[i].substring(minimumLeadingWhitespaceChars);
}
}
......@@ -19,6 +19,10 @@ body {
font-family: 'Roboto', sans-serif;
}
#source-status {
display: inline-block;
}
.tree-row-arrow {
margin-right: 0.2em;
text-align: right;
......@@ -35,6 +39,7 @@ body {
.tree-row-name {
margin-left: 0.2em;
margin-right: 0.2em;
}
.codeid-link {
......@@ -42,6 +47,54 @@ body {
cursor: pointer;
}
.view-source-link {
text-decoration: underline;
cursor: pointer;
font-size: 10pt;
margin-left: 0.6em;
color: #555555;
}
#source-viewer {
border: 1px solid black;
padding: 0.2em;
font-family: 'Roboto Mono', monospace;
white-space: pre;
margin-top: 1em;
margin-bottom: 1em;
}
#source-viewer td.line-none {
background-color: white;
}
#source-viewer td.line-cold {
background-color: #e1f5fe;
}
#source-viewer td.line-mediumcold {
background-color: #b2ebf2;
}
#source-viewer td.line-mediumhot {
background-color: #c5e1a5;
}
#source-viewer td.line-hot {
background-color: #dce775;
}
#source-viewer td.line-superhot {
background-color: #ffee58;
}
#source-viewer .source-line-number {
padding-left: 0.2em;
padding-right: 0.2em;
color: #003c8f;
background-color: #eceff1;
}
div.mode-button {
padding: 1em 3em;
display: inline-block;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment