Backed out 4 changesets (bug 1504133) for damp failures on TalosParentProfiler. CLOSED TREE

Backed out changeset 443ffec35c5f (bug 1504133)
Backed out changeset 7bd65d135a65 (bug 1504133)
Backed out changeset c544521fcec8 (bug 1504133)
Backed out changeset e9d439c05850 (bug 1504133)

--HG--
rename : testing/talos/talos/talos-powers/content/TalosParentProfiler.jsm => testing/talos/talos/talos-powers/content/TalosParentProfiler.js
This commit is contained in:
Csoregi Natalia 2018-11-09 01:57:21 +02:00
parent f26087e296
commit 57eccc941b
11 changed files with 297 additions and 261 deletions

View File

@ -39,7 +39,6 @@
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
"@mozilla.org/addons/addon-manager-startup;1",
@ -94,25 +93,9 @@ this.pageloader = class extends ExtensionAPI {
]);
if (env.exists("MOZ_USE_PAGELOADER")) {
// TalosPowers is a separate WebExtension that may or may not already have
// finished loading. tryLoad is used to wait for TalosPowers to be around
// before continuing.
async function tryLoad() {
try {
ChromeUtils.import("resource://talos-powers/TalosParentProfiler.jsm");
} catch (err) {
await new Promise(resolve => setTimeout(resolve, 500));
return tryLoad();
}
return null;
}
// talosStart is async but we're deliberately not await-ing or return-ing
// This is async but we're delibeately not await-ing or return-ing
// it here since it doesn't block extension startup.
tryLoad().then(() => {
talosStart();
});
}
}

View File

@ -8,8 +8,10 @@
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
ChromeUtils.import("resource://gre/modules/E10SUtils.jsm");
ChromeUtils.defineModuleGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyScriptGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.js");
var NUM_CYCLES = 5;
var numPageCycles = 1;

View File

