mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 01:35:35 +00:00
Bug 1593318 - De-duplicate head.js files in profiler tests; r=canaltinova
The tests for xpcshell and mochitests were pretty similar, and need to do similar things. This commit creates a shread-head.js file where those functions can be shared. This patch also renames a few shared functions to give them more clarity in their current usage. Differential Revision: https://phabricator.services.mozilla.com/D51933 --HG-- rename : tools/profiler/tests/xpcshell/head_profiler.js => tools/profiler/tests/xpcshell/head.js extra : moz-landing-system : lando
This commit is contained in:
parent
4c3bf72271
commit
e4d043f0aa
@ -1,5 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
../shared-head.js
|
||||
head.js
|
||||
do_work_500ms.html
|
||||
fixed_height.html
|
||||
|
@ -1,27 +1,16 @@
|
||||
/* import-globals-from ../shared-head.js */
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/tools/profiler/tests/browser/shared-head.js",
|
||||
this
|
||||
);
|
||||
|
||||
const { BrowserTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/BrowserTestUtils.jsm"
|
||||
);
|
||||
|
||||
const BASE_URL = "http://example.com/browser/tools/profiler/tests/browser/";
|
||||
|
||||
const defaultSettings = {
|
||||
entries: 1000000, // 9MB
|
||||
interval: 1, // ms
|
||||
features: ["threads"],
|
||||
threads: ["GeckoMain"],
|
||||
};
|
||||
|
||||
function startProfiler(callersSettings) {
|
||||
const settings = Object.assign({}, defaultSettings, callersSettings);
|
||||
Services.profiler.StartProfiler(
|
||||
settings.entries,
|
||||
settings.interval,
|
||||
settings.features,
|
||||
settings.threads,
|
||||
settings.duration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper function that will stop the profiler of the browser running
|
||||
* with PID contentPid.
|
||||
@ -70,37 +59,3 @@ async function stopProfilerAndGetThreads(contentPid) {
|
||||
|
||||
return stopProfilerNowAndGetThreads(contentPid);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper function be able to run `await wait(500)`. Unfortunately this
|
||||
* is needed as the act of collecting functions relies on the periodic sampling of
|
||||
* the threads. See: https://bugzilla.mozilla.org/show_bug.cgi?id=1529053
|
||||
*
|
||||
* @param {number} time
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function wait(time) {
|
||||
return new Promise(resolve => {
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payloads of a type from a single thread.
|
||||
*
|
||||
* @param {Object} thread The thread from a profile.
|
||||
* @param {string} type The marker payload type, e.g. "DiskIO".
|
||||
* @return {Array} The payloads.
|
||||
*/
|
||||
function getPayloadsOfType(thread, type) {
|
||||
const { markers } = thread;
|
||||
const results = [];
|
||||
for (const markerTuple of markers.data) {
|
||||
const payload = markerTuple[markers.schema.data];
|
||||
if (payload && payload.type === type) {
|
||||
results.push(payload);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
110
tools/profiler/tests/shared-head.js
Normal file
110
tools/profiler/tests/shared-head.js
Normal file
@ -0,0 +1,110 @@
|
||||
/* 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 file contains utilities that can be shared between xpcshell tests and mochitests.
|
||||
*/
|
||||
|
||||
// This Services declaration may shadow another from head.js, so define it as
|
||||
// a var rather than a const.
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const defaultSettings = {
|
||||
entries: 1000000, // 9MB
|
||||
interval: 1, // ms
|
||||
features: ["threads"],
|
||||
threads: ["GeckoMain"],
|
||||
};
|
||||
|
||||
function startProfiler(callersSettings) {
|
||||
const settings = Object.assign({}, defaultSettings, callersSettings);
|
||||
Services.profiler.StartProfiler(
|
||||
settings.entries,
|
||||
settings.interval,
|
||||
settings.features,
|
||||
settings.threads,
|
||||
settings.duration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper function be able to run `await wait(500)`. Unfortunately
|
||||
* this is needed as the act of collecting functions relies on the periodic
|
||||
* sampling of the threads. See:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1529053
|
||||
*
|
||||
* @param {number} time
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function wait(time) {
|
||||
return new Promise(resolve => {
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payloads of a type recursively, including from all subprocesses.
|
||||
*
|
||||
* @param {Object} profile The gecko profile.
|
||||
* @param {string} type The marker payload type, e.g. "DiskIO".
|
||||
* @param {Array} payloadTarget The recursive list of payloads.
|
||||
* @return {Array} The final payloads.
|
||||
*/
|
||||
function getPayloadsOfTypeFromAllThreads(profile, type, payloadTarget = []) {
|
||||
for (const { markers } of profile.threads) {
|
||||
for (const markerTuple of markers.data) {
|
||||
const payload = markerTuple[markers.schema.data];
|
||||
if (payload && payload.type === type) {
|
||||
payloadTarget.push(payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const subProcess of profile.processes) {
|
||||
getPayloadsOfTypeFromAllThreads(subProcess, type, payloadTarget);
|
||||
}
|
||||
|
||||
return payloadTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payloads of a type from a single thread.
|
||||
*
|
||||
* @param {Object} thread The thread from a profile.
|
||||
* @param {string} type The marker payload type, e.g. "DiskIO".
|
||||
* @return {Array} The payloads.
|
||||
*/
|
||||
function getPayloadsOfType(thread, type) {
|
||||
const { markers } = thread;
|
||||
const results = [];
|
||||
for (const markerTuple of markers.data) {
|
||||
const payload = markerTuple[markers.schema.data];
|
||||
if (payload && payload.type === type) {
|
||||
results.push(payload);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* It can be helpful to force the profiler to collect a JavaScript sample. This
|
||||
* function spins on a while loop until at least one more sample is collected.
|
||||
*
|
||||
* @return {number} The index of the collected sample.
|
||||
*/
|
||||
function captureAtLeastOneJsSample() {
|
||||
function getProfileSampleCount() {
|
||||
const profile = Services.profiler.getProfileData();
|
||||
return profile.threads[0].samples.data.length;
|
||||
}
|
||||
|
||||
const sampleCount = getProfileSampleCount();
|
||||
// Create an infinite loop until a sample has been collected.
|
||||
while (true) {
|
||||
if (sampleCount < getProfileSampleCount()) {
|
||||
return sampleCount;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,52 +2,26 @@
|
||||
* 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/. */
|
||||
|
||||
/* import-globals-from ../shared-head.js */
|
||||
|
||||
// This Services declaration may shadow another from head.js, so define it as
|
||||
// a var rather than a const.
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { AppConstants } = ChromeUtils.import(
|
||||
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
var { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
/**
|
||||
* Get the payloads of a type recursively, including from all subprocesses.
|
||||
*
|
||||
* @param {Object} profile The gecko profile.
|
||||
* @param {string} type The marker payload type, e.g. "DiskIO".
|
||||
* @param {Array} payloadTarget The recursive list of payloads.
|
||||
* @return {Array} The final payloads.
|
||||
*/
|
||||
function getAllPayloadsOfType(profile, type, payloadTarget = []) {
|
||||
for (const { markers } of profile.threads) {
|
||||
for (const markerTuple of markers.data) {
|
||||
const payload = markerTuple[markers.schema.data];
|
||||
if (payload && payload.type === type) {
|
||||
payloadTarget.push(payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const subProcess of profile.processes) {
|
||||
getAllPayloadsOfType(subProcess, type, payloadTarget);
|
||||
}
|
||||
|
||||
return payloadTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper function be able to run `await wait(500)`. Unfortunately
|
||||
* this is needed as the act of collecting functions relies on the periodic
|
||||
* sampling of the threads. See:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1529053
|
||||
*
|
||||
* @param {number} time
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function wait(time) {
|
||||
return new Promise(resolve => {
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
// Load the shared head
|
||||
const sharedHead = do_get_file("shared-head.js", false);
|
||||
if (!sharedHead) {
|
||||
throw new Error("Could not load the shared head.");
|
||||
}
|
||||
Services.scriptloader.loadSubScript(
|
||||
Services.io.newFileURI(sharedHead).spec,
|
||||
this
|
||||
);
|
||||
|
||||
/**
|
||||
* This function takes a thread, and a sample tuple from the "data" array, and
|
||||
@ -81,28 +55,6 @@ function getInflatedStackLocations(thread, sample) {
|
||||
return locations.reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* It can be helpful to deterministically do at least one more profile sample.
|
||||
* Sampling is done based on a timer. This function spins on a while loop until
|
||||
* at least one more sample is collected.
|
||||
*
|
||||
* @return {number} The index of the collected sample.
|
||||
*/
|
||||
function doAtLeastOnePeriodicSample() {
|
||||
function getProfileSampleCount() {
|
||||
const profile = Services.profiler.getProfileData();
|
||||
return profile.threads[0].samples.data.length;
|
||||
}
|
||||
|
||||
const sampleCount = getProfileSampleCount();
|
||||
// Create an infinite loop until a sample has been collected.
|
||||
while (true) {
|
||||
if (sampleCount < getProfileSampleCount()) {
|
||||
return sampleCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This utility matches up stacks to see if they contain a certain sequence of
|
||||
* stack frames. A correctly functioning profiler will have a certain sequence
|
@ -17,7 +17,7 @@ add_task(async () => {
|
||||
Services.profiler.StartProfiler(entries, interval, features, threads);
|
||||
|
||||
// Call the following to get a nice stack in the profiler:
|
||||
// functionA -> functionB -> functionC -> doAtLeastOnePeriodicSample
|
||||
// functionA -> functionB -> functionC -> captureAtLeastOneJsSample
|
||||
const sampleIndex = await functionA();
|
||||
|
||||
const profile = await Services.profiler.getProfileDataAsync();
|
||||
@ -59,5 +59,5 @@ function functionB() {
|
||||
}
|
||||
|
||||
async function functionC() {
|
||||
return doAtLeastOnePeriodicSample();
|
||||
return captureAtLeastOneJsSample();
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ async function startProfilerAndgetFileIOPayloads(features, filename) {
|
||||
|
||||
const profile = await Services.profiler.getProfileDataAsync();
|
||||
Services.profiler.StopProfiler();
|
||||
return getAllPayloadsOfType(profile, "FileIO");
|
||||
return getPayloadsOfTypeFromAllThreads(profile, "FileIO");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,7 @@ add_task(async () => {
|
||||
const features = ["stackwalk"];
|
||||
|
||||
Services.profiler.StartProfiler(entries, interval, features, threads);
|
||||
const sampleIndex = await doAtLeastOnePeriodicSample();
|
||||
const sampleIndex = await captureAtLeastOneJsSample();
|
||||
|
||||
const profile = await Services.profiler.getProfileDataAsync();
|
||||
const [thread] = profile.threads;
|
||||
|
@ -17,7 +17,7 @@ add_task(async () => {
|
||||
Services.profiler.StartProfiler(entries, interval, features, threads);
|
||||
|
||||
// Call the following to get a nice stack in the profiler:
|
||||
// functionA -> functionB -> functionC -> doAtLeastOnePeriodicSample
|
||||
// functionA -> functionB -> functionC
|
||||
const sampleIndex = await functionA();
|
||||
|
||||
const profile = await Services.profiler.getProfileDataAsync();
|
||||
@ -71,5 +71,5 @@ function functionB() {
|
||||
}
|
||||
|
||||
async function functionC() {
|
||||
return doAtLeastOnePeriodicSample();
|
||||
return captureAtLeastOneJsSample();
|
||||
}
|
||||
|
@ -49,5 +49,5 @@ function doSyncWork(milliseconds) {
|
||||
|
||||
function functionA() {
|
||||
doSyncWork(100);
|
||||
doAtLeastOnePeriodicSample();
|
||||
captureAtLeastOneJsSample();
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
[DEFAULT]
|
||||
head = head_profiler.js
|
||||
head = head.js
|
||||
support-files =
|
||||
../shared-head.js
|
||||
skip-if = toolkit == 'android'
|
||||
|
||||
[test_active_configuration.js]
|
||||
|
Loading…
Reference in New Issue
Block a user