Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* 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/. */
/**
* Test that sourceIndexes are collected properly in profiles.
*/
add_task(async function test_profile_js_sources() {
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
const url = BASE_URL + "simple.html";
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
// Start profiling to capture JS sources
await ProfilerTestUtils.startProfiler({ features: ["js", "jssources"] });
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
// Execute some JavaScript that will create frames with sourceIndexes
await SpecialPowers.spawn(contentBrowser, [], () => {
content.window.eval(`
function testFunction() {
// Simple function to generate JIT frames with 1ms busy loop
const start = performance.now();
let result = 0;
while (performance.now() - start < 1) {
for (let i = 0; i < 1000; i++) {
result += Math.random();
}
}
return result;
}
// Call the function multiple times to trigger JIT compilation
for (let i = 0; i < 100; i++) {
testFunction();
}
`);
});
const { contentThread } =
await waitSamplingAndStopProfilerAndGetThreads(contentPid);
// Check that we have frames with sourceIndexes in location strings
const { frameTable } = contentThread;
const FRAME_LOCATION_SLOT = frameTable.schema.location;
// Find frames that have sourceIndexes in their location strings
const framesWithSourceIndexes = [];
for (const frame of frameTable.data) {
const location = contentThread.stringTable[frame[FRAME_LOCATION_SLOT]];
if (location && location.match(/\[\d+\]$/)) {
framesWithSourceIndexes.push({ frame, location });
}
}
Assert.greater(
framesWithSourceIndexes.length,
0,
"Found frames with sourceIndexes in location strings"
);
// Verify that sourceIndexes are valid numbers
for (const { location } of framesWithSourceIndexes) {
const sourceIndexMatch = location.match(/\[(\d+)\]$/);
const sourceIndex = parseInt(sourceIndexMatch[1]);
Assert.greaterOrEqual(
sourceIndex,
0,
`SourceIndex ${sourceIndex} is a valid number`
);
}
info(`Found ${framesWithSourceIndexes.length} frames with sourceIndexes`);
// Check if testFunction frames have sourceIndexes
let testFunctionFrames = 0;
for (const frame of frameTable.data) {
const location = contentThread.stringTable[frame[FRAME_LOCATION_SLOT]];
if (location && location.includes("testFunction")) {
testFunctionFrames++;
if (!location.match(/\[\d+\]$/)) {
Assert.ok(false, `Failed to find sourceIndex for ${location}`);
}
}
}
Assert.greater(
testFunctionFrames,
0,
"At least some testFunction frames should have sourceIndexes"
);
});
});
/**
* Test that JS tracer frames include sourceIndexes when tracing is enabled.
*/
add_task(async function test_profile_js_sources_with_tracing() {
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
const url = BASE_URL + "tracing.html";
await BrowserTestUtils.withNewTab("about:blank", async contentBrowser => {
// Start profiling with tracing to capture JS tracer frames
await ProfilerTestUtils.startProfiler({
features: ["tracing", "jssources"],
});
await BrowserTestUtils.startLoadingURIString(contentBrowser, url);
await BrowserTestUtils.browserLoaded(contentBrowser, false, url);
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
const { contentThread } = await stopProfilerNowAndGetThreads(contentPid);
// Check that tracer frames have sourceIndexes in location strings
const { frameTable } = contentThread;
const FRAME_LOCATION_SLOT = frameTable.schema.location;
// Look for our test functions from tracing.html with sourceIndexes
const tracingFramesWithSourceIndexes = [];
for (const frame of frameTable.data) {
const location = contentThread.stringTable[frame[FRAME_LOCATION_SLOT]];
if (
location &&
location.includes("tracing.html") &&
location.match(/\[\d+\]$/)
) {
tracingFramesWithSourceIndexes.push({ frame, location });
}
}
dump(tracingFramesWithSourceIndexes.map(a => a.location));
Assert.greater(
tracingFramesWithSourceIndexes.length,
0,
"Found tracing frames with sourceIndexes"
);
info(
`Found ${tracingFramesWithSourceIndexes.length} tracing frames with sourceIndexes`
);
});
});
/**
* Test that sourceIndexes work with eval.
*/
add_task(async function test_profile_js_sources_location_format() {
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
const url = BASE_URL + "simple.html";
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
await ProfilerTestUtils.startProfiler({ features: ["js", "jssources"] });
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
// Execute JavaScript with eval
await SpecialPowers.spawn(contentBrowser, [], () => {
content.window.eval(`
function sourceIndexTest() {
return 42;
}
sourceIndexTest();
`);
});
const { contentThread } =
await waitSamplingAndStopProfilerAndGetThreads(contentPid);
const { frameTable } = contentThread;
const FRAME_LOCATION_SLOT = frameTable.schema.location;
// Find frames with sourceIndex in their location strings
const framesWithSourceIndexes = [];
for (const frame of frameTable.data) {
const location = contentThread.stringTable[frame[FRAME_LOCATION_SLOT]];
if (location && location.match(/\[\d+\]$/)) {
framesWithSourceIndexes.push({ frame, location });
info(`Found sourceIndex in location: ${location}`);
}
}
Assert.greater(
framesWithSourceIndexes.length,
0,
"Found at least one frame location that includes sourceIndex in brackets"
);
});
});