@ -9,14 +9,15 @@
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
Services: "resource://gre/modules/Services.jsm",
SessionStartup: "resource:///modules/sessionstore/SessionStartup.jsm",
setTimeout: "resource://gre/modules/Timer.jsm",
StartupPerformance: "resource:///modules/sessionstore/StartupPerformance.jsm",
TalosParentProfiler: "resource://talos-powers/TalosParentProfiler.jsm",
});
XPCOMUtils.defineLazyScriptGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.js");
/* globals ExtensionAPI */
this.sessionrestore = class extends ExtensionAPI {
@ -46,21 +47,6 @@ this.sessionrestore = class extends ExtensionAPI {
async function observe() {
Services.obs.removeObserver(observe, StartupPerformance.RESTORED_TOPIC);
let win = BrowserWindowTracker.getTopWindow();
let args = win.arguments[0];
if (args && args instanceof Ci.nsIArray) {
// For start-up tests Gecko Profiler arguments are passed to the first URL in
// the query string, with the presumption that some tab that is loaded at start-up
// will want to use them in the TalosContentProfiler.js script.
//
// Because we're running this part of the test in the parent process, we
// pull those arguments from the top window directly. This is mainly so
// that TalosParentProfiler knows where to save the profile.
Cu.importGlobalProperties(["URL"]);
let url = new URL(args.queryElementAt(0, Ci.nsISupportsString).data);
TalosParentProfiler.initFromURLQueryParams(url.search);
}
await TalosParentProfiler.pause("This test measures the time between sessionRestoreInit and sessionRestored, ignore everything around that");
await TalosParentProfiler.finishStartupProfiling();

View File

@ -0,0 +1,21 @@
<html>
<head>
<meta charset="UTF-8"/>
<title>Session Restore Regression Test</title>
<script type="text/javascript" src="chrome://pageloader/content/MozillaFileLogger.js"></script>
<script type="text/javascript" src="resource://talos-powers/TalosContentProfiler.js"></script>
<script type="text/javascript" src="resource://talos-powers/TalosPowersContent.js"></script>
<script type="text/javascript" src="chrome://session-restore-test/content/main.js">
</script>
<div>
<strong>Time between sessionRestoreInit and sessionRestored</strong>
<span id="sessionRestoreInit-to-sessionRestored">
(in progress)
</span>
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
"use strict";
var Services = ChromeUtils.import("resource://gre/modules/Services.jsm", {}).Services;
// Process Message Manager topics.
const MSG_REQUEST = "session-restore-test?duration";
const MSG_PROVIDE = "session-restore-test:duration";
addEventListener("load", function() {
Services.cpmm.addMessageListener(MSG_PROVIDE,
/**
* Display the result, send it to the harness and quit.
*/
async function finish(msg) {
console.log(`main.js: received data on ${MSG_PROVIDE}`, msg);
Services.cpmm.removeMessageListener(MSG_PROVIDE, finish);
var duration = msg.data.duration;
TalosContentProfiler.initFromURLQueryParams(location.search);
await TalosContentProfiler.pause("This test measures the time between sessionRestoreInit and sessionRestored, ignore everything around that");
await TalosContentProfiler.finishStartupProfiling();
// Show result on screen. Nice but not really necessary.
document.getElementById("sessionRestoreInit-to-sessionRestored").textContent = duration + "ms";
// Report data to Talos, if possible
dumpLog("__start_report" +
duration +
"__end_report\n\n");
// Next one is required by the test harness but not used
dumpLog("__startTimestamp" +
Date.now() + // eslint-disable-line mozilla/avoid-Date-timing
"__endTimestamp\n\n");
TalosPowersContent.goQuitApplication();
});
// In case the add-on has broadcasted the message before we were loaded,
// request a second broadcast.
Services.cpmm.sendAsyncMessage(MSG_REQUEST, {});
});

View File

@ -0,0 +1,213 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This utility script is for instrumenting your Talos test for
* performance profiles while running within the parent process.
* Almost all of the functions that this script exposes to the
* Gecko Profiler are synchronous, except for finishTest, since that
* involves requesting the profiles from any content processes and
* then writing to disk.
*
* If your test is running in the content process, you should use
* TalosContentProfiler.js instead.
*/
var TalosParentProfiler;
(function() {
ChromeUtils.import("resource://gre/modules/Services.jsm");
// Whether or not this TalosContentProfiler object has had initFromObject
// or initFromURLQueryParams called on it. Any functions that change the
// state of the Gecko Profiler should only be called after calling either
// initFromObject or initFromURLQueryParams.
let initted = Services.profiler.IsActive();
// The subtest name that beginTest() was called with.
let currentTest = "unknown";
// Profiler settings.
let interval, entries, threadsArray, profileDir;
// Use a bit of XPCOM hackery to get at the Talos Powers service
// implementation...
let TalosPowers =
Cc["@mozilla.org/talos/talos-powers-service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
/**
* Parses an url query string into a JS object.
*
* @param locationSearch (string)
* The location string to parse.
* @returns Object
* The GET params from the location string as
* key-value pairs in the Object.
*/
function searchToObject(locationSearch) {
let pairs = locationSearch.substring(1).split("&");
let result = {};
for (let i in pairs) {
if (pairs[i] !== "") {
let pair = pairs[i].split("=");
result[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
}
}
return result;
}
TalosParentProfiler = {
/**
* Initialize the profiler using profiler settings supplied in a JS object.
*
* @param obj (object)
* The following properties on the object are respected:
* gecko_profile_interval (int)
* gecko_profile_entries (int)
* gecko_profile_threads (string, comma separated list of threads to filter with)
* gecko_profile_dir (string)
*/
initFromObject(obj = {}) {
if (!initted) {
if (("gecko_profile_dir" in obj) && typeof obj.gecko_profile_dir == "string" &&
("gecko_profile_interval" in obj) && Number.isFinite(obj.gecko_profile_interval * 1) &&
("gecko_profile_entries" in obj) && Number.isFinite(obj.gecko_profile_entries * 1) &&
("gecko_profile_threads" in obj) && typeof obj.gecko_profile_threads == "string") {
interval = obj.gecko_profile_interval;
entries = obj.gecko_profile_entries;
threadsArray = obj.gecko_profile_threads.split(",");
profileDir = obj.gecko_profile_dir;
initted = true;
} else {
console.error("Profiler could not init with object: " + JSON.stringify(obj));
}
}
},
/**
* Initialize the profiler using a string from a location string.
*
* @param locationSearch (string)
* The location string to initialize with.
*/
initFromURLQueryParams(locationSearch) {
this.initFromObject(searchToObject(locationSearch));
},
/**
* A Talos test is about to start. Note that the Gecko Profiler will be
* paused immediately after starting and that resume() should be called
* in order to collect samples.
*
* @param testName (string)
* The name of the test to use in Profiler markers.
*/
beginTest(testName) {
if (initted) {
currentTest = testName;
TalosPowers.profilerBegin({ entries, interval, threadsArray });
} else {
let msg = "You should not call beginTest without having first " +
"initted the Profiler";
console.error(msg);
}
},
/**
* A Talos test has finished. This will stop the Gecko Profiler from
* sampling, and return a Promise that resolves once the Profiler has
* finished dumping the multi-process profile to disk.
*
* @returns Promise
* Resolves once the profile has been dumped to disk. The test should
* not try to quit the browser until this has resolved.
*/
finishTest() {
if (initted) {
let profileFile = profileDir + "/" + currentTest + ".profile";
return TalosPowers.profilerFinish(profileFile);
}
let msg = "You should not call finishTest without having first " +
"initted the Profiler";
console.error(msg);
return Promise.reject(msg);
},
/**
* A start-up test has finished. Callers don't need to run beginTest or
* finishTest, but should pause the sampler as soon as possible, and call
* this function to dump the profile.
*
* @returns Promise
* Resolves once the profile has been dumped to disk. The test should
* not try to quit the browser until this has resolved.
*/
finishStartupProfiling() {
if (initted) {
let profileFile = profileDir + "/startup.profile";
return TalosPowers.profilerFinish(profileFile);
}
return Promise.resolve();
},
/**
* Resumes the Gecko Profiler sampler. Can also simultaneously set a marker.
*
* @returns Promise
* Resolves once the Gecko Profiler has resumed.
*/
resume(marker = "") {
if (initted) {
TalosPowers.profilerResume(marker);
}
},
/**
* Pauses the Gecko Profiler sampler. Can also simultaneously set a marker.
*
* @returns Promise
* Resolves once the Gecko Profiler has paused.
*/
pause(marker = "") {
if (initted) {
TalosPowers.profilerPause(marker);
}
},
/**
* Adds a marker to the profile.
*
* @returns Promise
* Resolves once the marker has been set.
*/
mark(marker) {
if (initted) {
// 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");
});
},
};
})();

View File

@ -1,217 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This module is for instrumenting your Talos test for
* performance profiles while running within the parent process.
* Almost all of the functions that this script exposes to the
* Gecko Profiler are synchronous, except for finishTest, since that
* involves requesting the profiles from any content processes and
* then writing to disk.
*
* If your test is running in the content process, you should use the
* TalosContentProfiler.js utility script instead.
*/
var EXPORTED_SYMBOLS = ["TalosParentProfiler"];
ChromeUtils.import("resource://gre/modules/Services.jsm");
const TalosParentProfiler = {
// Whether or not this TalosContentProfiler object has had initFromObject
// or initFromURLQueryParams called on it. Any functions that change the
// state of the Gecko Profiler should only be called after calling either
// initFromObject or initFromURLQueryParams.
initted: false,
// The subtest name that beginTest() was called with.
currentTest: "unknown",
// Profiler settings.
interval: undefined,
entries: undefined,
threadsArray: undefined,
profileDir: undefined,
get TalosPowers() {
// Use a bit of XPCOM hackery to get at the Talos Powers service
// implementation...
return Cc["@mozilla.org/talos/talos-powers-service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
},
/**
* Initialize the profiler using profiler settings supplied in a JS object.
*
* @param obj (object)
* The following properties on the object are respected:
* gecko_profile_interval (int)
* gecko_profile_entries (int)
* gecko_profile_threads (string, comma separated list of threads to filter with)
* gecko_profile_dir (string)
*/
initFromObject(obj = {}) {
if (!this.initted) {
if (("gecko_profile_dir" in obj) && typeof obj.gecko_profile_dir == "string" &&
("gecko_profile_interval" in obj) && Number.isFinite(obj.gecko_profile_interval * 1) &&
("gecko_profile_entries" in obj) && Number.isFinite(obj.gecko_profile_entries * 1) &&
("gecko_profile_threads" in obj) && typeof obj.gecko_profile_threads == "string") {
this.interval = obj.gecko_profile_interval;
this.entries = obj.gecko_profile_entries;
this.threadsArray = obj.gecko_profile_threads.split(",");
this.profileDir = obj.gecko_profile_dir;
this.initted = true;
} else {
console.error("Profiler could not init with object: " + JSON.stringify(obj));
}
}
},
/**
* Initialize the profiler using a string from a location string.
*
* @param locationSearch (string)
* The location string to initialize with.
*/
initFromURLQueryParams(locationSearch) {
this.initFromObject(this.searchToObject(locationSearch));
},
/**
* Parses an url query string into a JS object.
*
* @param locationSearch (string)
* The location string to parse.
* @returns Object
* The GET params from the location string as
* key-value pairs in the Object.
*/
searchToObject(locationSearch) {
let pairs = locationSearch.substring(1).split("&");
let result = {};
for (let i in pairs) {
if (pairs[i] !== "") {
let pair = pairs[i].split("=");
result[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
}
}
return result;
},
/**
* A Talos test is about to start. Note that the Gecko Profiler will be
* paused immediately after starting and that resume() should be called
* in order to collect samples.
*
* @param testName (string)
* The name of the test to use in Profiler markers.
*/
beginTest(testName) {
if (this.initted) {
this.currentTest = testName;
this.TalosPowers.profilerBegin({
entries: this.entries,
interval: this.interval,
threadsArray: this.threadsArray,
});
} else {
let msg = "You should not call beginTest without having first " +
"initted the Profiler";
console.error(msg);
}
},
/**
* A Talos test has finished. This will stop the Gecko Profiler from
* sampling, and return a Promise that resolves once the Profiler has
* finished dumping the multi-process profile to disk.
*
* @returns Promise
* Resolves once the profile has been dumped to disk. The test should
* not try to quit the browser until this has resolved.
*/
finishTest() {
if (this.initted) {
let profileFile = this.profileDir + "/" + this.currentTest + ".profile";
return this.TalosPowers.profilerFinish(profileFile);
}
let msg = "You should not call finishTest without having first " +
"initted the Profiler";
console.error(msg);
return Promise.reject(msg);
},
/**
* A start-up test has finished. Callers don't need to run beginTest or
* finishTest, but should pause the sampler as soon as possible, and call
* this function to dump the profile.
*
* @returns Promise
* Resolves once the profile has been dumped to disk. The test should
* not try to quit the browser until this has resolved.
*/
finishStartupProfiling() {
if (this.initted) {
let profileFile = this.profileDir + "/startup.profile";
return this.TalosPowers.profilerFinish(profileFile);
}
return Promise.resolve();
},
/**
* Resumes the Gecko Profiler sampler. Can also simultaneously set a marker.
*
* @returns Promise
* Resolves once the Gecko Profiler has resumed.
*/
resume(marker = "") {
if (this.initted) {
this.TalosPowers.profilerResume(marker);
}
},
/**
* Pauses the Gecko Profiler sampler. Can also simultaneously set a marker.
*
* @returns Promise
* Resolves once the Gecko Profiler has paused.
*/
pause(marker = "") {
if (this.initted) {
this.TalosPowers.profilerPause(marker);
}
},
/**
* Adds a marker to the profile.
*
* @returns Promise
* Resolves once the marker has been set.
*/
mark(marker) {
if (this.initted) {
// If marker is omitted, just use the test name
if (!marker) {
marker = this.currentTest;
}
this.TalosPowers.profilerMarker(marker);
}
},
afterProfileGathered() {
if (!this.initted) {
return Promise.resolve();
}
return new Promise(resolve => {
Services.obs.addObserver(function onGathered() {
Services.obs.removeObserver(onGathered, "talos-profile-gathered");
resolve();
}, "talos-profile-gathered");
});
},
};

View File

@ -2,6 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
/**
* The purpose of this test it to measure the performance of a
* content process startup.
@ -15,8 +18,9 @@
* the content side, just the overhead of spawning a new content process.
*/
ChromeUtils.defineModuleGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.jsm");
XPCOMUtils.defineLazyScriptGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.js");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");

View File

@ -1,8 +1,10 @@
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm", {});
const { TalosParentProfiler } = ChromeUtils.import("resource://talos-powers/TalosParentProfiler.jsm", {});
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
let scope = {};
Services.scriptloader.loadSubScript("resource://talos-powers/TalosParentProfiler.js", scope);
const { TalosParentProfiler } = scope;
XPCOMUtils.defineLazyGetter(this, "require", function() {
let { require } =

View File

@ -20,10 +20,12 @@
* for certain types of links (_blank links for example) to open new tabs.
*/
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.jsm");
XPCOMUtils.defineLazyScriptGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.js");
const ANIMATION_PREF = "toolkit.cosmeticAnimations.enabled";
const MULTI_OPT_OUT_PREF = "dom.ipc.multiOptOut";

View File

@ -190,7 +190,7 @@ async function test(window) {
return;
}
ChromeUtils.import("resource://talos-powers/TalosParentProfiler.jsm", context);
Services.scriptloader.loadSubScript("resource://talos-powers/TalosParentProfiler.js", context);
TalosParentProfiler = context.TalosParentProfiler;
let testURLs = [];