Bug 1374333 - Ensure we get profiles for all content processes for tps by waiting until the profiles are gathered before closing the tabs. r?rwood
There seems to be a race where the ProfilerParent::SendGatherProfile Promise can fail
if the shutdown message has been sent by ContentParent. This means that exit profiles
are on their way, but the gatherer is going to hear about the rejected Promises first
and decrement the mPendingProfiles counter (with empty profiles) before the exit
profiles can arrive.
This is a workaround.
Bug 1380785 has been filed for the ProfilerParent race.
MozReview-Commit-ID: LacBwp4ttiP
--- a/testing/talos/talos/talos-powers/components/TalosPowersService.js
+++ b/testing/talos/talos/talos-powers/components/TalosPowersService.js
@@ -117,16 +117,17 @@ TalosPowersService.prototype = {
let encoder = new TextEncoder();
let array = encoder.encode(JSON.stringify(profile));
OS.File.writeAtomic(profileFile, array, {
tmpPath: profileFile + ".tmp",
}).then(() => {
Services.profiler.StopProfiler();
resolve();
+ Services.obs.notifyObservers(null, "talos-profile-gathered");
});
}, (error) => {
Cu.reportError("Failed to gather profile: " + error);
// FIXME: We should probably send a message down to the
// child which causes it to reject the waiting Promise.
reject();
});
});
--- a/testing/talos/talos/talos-powers/content/TalosParentProfiler.js
+++ b/testing/talos/talos/talos-powers/content/TalosParentProfiler.js
@@ -192,10 +192,23 @@ var TalosParentProfiler;
// If marker is omitted, just use the test name
if (!marker) {
marker = currentTest;
}
TalosPowers.profilerMarker(marker);
}
},
+
+ afterProfileGathered() {
+ if (!initted) {
+ return Promise.resolve();
+ }
+
+ return new Promise(resolve => {
+ Services.obs.addObserver(function onGathered() {
+ Services.obs.removeObserver(onGathered, "talos-profile-gathered");
+ resolve();
+ }, "talos-profile-gathered");
+ });
+ }
};
})();
--- a/testing/talos/talos/test.py
+++ b/testing/talos/talos/test.py
@@ -301,17 +301,17 @@ class tabpaint(PageloaderTest):
@register_test()
class tps(PageloaderTest):
"""
Tests the amount of time it takes to switch between tabs
"""
extensions = '${talos}/tests/tabswitch/tabswitch-signed.xpi'
tpmanifest = '${talos}/tests/tabswitch/tps.manifest'
tppagecycles = 5
- gecko_profile_entries = 1000000
+ gecko_profile_entries = 5000000
tploadnocache = True
preferences = {
'addon.test.tabswitch.urlfile': os.path.join('${talos}',
'tests',
'tp5o.html'),
'addon.test.tabswitch.webserver': '${webserver}',
'addon.test.tabswitch.maxurls': -1,
}
--- a/testing/talos/talos/tests/tabswitch/bootstrap.js
+++ b/testing/talos/talos/tests/tabswitch/bootstrap.js
@@ -201,41 +201,38 @@ function switchToTab(tab) {
if (browser.isRemoteBrowser) {
return Task.spawn(function*() {
// The multi-process case requires that we load our utility script
// inside the content, since it's the content that will hear a MozAfterPaint
// once the content is presented to the user.
yield loadTPSContentScript(browser);
let start = Math.floor(window.performance.timing.navigationStart + window.performance.now());
- TalosParentProfiler.resume("start (" + start + "): " + browser.currentURI.spec);
// We need to wait for the TabSwitchDone event to make sure
// that the async tab switcher has shut itself down.
let switchDone = waitForTabSwitchDone(browser);
// Set up our promise that will wait for the content to be
// presented.
let finishPromise = waitForContentPresented(browser);
// Finally, do the tab switch.
gBrowser.selectedTab = tab;
yield switchDone;
let finish = yield finishPromise;
- TalosParentProfiler.mark("end (" + finish + ")");
return finish - start;
});
}
return Task.spawn(function*() {
let win = browser.ownerGlobal;
let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let start = Math.floor(window.performance.timing.navigationStart + window.performance.now());
- TalosParentProfiler.resume("start (" + start + "): " + browser.currentURI.spec);
// There is no async tab switcher for the single-process case,
// but tabbrowser.xml will still fire this once the updateCurrentBrowser
// method runs.
let switchDone = waitForTabSwitchDone(browser);
// Do our tab switch
gBrowser.selectedTab = tab;
// Because the above tab switch is synchronous, we know that the
@@ -245,17 +242,16 @@ function switchToTab(tab) {
yield switchDone;
// Now we'll wait for content to be presented. Because
// this is the single-process case, we pass the last transaction
// id that we got so that we don't get any intermediate MozAfterPaint's
// that might fire before web content is shown.
let finish = yield waitForContentPresented(browser, lastTransactionId);
- TalosParentProfiler.mark("end (" + finish + ")");
return finish - start;
});
}
/**
* For some <xul:browser>, find the <xul:tabbrowser> associated with it,
* and wait until that tabbrowser has finished a tab switch. This function
* assumes a tab switch has started, or is about to start.
@@ -415,17 +411,19 @@ function test(window) {
// content processes, so we cannot do this at the manifest level.
yield switchToTab(tab);
yield switchToTab(initialTab);
}
for (let tab of tabs) {
gBrowser.moveTabTo(tab, 1);
yield forceGC(win, tab.linkedBrowser);
+ TalosParentProfiler.resume("start: " + tab.linkedBrowser.currentURI.spec);
let time = yield switchToTab(tab);
+ TalosParentProfiler.pause("finish: " + tab.linkedBrowser.currentURI.spec);
dump(`${tab.linkedBrowser.currentURI.spec}: ${time}ms\n`);
times.push(time);
yield switchToTab(initialTab);
}
let output = "<!DOCTYPE html>" +
'<html lang="en">' +
"<head><title>Tab Switch Results</title></head>" +
@@ -438,29 +436,27 @@ function test(window) {
}
output += "</table></body></html>";
dump("total tab switch time:" + time + "\n");
let resultsTab = win.gBrowser.loadOneTab(
"data:text/html;charset=utf-8," + encodeURIComponent(output), {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
- let pref = Services.prefs.getBoolPref("browser.tabs.warnOnCloseOtherTabs");
- if (pref)
- Services.prefs.setBoolPref("browser.tabs.warnOnCloseOtherTabs", false);
- win.gBrowser.removeAllTabsBut(resultsTab);
- if (pref)
- Services.prefs.setBoolPref("browser.tabs.warnOnCloseOtherTabs", pref);
+
+ win.gBrowser.selectedTab = resultsTab;
remotePage.sendAsyncMessage("tabswitch-test-results", {
times,
urls: testURLs,
});
- win.close();
+ TalosParentProfiler.afterProfileGathered().then(() => {
+ win.close();
+ });
});
}
function unloadFromWindow(window) {
if (!window)
return;
let toolsMenu = window.document.getElementById("menu_ToolsPopup");
if (!toolsMenu)
--- a/testing/talos/talos/tests/tabswitch/content/test.html
+++ b/testing/talos/talos/tests/tabswitch/content/test.html
@@ -2,16 +2,17 @@
<head>
<script>
function do_test(override) {
if (override || document.location.hash.indexOf("#auto") == 0) {
sendAsyncMessage("tabswitch-do-test");
addMessageListener("tabswitch-test-results", function onMessage(msg) {
let data = msg.data;
content.tpRecordTime(data.times.join(","), 0, data.urls.join(","));
+ sendAsyncMessage("tabswitch-test-results-reported");
});
}
}
</script>
</head>
<body onload="do_test(false)">
Hello Talos!
</body>