mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1140569 - Show async stacks attached to timeline markers. r=vporof
This commit is contained in:
parent
764a676c31
commit
8d77d6ea8a
@ -177,12 +177,26 @@ MarkerDetails.prototype = {
|
||||
labelName.setAttribute("value", L10N.getStr(property));
|
||||
parent.appendChild(labelName);
|
||||
|
||||
let wasAsyncParent = false;
|
||||
while (frameIndex > 0) {
|
||||
let frame = frames[frameIndex];
|
||||
let url = frame.source;
|
||||
let displayName = frame.functionDisplayName;
|
||||
let line = frame.line;
|
||||
|
||||
// If the previous frame had an async parent, then the async
|
||||
// cause is in this frame and should be displayed.
|
||||
if (wasAsyncParent) {
|
||||
let asyncBox = this._document.createElement("hbox");
|
||||
let asyncLabel = this._document.createElement("label");
|
||||
asyncLabel.className = "devtools-monospace";
|
||||
asyncLabel.setAttribute("value", L10N.getFormatStr("timeline.markerDetail.asyncStack",
|
||||
frame.asyncCause));
|
||||
asyncBox.appendChild(asyncLabel);
|
||||
parent.appendChild(asyncBox);
|
||||
wasAsyncParent = false;
|
||||
}
|
||||
|
||||
let hbox = this._document.createElement("hbox");
|
||||
|
||||
if (displayName) {
|
||||
@ -219,7 +233,12 @@ MarkerDetails.prototype = {
|
||||
|
||||
parent.appendChild(hbox);
|
||||
|
||||
frameIndex = frame.parent;
|
||||
if (frame.asyncParent) {
|
||||
frameIndex = frame.asyncParent;
|
||||
wasAsyncParent = true;
|
||||
} else {
|
||||
frameIndex = frame.parent;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -70,3 +70,4 @@ timeline.markerDetail.stack=Stack:
|
||||
timeline.markerDetail.startStack=Stack at start:
|
||||
timeline.markerDetail.endStack=Stack at end:
|
||||
timeline.markerDetail.unknownFrame=<unknown location>
|
||||
timeline.markerDetail.asyncStack=(Async: %S)
|
||||
|
@ -21,6 +21,21 @@ function testConsoleTimeEnd() {
|
||||
content.console.timeEnd("cats");
|
||||
}
|
||||
|
||||
function makePromise() {
|
||||
let resolver;
|
||||
new Promise(function(resolve, reject) {
|
||||
testConsoleTime();
|
||||
resolver = resolve;
|
||||
}).then(function(val) {
|
||||
testConsoleTimeEnd();
|
||||
});
|
||||
return resolver;
|
||||
}
|
||||
|
||||
function resolvePromise(resolver) {
|
||||
resolver(23);
|
||||
}
|
||||
|
||||
let TESTS = [{
|
||||
desc: "Stack trace on sync reflow",
|
||||
searchFor: "Reflow",
|
||||
@ -63,6 +78,24 @@ let TESTS = [{
|
||||
ok(markers[0].endStack.functionDisplayName == "testConsoleTimeEnd",
|
||||
"testConsoleTimeEnd is on the stack");
|
||||
}
|
||||
}, {
|
||||
desc: "Async stack trace on Promise",
|
||||
searchFor: "ConsoleTime",
|
||||
setup: function(docShell) {
|
||||
let resolver = makePromise();
|
||||
resolvePromise(resolver);
|
||||
},
|
||||
check: function(markers) {
|
||||
markers = markers.filter(m => m.name == "ConsoleTime");
|
||||
ok(markers.length > 0, "Promise marker includes stack");
|
||||
|
||||
let frame = markers[0].endStack;
|
||||
ok(frame.parent.asyncParent !== null, "Parent frame has async parent");
|
||||
is(frame.parent.asyncParent.asyncCause, "Promise",
|
||||
"Async parent has correct cause");
|
||||
is(frame.parent.asyncParent.functionDisplayName, "makePromise",
|
||||
"Async parent has correct function name");
|
||||
}
|
||||
}];
|
||||
|
||||
timelineContentTest(TESTS);
|
||||
|
@ -111,6 +111,8 @@ let StackFrameCache = Class({
|
||||
* source: <filename string for this frame>,
|
||||
* functionDisplayName: <this frame's inferred function name function or null>,
|
||||
* parent: <frame ID -- an index into the concatenated array mentioned above>
|
||||
* asyncCause: the async cause, or null
|
||||
* asyncParent: <frame ID -- an index into the concatenated array mentioned above>
|
||||
* }
|
||||
*
|
||||
* The intent of this approach is to make it simpler to efficiently
|
||||
@ -151,6 +153,7 @@ let StackFrameCache = Class({
|
||||
|
||||
if (frame) {
|
||||
this._assignFrameIndices(frame.parent);
|
||||
this._assignFrameIndices(frame.asyncParent);
|
||||
}
|
||||
|
||||
const index = this._framesToIndices.size;
|
||||
@ -175,9 +178,12 @@ let StackFrameCache = Class({
|
||||
column: frame.column,
|
||||
source: frame.source,
|
||||
functionDisplayName: frame.functionDisplayName,
|
||||
parent: this._framesToIndices.get(frame.parent)
|
||||
parent: this._framesToIndices.get(frame.parent),
|
||||
asyncParent: this._framesToIndices.get(frame.asyncParent),
|
||||
asyncCause: frame.asyncCause
|
||||
};
|
||||
this._createFrameForms(frame.parent);
|
||||
this._createFrameForms(frame.asyncParent);
|
||||
}
|
||||
|
||||
this._framesToForms.set(frame, form);
|
||||
|
@ -11,16 +11,35 @@ function run_test() {
|
||||
|
||||
let cache = new StackFrameCache();
|
||||
cache.initFrames();
|
||||
cache.addFrame({
|
||||
let baseFrame = {
|
||||
line: 23,
|
||||
column: 77,
|
||||
source: "nowhere",
|
||||
functionDisplayName: "nobody",
|
||||
parent: null
|
||||
});
|
||||
parent: null,
|
||||
asyncParent: null,
|
||||
asyncCause: null
|
||||
};
|
||||
cache.addFrame(baseFrame);
|
||||
|
||||
let event = cache.makeEvent();
|
||||
do_check_eq(event[0], null);
|
||||
do_check_eq(event[1].functionDisplayName, "nobody");
|
||||
do_check_eq(event.length, 2);
|
||||
|
||||
cache.addFrame({
|
||||
line: 24,
|
||||
column: 78,
|
||||
source: "nowhere",
|
||||
functionDisplayName: "still nobody",
|
||||
parent: null,
|
||||
asyncParent: baseFrame,
|
||||
asyncCause: "async"
|
||||
});
|
||||
|
||||
event = cache.makeEvent();
|
||||
do_check_eq(event[0].functionDisplayName, "still nobody");
|
||||
do_check_eq(event[0].parent, 0);
|
||||
do_check_eq(event[0].asyncParent, 1);
|
||||
do_check_eq(event.length, 1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user