mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Backed out 3 changesets (bug 1540135, bug 1547018, bug 1549723) for causing leaks
Backed out changeset 72723e7257b1 (bug 1549723) Backed out changeset 5c597a3f82bd (bug 1547018) Backed out changeset eb8757f9586f (bug 1540135)
This commit is contained in:
parent
520193d092
commit
bd960ef22c
@ -1,419 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* This test records I/O syscalls done on the main thread during startup.
|
||||
*
|
||||
* To run this test similar to try server, you need to run:
|
||||
* ./mach package
|
||||
* ./mach test --appname=dist <path to test>
|
||||
*
|
||||
* If you made changes that cause this test to fail, it's likely because you
|
||||
* are touching more files or directories during startup.
|
||||
* Most code has no reason to use main thread I/O.
|
||||
* If for some reason accessing the file system on the main thread is currently
|
||||
* unavoidable, consider defering the I/O as long as you can, ideally after
|
||||
* the end of startup.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/* Set this to true only for debugging purpose; it makes the output noisy. */
|
||||
const kDumpAllStacks = false;
|
||||
|
||||
// Shortcuts for conditions.
|
||||
const LINUX = AppConstants.platform == "linux";
|
||||
const WIN = AppConstants.platform == "win";
|
||||
const MAC = AppConstants.platform == "macosx";
|
||||
|
||||
/* Paths in the whitelist can:
|
||||
* - be a full path, eg. "/etc/mime.types"
|
||||
* - have a prefix which will be resolved using Services.dirsvc
|
||||
* eg. "GreD:omni.ja"
|
||||
* It's possible to have only a prefix, in thise case the directory will
|
||||
* still be resolved, eg. "UAppData:"
|
||||
* - use * at the begining and/or end as a wildcard
|
||||
* The folder separator is '/' even for Windows paths, where it'll be
|
||||
* automatically converted to '\'.
|
||||
*
|
||||
* Specifying 'ignoreIfUnused: true' will make the test ignore unused entries;
|
||||
* without this the test is strict and will fail if a whitelist entry isn't used.
|
||||
*
|
||||
* Each entry specifies the maximum number of times an operation is expected to
|
||||
* occur.
|
||||
* The operations currently reported by the I/O interposer are:
|
||||
* create/open: only supported on Windows currently. The test currently
|
||||
* ignores these markers to have a shorter initial whitelist.
|
||||
* Adding Unix support is bug 1533779.
|
||||
* stat: supported on all platforms when checking the last modified date or
|
||||
* file size. Supported only on Windows when checking if a file exists;
|
||||
* fixing this inconsistency is bug 1536109.
|
||||
* read: supported on all platforms, but unix platforms will only report read
|
||||
* calls going through NSPR.
|
||||
* write: supported on all platforms, but Linux will only report write calls
|
||||
* going through NSPR.
|
||||
* close: supported only on Unix, and only for close calls going through NSPR.
|
||||
* Adding Windows support is bug 1524574.
|
||||
* fsync: supported only on Windows.
|
||||
*
|
||||
* If an entry specifies more than one operation, if at least one of them is
|
||||
* encountered, the test won't report a failure for the entry. This helps when
|
||||
* whitelisting cases where the reported operations aren't the same on all
|
||||
* platforms due to the I/O interposer inconsistencies across platforms
|
||||
* documented above.
|
||||
*/
|
||||
const processes = {
|
||||
"Web Content": [
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||
path: "XCurProcD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
],
|
||||
"Privileged Content": [
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||
path: "XCurProcD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
],
|
||||
"WebExtensions": [
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||
path: "XCurProcD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:screenshots@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
close: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function expandWhitelistPath(path) {
|
||||
if (path.includes(":")) {
|
||||
let [prefix, suffix] = path.split(":");
|
||||
let [key, property] = prefix.split(".");
|
||||
let dir = Services.dirsvc.get(key, Ci.nsIFile);
|
||||
if (property) {
|
||||
dir = dir[property];
|
||||
}
|
||||
|
||||
// Resolve symLinks.
|
||||
let dirPath = dir.path;
|
||||
while (dir && !dir.isSymlink()) {
|
||||
dir = dir.parent;
|
||||
}
|
||||
if (dir) {
|
||||
dirPath = dirPath.replace(dir.path, dir.target);
|
||||
}
|
||||
|
||||
path = dirPath;
|
||||
|
||||
if (suffix) {
|
||||
path += "/" + suffix;
|
||||
}
|
||||
}
|
||||
if (AppConstants.platform == "win") {
|
||||
path = path.replace(/\//g, "\\");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function getStackFromProfile(profile, stack) {
|
||||
const stackPrefixCol = profile.stackTable.schema.prefix;
|
||||
const stackFrameCol = profile.stackTable.schema.frame;
|
||||
const frameLocationCol = profile.frameTable.schema.location;
|
||||
|
||||
let result = [];
|
||||
while (stack) {
|
||||
let sp = profile.stackTable.data[stack];
|
||||
let frame = profile.frameTable.data[sp[stackFrameCol]];
|
||||
stack = sp[stackPrefixCol];
|
||||
frame = profile.stringTable[frame[frameLocationCol]];
|
||||
if (frame != "js::RunScript" && !frame.startsWith("next (self-hosted:")) {
|
||||
result.push(frame);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getIOMarkersFromProfile(profile) {
|
||||
const nameCol = profile.markers.schema.name;
|
||||
const dataCol = profile.markers.schema.data;
|
||||
|
||||
let markers = [];
|
||||
for (let m of profile.markers.data) {
|
||||
let markerName = profile.stringTable[m[nameCol]];
|
||||
|
||||
if (markerName != "FileIO")
|
||||
continue;
|
||||
|
||||
let markerData = m[dataCol];
|
||||
if (markerData.source == "sqlite-mainthread") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let samples = markerData.stack.samples;
|
||||
let stack = samples.data[0][samples.schema.stack];
|
||||
markers.push({operation: markerData.operation,
|
||||
filename: markerData.filename,
|
||||
source: markerData.source,
|
||||
stackId: stack});
|
||||
}
|
||||
|
||||
return markers;
|
||||
}
|
||||
|
||||
function pathMatches(path, filename) {
|
||||
path = path.toLowerCase();
|
||||
return path == filename || // Full match
|
||||
// Wildcard on both sides of the path
|
||||
(path.startsWith("*") && path.endsWith("*") &&
|
||||
filename.includes(path.slice(1, -1))) ||
|
||||
// Wildcard suffix
|
||||
(path.endsWith("*") && filename.startsWith(path.slice(0, -1))) ||
|
||||
// Wildcard prefix
|
||||
(path.startsWith("*") && filename.endsWith(path.slice(1)));
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
if (!AppConstants.NIGHTLY_BUILD && !AppConstants.MOZ_DEV_EDITION && !AppConstants.DEBUG) {
|
||||
ok(!("@mozilla.org/test/startuprecorder;1" in Cc),
|
||||
"the startup recorder component shouldn't exist in this non-nightly/non-devedition/" +
|
||||
"non-debug build.");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
let omniJa = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||
omniJa.append("omni.ja");
|
||||
if (!omniJa.exists()) {
|
||||
ok(false, "This test requires a packaged build, " +
|
||||
"run 'mach package' and then use --appname=dist");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
|
||||
await startupRecorder.done;
|
||||
|
||||
for (let process in processes) {
|
||||
processes[process] =
|
||||
processes[process].filter(entry => !("condition" in entry) || entry.condition);
|
||||
processes[process].forEach(entry => {
|
||||
entry.path = expandWhitelistPath(entry.path, entry.canonicalize);
|
||||
});
|
||||
}
|
||||
|
||||
let tmpPath = expandWhitelistPath(MAC ? "TmpD:" : "/dev/shm").toLowerCase();
|
||||
let shouldPass = true;
|
||||
for (let procName in processes) {
|
||||
let whitelist = processes[procName];
|
||||
info(`whitelisted paths for ${procName} process:\n` +
|
||||
whitelist.map(e => {
|
||||
let operations = Object.keys(e).filter(k => !["path", "condition"].includes(k))
|
||||
.map(k => `${k}: ${e[k]}`);
|
||||
return ` ${e.path} - ${operations.join(", ")}`;
|
||||
}).join("\n"));
|
||||
|
||||
let profile;
|
||||
for (let process of startupRecorder.data.profile.processes) {
|
||||
if (process.threads[0].processName == procName) {
|
||||
profile = process.threads[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (procName == "Privileged Content" && !profile) {
|
||||
// The Privileged Content is started from an idle task that may not have
|
||||
// been executed yet at the time we captured the startup profile in
|
||||
// startupRecorder.
|
||||
todo(false, `profile for ${procName} process not found`);
|
||||
} else {
|
||||
ok(profile, `Found profile for ${procName} process`);
|
||||
}
|
||||
if (!profile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let markers = getIOMarkersFromProfile(profile);
|
||||
for (let marker of markers) {
|
||||
if (marker.operation == "create/open") {
|
||||
// TODO: handle these I/O markers once they are supported on
|
||||
// non-Windows platforms.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert to lower case before comparing because the OS X test slaves
|
||||
// have the 'Firefox' folder in 'Library/Application Support' created
|
||||
// as 'firefox' for some reason.
|
||||
let filename = marker.filename.toLowerCase();
|
||||
|
||||
if (!filename) {
|
||||
// We are still missing the filename on some mainthreadio markers,
|
||||
// these markers are currently useless for the purpose of this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!WIN) {
|
||||
if (filename == "/dev/urandom") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore I/O due to IPC. This doesn't really touch the disk.
|
||||
if (filename.startsWith(tmpPath + "/org.chromium.")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let expected = false;
|
||||
for (let entry of whitelist) {
|
||||
if (pathMatches(entry.path, filename)) {
|
||||
entry[marker.operation] = (entry[marker.operation] || 0) - 1;
|
||||
entry._used = true;
|
||||
expected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!expected) {
|
||||
record(false,
|
||||
`unexpected ${marker.operation} on ${marker.filename} in ${procName} process`,
|
||||
undefined,
|
||||
" " + getStackFromProfile(profile, marker.stackId).join("\n "));
|
||||
shouldPass = false;
|
||||
}
|
||||
info(`(${marker.source}) ${marker.operation} - ${marker.filename}`);
|
||||
if (kDumpAllStacks) {
|
||||
info(getStackFromProfile(profile, marker.stackId).map(f => " " + f)
|
||||
.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
for (let entry of whitelist) {
|
||||
for (let op in entry) {
|
||||
if (["path", "condition", "ignoreIfUnused", "_used"].includes(op)) {
|
||||
continue;
|
||||
}
|
||||
let message = `${op} on ${entry.path} `;
|
||||
if (entry[op] == 0) {
|
||||
message += "as many times as expected";
|
||||
} else if (entry[op] > 0) {
|
||||
message += `allowed ${entry[op]} more times`;
|
||||
} else {
|
||||
message += `${entry[op] * -1} more times than expected`;
|
||||
}
|
||||
ok(entry[op] >= 0, `${message} in ${procName} process`);
|
||||
}
|
||||
if (!("_used" in entry) && !entry.ignoreIfUnused) {
|
||||
ok(false, `unused whitelist entry ${procName}: ${entry.path}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPass) {
|
||||
ok(shouldPass, "No unexpected main thread I/O during startup");
|
||||
} else {
|
||||
const filename = "child-startup-mainthreadio-profile.json";
|
||||
let path = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment)
|
||||
.get("MOZ_UPLOAD_DIR");
|
||||
let encoder = new TextEncoder();
|
||||
let profilePath = OS.Path.join(path, filename);
|
||||
await OS.File.writeAtomic(profilePath,
|
||||
encoder.encode(JSON.stringify(startupRecorder.data.profile)));
|
||||
ok(false,
|
||||
"Found some unexpected main thread I/O during child process startup; " +
|
||||
"profile uploaded in " + filename);
|
||||
}
|
||||
});
|
@ -1,930 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* This test records I/O syscalls done on the main thread during startup.
|
||||
*
|
||||
* To run this test similar to try server, you need to run:
|
||||
* ./mach package
|
||||
* ./mach test --appname=dist <path to test>
|
||||
*
|
||||
* If you made changes that cause this test to fail, it's likely because you
|
||||
* are touching more files or directories during startup.
|
||||
* Most code has no reason to use main thread I/O.
|
||||
* If for some reason accessing the file system on the main thread is currently
|
||||
* unavoidable, consider defering the I/O as long as you can, ideally after
|
||||
* the end of startup.
|
||||
* If your code isn't strictly required to show the first browser window,
|
||||
* it shouldn't be loaded before we are done with first paint.
|
||||
* Finally, if your code isn't really needed during startup, it should not be
|
||||
* loaded before we have started handling user events.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
/* Set this to true only for debugging purpose; it makes the output noisy. */
|
||||
const kDumpAllStacks = false;
|
||||
|
||||
// Shortcuts for conditions.
|
||||
const LINUX = AppConstants.platform == "linux";
|
||||
const WIN = AppConstants.platform == "win";
|
||||
const MAC = AppConstants.platform == "macosx";
|
||||
|
||||
/* Paths in the whitelist can:
|
||||
* - be a full path, eg. "/etc/mime.types"
|
||||
* - have a prefix which will be resolved using Services.dirsvc
|
||||
* eg. "GreD:omni.ja"
|
||||
* It's possible to have only a prefix, in thise case the directory will
|
||||
* still be resolved, eg. "UAppData:"
|
||||
* - use * at the begining and/or end as a wildcard
|
||||
* - For Windows specific entries that require resolving the path to its
|
||||
* canonical form, ie. the old DOS 8.3 format, use canonicalize: true.
|
||||
* This is needed for stat calls to non-existent files.
|
||||
* The folder separator is '/' even for Windows paths, where it'll be
|
||||
* automatically converted to '\'.
|
||||
*
|
||||
* Specifying 'ignoreIfUnused: true' will make the test ignore unused entries;
|
||||
* without this the test is strict and will fail if a whitelist entry isn't used.
|
||||
*
|
||||
* Each entry specifies the maximum number of times an operation is expected to
|
||||
* occur.
|
||||
* The operations currently reported by the I/O interposer are:
|
||||
* create/open: only supported on Windows currently. The test currently
|
||||
* ignores these markers to have a shorter initial whitelist.
|
||||
* Adding Unix support is bug 1533779.
|
||||
* stat: supported on all platforms when checking the last modified date or
|
||||
* file size. Supported only on Windows when checking if a file exists;
|
||||
* fixing this inconsistency is bug 1536109.
|
||||
* read: supported on all platforms, but unix platforms will only report read
|
||||
* calls going through NSPR.
|
||||
* write: supported on all platforms, but Linux will only report write calls
|
||||
* going through NSPR.
|
||||
* close: supported only on Unix, and only for close calls going through NSPR.
|
||||
* Adding Windows support is bug 1524574.
|
||||
* fsync: supported only on Windows.
|
||||
*
|
||||
* If an entry specifies more than one operation, if at least one of them is
|
||||
* encountered, the test won't report a failure for the entry. This helps when
|
||||
* whitelisting cases where the reported operations aren't the same on all
|
||||
* platforms due to the I/O interposer inconsistencies across platforms
|
||||
* documented above.
|
||||
*/
|
||||
const startupPhases = {
|
||||
// Anything done before or during app-startup must have a compelling reason
|
||||
// to run before we have even selected the user profile.
|
||||
"before profile selection": [
|
||||
{ // bug 1541226
|
||||
path: "UAppData:",
|
||||
condition: WIN,
|
||||
stat: 3,
|
||||
},
|
||||
{ // bug 1541200
|
||||
path: "UAppData:Crash Reports/InstallTime20*",
|
||||
stat: 1, // only caught on Windows.
|
||||
read: 1,
|
||||
write: 2,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1541200
|
||||
path: "UAppData:Crash Reports/LastCrash",
|
||||
condition: WIN,
|
||||
stat: 1, // only caught on Windows.
|
||||
read: 1,
|
||||
},
|
||||
{ // bug 1541200
|
||||
path: "UAppData:Crash Reports/LastCrash",
|
||||
condition: !WIN,
|
||||
ignoreIfUnused: true, // only if we ever crashed on this machine
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1541226
|
||||
path: "DefProfLRt.parent:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // At least the read seems unavoidable for a regular startup.
|
||||
path: "UAppData:profiles.ini",
|
||||
condition: MAC,
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1546931
|
||||
path: "UAppData:installs.ini",
|
||||
condition: WIN || MAC,
|
||||
ignoreIfUnused: true, // only if a real profile exists on the system.
|
||||
read: 1,
|
||||
stat: 2,
|
||||
close: 1,
|
||||
},
|
||||
{ // At least the read seems unavoidable for a regular startup.
|
||||
path: "UAppData:profiles.ini",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // only if a real profile exists on the system.
|
||||
read: 1,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541226, bug 1363586, bug 1541593
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
stat: 3,
|
||||
},
|
||||
{
|
||||
path: "ProfLD:.startup-incomplete",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1541491 to stop using this file, bug 1541494 to write correctly.
|
||||
path: "ProfLD:compatibility.ini",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
write: 18,
|
||||
close: 1,
|
||||
},
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "ProfD:parent.lock",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541603
|
||||
path: "ProfD:minidumps",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543746
|
||||
path: "XCurProcD:defaults/preferences",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache-child-current.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache-child.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache-current.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544037
|
||||
path: "ProfLDS:startupCache/startupCache." +
|
||||
(Services.appinfo.is64Bit ? 8 : 4) + ".little",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541601
|
||||
path: "PrfDef:channel-prefs.js",
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // At least the read seems unavoidable
|
||||
path: "PrefD:prefs.js",
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1543752
|
||||
path: "PrefD:user.js",
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{
|
||||
path: "*ld.so.conf*",
|
||||
condition: LINUX,
|
||||
read: 22,
|
||||
close: 11,
|
||||
},
|
||||
{ // bug 1546838
|
||||
path: "ProfD:xulstore/data.mdb",
|
||||
condition: WIN,
|
||||
write: 1,
|
||||
fsync: 1,
|
||||
},
|
||||
],
|
||||
|
||||
"before opening first browser window": [
|
||||
{ // bug 1541226
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
{
|
||||
path: "XCurProcD:blocklist.xml",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1534745
|
||||
path: "ProfD:cookies.sqlite-journal",
|
||||
condition: !LINUX,
|
||||
stat: 3,
|
||||
write: 4,
|
||||
},
|
||||
{ // bug 1534745
|
||||
path: "ProfD:cookies.sqlite",
|
||||
condition: !LINUX,
|
||||
stat: 2,
|
||||
read: 2,
|
||||
write: 1,
|
||||
},
|
||||
{ // bug 1534745
|
||||
path: "ProfD:cookies.sqlite-wal",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 975996
|
||||
path: "ProfD:permissions.sqlite",
|
||||
condition: WIN || MAC,
|
||||
fsync: 7,
|
||||
read: 2,
|
||||
stat: 1,
|
||||
write: 10,
|
||||
},
|
||||
{ // bug 975996
|
||||
path: "ProfD:permissions.sqlite-journal",
|
||||
condition: WIN || MAC,
|
||||
fsync: 7,
|
||||
stat: 26,
|
||||
write: 38,
|
||||
},
|
||||
{ // bug 975996
|
||||
path: "ProfD:permissions.sqlite-wal",
|
||||
condition: WIN,
|
||||
stat: 20,
|
||||
},
|
||||
{ // Seems done by OS X and outside of our control.
|
||||
path: "*.savedState/restorecount.plist",
|
||||
condition: MAC,
|
||||
ignoreIfUnused: true,
|
||||
write: 1,
|
||||
},
|
||||
{
|
||||
path: "*ld.so.conf*",
|
||||
condition: LINUX,
|
||||
read: 22,
|
||||
close: 11,
|
||||
},
|
||||
{ // bug 1545167
|
||||
path: "/etc/mime.types",
|
||||
condition: LINUX,
|
||||
read: 3,
|
||||
close: 3,
|
||||
},
|
||||
{
|
||||
path: "UChrm:userChrome.css",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541233
|
||||
path: "UChrm:userContent.css",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "XREUSysExt:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "XRESysExtDev:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "ProfD:extensions",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "XCurProcD:extensions",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "UAppData:",
|
||||
ignoreIfUnused: true, // sometimes before opening first browser window,
|
||||
// sometimes before first paint
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1546838
|
||||
path: "ProfD:xulstore/data.mdb",
|
||||
condition: WIN,
|
||||
read: 1,
|
||||
},
|
||||
],
|
||||
|
||||
// We reach this phase right after showing the first browser window.
|
||||
// This means that any I/O at this point delayed first paint.
|
||||
"before first paint": [
|
||||
{ // bug 1541226
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545119
|
||||
path: "OldUpdRootD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1446012
|
||||
path: "UpdRootD:updates/0/update.status",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:pluginreg.dat",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:pluginreg.dat.tmp",
|
||||
stat: 1,
|
||||
write: 64,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "APlugns:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "UserPlugins.parent:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "UserPlugins:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/nptest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/npsecondtest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/npthirdtest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/npswftest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1545167
|
||||
path: "/etc/mime.types",
|
||||
condition: LINUX,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // We only hit this for new profiles.
|
||||
path: "XREAppDist:distribution.ini",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "*WindowsApps/microsoft.windowscommunicationsapps*",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 3,
|
||||
},
|
||||
{ // bug 1545139
|
||||
path: "*Fonts/StaticCache.dat",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // Only on Win7
|
||||
read: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "UAppData:",
|
||||
ignoreIfUnused: true, // sometimes before opening first browser window,
|
||||
// sometimes before first paint
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // Not in packaged builds; useful for artifact builds.
|
||||
path: "GreD:ScalarArtifactDefinitions.json",
|
||||
condition: WIN && !AppConstants.MOZILLA_OFFICIAL,
|
||||
stat: 1,
|
||||
},
|
||||
{ // Not in packaged builds; useful for artifact builds.
|
||||
path: "GreD:EventArtifactDefinitions.json",
|
||||
condition: WIN && !AppConstants.MOZILLA_OFFICIAL,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1546838
|
||||
path: "ProfD:xulstore/data.mdb",
|
||||
condition: MAC,
|
||||
write: 3,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "GreD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
],
|
||||
|
||||
// We are at this phase once we are ready to handle user events.
|
||||
// Any IO at this phase or before gets in the way of the user
|
||||
// interacting with the first browser window.
|
||||
"before handling user events": [
|
||||
{
|
||||
path: "GreD:update.test",
|
||||
ignoreIfUnused: true,
|
||||
condition: LINUX,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db",
|
||||
condition: WIN,
|
||||
read: 2,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db-journal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db-wal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:pkcs11.txt",
|
||||
condition: WIN,
|
||||
read: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db",
|
||||
condition: WIN,
|
||||
read: 2,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db-journal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 5,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db-wal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 5,
|
||||
},
|
||||
{
|
||||
path: "XREAppFeat:webcompat-reporter@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1003968
|
||||
path: "XREAppDist:searchplugins",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "XCurProcD:extensions",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "GreD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
],
|
||||
|
||||
// Things that are expected to be completely out of the startup path
|
||||
// and loaded lazily when used for the first time by the user should
|
||||
// be blacklisted here.
|
||||
"before becoming idle": [
|
||||
{
|
||||
path: "XREAppFeat:screenshots@mozilla.org.xpi",
|
||||
ignoreIfUnused: true,
|
||||
close: 1,
|
||||
},
|
||||
{
|
||||
path: "XREAppFeat:webcompat-reporter@mozilla.org.xpi",
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite-journal",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 1,
|
||||
stat: 4,
|
||||
write: 2,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite-wal",
|
||||
ignoreIfUnused: true,
|
||||
stat: 4,
|
||||
fsync: 3,
|
||||
write: 148,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite-shm",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 2,
|
||||
read: 1,
|
||||
stat: 3,
|
||||
write: 1310,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite-journal",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 2,
|
||||
stat: 7,
|
||||
write: 7,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite-wal",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 2,
|
||||
stat: 7,
|
||||
write: 15,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite-shm",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 3,
|
||||
read: 4,
|
||||
stat: 4,
|
||||
write: 1300,
|
||||
},
|
||||
{
|
||||
path: "ProfD:key4.db-journal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{
|
||||
path: "ProfD:key4.db-wal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 3,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 7,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
for (let name of ["d3d11layers", "d3d9video", "glcontext", "d3d11video", "wmfvpxvideo"]) {
|
||||
startupPhases["before first paint"].push({
|
||||
path: `ProfD:${name}.guard`,
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
});
|
||||
}
|
||||
|
||||
function expandWhitelistPath(path, canonicalize = false) {
|
||||
if (path.includes(":")) {
|
||||
let [prefix, suffix] = path.split(":");
|
||||
let [key, property] = prefix.split(".");
|
||||
let dir = Services.dirsvc.get(key, Ci.nsIFile);
|
||||
if (property) {
|
||||
dir = dir[property];
|
||||
}
|
||||
|
||||
if (canonicalize) {
|
||||
path = dir.QueryInterface(Ci.nsILocalFileWin).canonicalPath;
|
||||
} else {
|
||||
// Resolve symLinks.
|
||||
let dirPath = dir.path;
|
||||
while (dir && !dir.isSymlink()) {
|
||||
dir = dir.parent;
|
||||
}
|
||||
if (dir) {
|
||||
dirPath = dirPath.replace(dir.path, dir.target);
|
||||
}
|
||||
|
||||
path = dirPath;
|
||||
}
|
||||
|
||||
if (suffix) {
|
||||
path += "/" + suffix;
|
||||
}
|
||||
}
|
||||
if (AppConstants.platform == "win") {
|
||||
path = path.replace(/\//g, "\\");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function getStackFromProfile(profile, stack) {
|
||||
const stackPrefixCol = profile.stackTable.schema.prefix;
|
||||
const stackFrameCol = profile.stackTable.schema.frame;
|
||||
const frameLocationCol = profile.frameTable.schema.location;
|
||||
|
||||
let result = [];
|
||||
while (stack) {
|
||||
let sp = profile.stackTable.data[stack];
|
||||
let frame = profile.frameTable.data[sp[stackFrameCol]];
|
||||
stack = sp[stackPrefixCol];
|
||||
frame = profile.stringTable[frame[frameLocationCol]];
|
||||
if (frame != "js::RunScript" && !frame.startsWith("next (self-hosted:")) {
|
||||
result.push(frame);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function pathMatches(path, filename) {
|
||||
path = path.toLowerCase();
|
||||
return path == filename || // Full match
|
||||
// Wildcard on both sides of the path
|
||||
(path.startsWith("*") && path.endsWith("*") &&
|
||||
filename.includes(path.slice(1, -1))) ||
|
||||
// Wildcard suffix
|
||||
(path.endsWith("*") && filename.startsWith(path.slice(0, -1))) ||
|
||||
// Wildcard prefix
|
||||
(path.startsWith("*") && filename.endsWith(path.slice(1)));
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
if (!AppConstants.NIGHTLY_BUILD && !AppConstants.MOZ_DEV_EDITION && !AppConstants.DEBUG) {
|
||||
ok(!("@mozilla.org/test/startuprecorder;1" in Cc),
|
||||
"the startup recorder component shouldn't exist in this non-nightly/non-devedition/" +
|
||||
"non-debug build.");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
let omniJa = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||
omniJa.append("omni.ja");
|
||||
if (!omniJa.exists()) {
|
||||
ok(false, "This test requires a packaged build, " +
|
||||
"run 'mach package' and then use --appname=dist");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
|
||||
await startupRecorder.done;
|
||||
|
||||
// Add system add-ons to the whitelist dynamically.
|
||||
// They should go in the omni.ja file (bug 1357205).
|
||||
{
|
||||
let addons = await AddonManager.getAddonsByTypes(["extension"]);
|
||||
for (let addon of addons) {
|
||||
if (addon.isSystem) {
|
||||
startupPhases["before opening first browser window"].push({
|
||||
path: `XREAppFeat:${addon.id}.xpi`,
|
||||
stat: 3,
|
||||
close: 2,
|
||||
});
|
||||
startupPhases["before handling user events"].push({
|
||||
path: `XREAppFeat:${addon.id}.xpi`,
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for main thread I/O markers in the startup profile.
|
||||
let profile = startupRecorder.data.profile.threads[0];
|
||||
|
||||
let phases = {};
|
||||
{
|
||||
const nameCol = profile.markers.schema.name;
|
||||
const dataCol = profile.markers.schema.data;
|
||||
|
||||
let markersForCurrentPhase = [];
|
||||
|
||||
for (let m of profile.markers.data) {
|
||||
let markerName = profile.stringTable[m[nameCol]];
|
||||
if (markerName.startsWith("startupRecorder:")) {
|
||||
phases[markerName.split("startupRecorder:")[1]] = markersForCurrentPhase;
|
||||
markersForCurrentPhase = [];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (markerName != "FileIO")
|
||||
continue;
|
||||
|
||||
let markerData = m[dataCol];
|
||||
if (markerData.source == "sqlite-mainthread") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let samples = markerData.stack.samples;
|
||||
let stack = samples.data[0][samples.schema.stack];
|
||||
markersForCurrentPhase.push({operation: markerData.operation,
|
||||
filename: markerData.filename,
|
||||
source: markerData.source,
|
||||
stackId: stack});
|
||||
}
|
||||
}
|
||||
|
||||
for (let phase in startupPhases) {
|
||||
startupPhases[phase] =
|
||||
startupPhases[phase].filter(entry => !("condition" in entry) || entry.condition);
|
||||
startupPhases[phase].forEach(entry => {
|
||||
entry.path = expandWhitelistPath(entry.path, entry.canonicalize);
|
||||
});
|
||||
}
|
||||
|
||||
let tmpPath = expandWhitelistPath(MAC ? "TmpD:" : "/dev/shm").toLowerCase();
|
||||
let shouldPass = true;
|
||||
for (let phase in phases) {
|
||||
let whitelist = startupPhases[phase];
|
||||
info(`whitelisted paths ${phase}:\n` +
|
||||
whitelist.map(e => {
|
||||
let operations = Object.keys(e).filter(k => k != "path")
|
||||
.map(k => `${k}: ${e[k]}`);
|
||||
return ` ${e.path} - ${operations.join(", ")}`;
|
||||
}).join("\n"));
|
||||
|
||||
let markers = phases[phase];
|
||||
for (let marker of markers) {
|
||||
if (marker.operation == "create/open") {
|
||||
// TODO: handle these I/O markers once they are supported on
|
||||
// non-Windows platforms.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert to lower case before comparing because the OS X test slaves
|
||||
// have the 'Firefox' folder in 'Library/Application Support' created
|
||||
// as 'firefox' for some reason.
|
||||
let filename = marker.filename.toLowerCase();
|
||||
|
||||
if (!filename) {
|
||||
// We are still missing the filename on some mainthreadio markers,
|
||||
// these markers are currently useless for the purpose of this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!WIN) {
|
||||
if (filename == "/dev/urandom") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore I/O due to IPC. This doesn't really touch the disk.
|
||||
if (filename.startsWith(tmpPath + "/org.chromium.")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let expected = false;
|
||||
for (let entry of whitelist) {
|
||||
if (pathMatches(entry.path, filename)) {
|
||||
entry[marker.operation] = (entry[marker.operation] || 0) - 1;
|
||||
entry._used = true;
|
||||
expected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!expected) {
|
||||
record(false,
|
||||
`unexpected ${marker.operation} on ${marker.filename} ${phase}`,
|
||||
undefined,
|
||||
" " + getStackFromProfile(profile, marker.stackId).join("\n "));
|
||||
shouldPass = false;
|
||||
}
|
||||
info(`(${marker.source}) ${marker.operation} - ${marker.filename}`);
|
||||
if (kDumpAllStacks) {
|
||||
info(getStackFromProfile(profile, marker.stackId).map(f => " " + f)
|
||||
.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
for (let entry of whitelist) {
|
||||
for (let op in entry) {
|
||||
if (["path", "condition", "canonicalize", "ignoreIfUnused", "_used"].includes(op)) {
|
||||
continue;
|
||||
}
|
||||
let message = `${op} on ${entry.path} `;
|
||||
if (entry[op] == 0) {
|
||||
message += "as many times as expected";
|
||||
} else if (entry[op] > 0) {
|
||||
message += `allowed ${entry[op]} more times`;
|
||||
} else {
|
||||
message += `${entry[op] * -1} more times than expected`;
|
||||
}
|
||||
ok(entry[op] >= 0, `${message} ${phase}`);
|
||||
}
|
||||
if (!("_used" in entry) && !entry.ignoreIfUnused) {
|
||||
ok(false, `unused whitelist entry ${phase}: ${entry.path}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPass) {
|
||||
ok(shouldPass, "No unexpected main thread I/O during startup");
|
||||
} else {
|
||||
const filename = "startup-mainthreadio-profile.json";
|
||||
let path = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment)
|
||||
.get("MOZ_UPLOAD_DIR");
|
||||
let encoder = new TextEncoder();
|
||||
let profilePath = OS.Path.join(path, filename);
|
||||
await OS.File.writeAtomic(profilePath,
|
||||
encoder.encode(JSON.stringify(startupRecorder.data.profile)));
|
||||
ok(false,
|
||||
"Found some unexpected main thread I/O during startup; profile uploaded in " +
|
||||
filename);
|
||||
}
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
[DEFAULT]
|
||||
# Currently disabled on debug due to debug-only failures, see bug 1549723.
|
||||
skip-if = debug
|
||||
# to avoid overhead when running the browser normally, startupRecorder.js will
|
||||
# do almost nothing unless browser.startup.record is true.
|
||||
# gfx.canvas.willReadFrequently.enable is just an optimization, but needs to be
|
||||
# set during early startup to have an impact as a canvas will be used by
|
||||
# startupRecorder.js
|
||||
prefs =
|
||||
# Skip migration work in BG__migrateUI for browser_startup.js since it isn't
|
||||
# representative of common startup, and triggers Places I/O.
|
||||
browser.migration.version=9999999
|
||||
browser.startup.record=true
|
||||
gfx.canvas.willReadFrequently.enable=true
|
||||
environment =
|
||||
MOZ_PROFILER_STARTUP=1
|
||||
MOZ_PROFILER_STARTUP_FEATURES=js,mainthreadio
|
||||
MOZ_PROFILER_STARTUP_ENTRIES=10000000
|
||||
[../browser_startup_mainthreadio.js]
|
||||
[../browser_startup_content_mainthreadio.js]
|
@ -34,7 +34,6 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
'content/test/pageinfo/browser.ini',
|
||||
'content/test/performance/browser.ini',
|
||||
'content/test/performance/hidpi/browser.ini',
|
||||
'content/test/performance/io/browser.ini',
|
||||
'content/test/performance/legacyurlbar/browser.ini',
|
||||
'content/test/performance/lowdpi/browser.ini',
|
||||
'content/test/permissions/browser.ini',
|
||||
|
@ -63,7 +63,6 @@ startupRecorder.prototype = {
|
||||
if (!Services.prefs.getBoolPref("browser.startup.record", false))
|
||||
return;
|
||||
|
||||
Services.profiler.AddMarker("startupRecorder:" + name);
|
||||
this.data.code[name] = {
|
||||
components: Cu.loadedComponents,
|
||||
modules: Cu.loadedModules,
|
||||
@ -164,24 +163,8 @@ startupRecorder.prototype = {
|
||||
Services.prefs.readStats((key, value) => this.data.prefStats[key] = value);
|
||||
}
|
||||
paints = null;
|
||||
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
if (!env.exists("MOZ_PROFILER_STARTUP")) {
|
||||
this._resolve();
|
||||
this._resolve = null;
|
||||
return;
|
||||
}
|
||||
|
||||
Services.profiler.getProfileDataAsync().then(profileData => {
|
||||
this.data.profile = profileData;
|
||||
// There's no equivalent StartProfiler call in this file because the
|
||||
// profiler is started using the MOZ_PROFILER_STARTUP environment
|
||||
// variable in browser/base/content/test/performance/browser.ini
|
||||
Services.profiler.StopProfiler();
|
||||
|
||||
this._resolve();
|
||||
this._resolve = null;
|
||||
});
|
||||
this._resolve();
|
||||
this._resolve = null;
|
||||
});
|
||||
} else {
|
||||
const topicsToNames = {
|
||||
|
Loading…
Reference in New Issue
Block a user