Source code

Revision control

Copy as Markdown

Other Tools

/* Any copyright is dedicated to the Public Domain.
"use strict";
const { ProfilerTestUtils } = ChromeUtils.importESModule(
);
/**
* Start the profiler, run `func`, stop the profiler, and get a collection of
* markers that were recorded while running `func`.
*
* @param {string} type The marker payload type, e.g. "Counter"
* @param {object} func The function that runs glean code to generate markers
* @returns {object} The markers generated during `func`, with the id field
* expanded using the string table
*/
async function runWithProfilerAndGetMarkers(type, func) {
await ProfilerTestUtils.startProfiler({
entries: 10000,
interval: 10,
features: ["nostacksampling"],
threads: ["GeckoMain"],
});
Assert.ok(Services.profiler.IsActive());
let startTime = Services.profiler.getElapsedTime();
await func();
let endTime = Services.profiler.getElapsedTime();
let profile = await ProfilerTestUtils.stopNowAndGetProfile();
// We assume that we only have one thread being profiled here.
Assert.equal(
profile.threads.length,
1,
"We should only be profiling one thread"
);
let thread = profile.threads[0];
// Exclude profiler setup and teardown, which can record unrelated IPC metrics.
let timeIndex = thread.markers.schema.startTime;
thread.markers.data = thread.markers.data.filter(
marker => marker[timeIndex] >= startTime && marker[timeIndex] <= endTime
);
let markers = ProfilerTestUtils.getPayloadsOfType(thread, type);
let stringTable = thread.stringTable;
// We expect that the id, or name, of a marker should be a unique string.
// Go through them and look up the values so that we can just write a string
// in the test, and not use a numerical id (which may not be stable!)
for (let marker of markers) {
marker.id = stringTable[marker.id];
if (marker.cat != undefined) {
marker.cat = stringTable[marker.cat];
}
if (marker.label != undefined) {
marker.label = stringTable[marker.label];
}
}
// Next, filter the markers so that we only return those generated by test
// metrics. We need to do this, as some metric types are used by other
// parts of Fx, which may be running during the test. As we cannot predict
// when they may occur, or what values they may hold, we can't write down
// a "gold" value in our tests to compare them to - so we need to remove
// them. Some notable existing examples include:
// - Memory distribution metrics, "performanceCloneDeserialize.<x>"
// - Custom distribution metrics (same as memory distribution)
// - Timing distribution metrics (for timing of performance
// clone/deserialise)
// - Counter metrics ("javascriptGc"), which caused intermittents in Bug
// 1943425
markers = markers.filter(marker => {
// Metric markers with names coming from JS all start with `testOnly`,
// `test_only` or `jog_`
let name =
marker.id.startsWith("testOnly") ||
marker.id.startsWith("test_only") ||
marker.id.startsWith("jog_");
// Marker categories all start with test or jog
let cat = false;
if (marker.cat != undefined) {
cat = marker.cat.startsWith("test") || marker.cat.startsWith("jog_");
}
// Ping markers are a little more varied, so we enumerate them
let ping = ["test-ping", "one-ping-only", "ride-along-ping"].includes(
marker.id
);
// Include child lookup failures, but not background timing accumulations
// (e.g. GC), which can also fail to resolve their metric names.
let error =
marker.id.startsWith("JOG") ||
(marker.type == "EventMetric" && marker.id == "id not found") ||
marker.id.endsWith(": LabeledBaseMetricIsNotDynamic") ||
(marker.id == "FOGMetricMapLookupFailed" && marker.timer_id != undefined);
return name || cat || ping || error;
});
// Return selected markers
return markers;
}