Bug 1504133 - Make TalosParentProfiler a singleton module. r=aswan

Differential Revision: https://phabricator.services.mozilla.com/D11259

--HG--
rename : testing/talos/talos/talos-powers/content/TalosParentProfiler.js => testing/talos/talos/talos-powers/content/TalosParentProfiler.jsm
extra : moz-landing-system : lando
This commit is contained in:
Mike Conley 2018-11-08 22:39:30 +00:00
parent a4065c4324
commit 983205d86f
8 changed files with 225 additions and 232 deletions

View File

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

View File

@ -13,11 +13,9 @@ XPCOMUtils.defineLazyModuleGetters(this, {
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 {

View File

@ -1,213 +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 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

@ -0,0 +1,217 @@
/* 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,9 +2,6 @@
* 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.
@ -18,9 +15,8 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
* the content side, just the overhead of spawning a new content process.
*/
XPCOMUtils.defineLazyScriptGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.js");
ChromeUtils.defineModuleGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");

View File

@ -3,7 +3,6 @@ const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.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() {

View File

@ -20,12 +20,10 @@
* 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");
XPCOMUtils.defineLazyScriptGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.js");
ChromeUtils.defineModuleGetter(this, "TalosParentProfiler",
"resource://talos-powers/TalosParentProfiler.jsm");
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;
}
Services.scriptloader.loadSubScript("resource://talos-powers/TalosParentProfiler.js", context);
ChromeUtils.import("resource://talos-powers/TalosParentProfiler.jsm", context);
TalosParentProfiler = context.TalosParentProfiler;
let testURLs = [];