mirror of
https://github.com/classilla/tenfourfox.git
synced 2026-01-26 09:16:38 +00:00
200 lines
6.6 KiB
JavaScript
200 lines
6.6 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
/**
|
|
* Unit test for `createTierGraphDataFromFrameNode` function.
|
|
*/
|
|
|
|
function run_test() {
|
|
run_next_test();
|
|
}
|
|
|
|
const SAMPLE_COUNT = 1000;
|
|
const RESOLUTION = 50;
|
|
const TIME_PER_SAMPLE = 5;
|
|
|
|
// Offset needed since ThreadNode requires the first sample to be strictly
|
|
// greater than its start time. This lets us still have pretty numbers
|
|
// in this test to keep it (more) simple, which it sorely needs.
|
|
const TIME_OFFSET = 5;
|
|
|
|
add_task(function test() {
|
|
let { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
|
|
let { createTierGraphDataFromFrameNode } = require("devtools/client/performance/modules/logic/jit");
|
|
|
|
// Select the second half of the set of samples
|
|
let startTime = (SAMPLE_COUNT / 2 * TIME_PER_SAMPLE) - TIME_OFFSET;
|
|
let endTime = (SAMPLE_COUNT * TIME_PER_SAMPLE) - TIME_OFFSET;
|
|
let invertTree = true;
|
|
|
|
let root = new ThreadNode(gThread, { invertTree, startTime, endTime });
|
|
|
|
equal(root.samples, SAMPLE_COUNT / 2, "root has correct amount of samples");
|
|
equal(root.sampleTimes.length, SAMPLE_COUNT / 2, "root has correct amount of sample times");
|
|
// Add time offset since the first sample begins TIME_OFFSET after startTime
|
|
equal(root.sampleTimes[0], startTime + TIME_OFFSET, "root recorded first sample time in scope");
|
|
equal(root.sampleTimes[root.sampleTimes.length - 1], endTime, "root recorded last sample time in scope");
|
|
|
|
let frame = getFrameNodePath(root, "X");
|
|
let data = createTierGraphDataFromFrameNode(frame, root.sampleTimes, (endTime-startTime)/RESOLUTION);
|
|
|
|
let TIME_PER_WINDOW = SAMPLE_COUNT / 2 / RESOLUTION * TIME_PER_SAMPLE;
|
|
|
|
// Filter out the dupes created with the same delta so the graph
|
|
// can render correctly.
|
|
let filteredData = [];
|
|
for (let i = 0; i < data.length; i++) {
|
|
if (!i || data[i].delta !== data[i-1].delta) {
|
|
filteredData.push(data[i]);
|
|
}
|
|
}
|
|
data = filteredData;
|
|
|
|
for (let i = 0; i < 11; i++) {
|
|
equal(data[i].delta, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "first window has correct x");
|
|
equal(data[i].values[0], 0.2, "first window has 2 frames in interpreter");
|
|
equal(data[i].values[1], 0.2, "first window has 2 frames in baseline");
|
|
equal(data[i].values[2], 0.2, "first window has 2 frames in ion");
|
|
}
|
|
// Start on 11, since i===10 is where the values change, and the new value (0,0,0)
|
|
// is removed in `filteredData`
|
|
for (let i = 11; i < 20; i++) {
|
|
equal(data[i].delta, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "second window has correct x");
|
|
equal(data[i].values[0], 0, "second window observed no optimizations");
|
|
equal(data[i].values[1], 0, "second window observed no optimizations");
|
|
equal(data[i].values[2], 0, "second window observed no optimizations");
|
|
}
|
|
// Start on 21, since i===20 is where the values change, and the new value (0.3,0,0)
|
|
// is removed in `filteredData`
|
|
for (let i = 21; i < 30; i++) {
|
|
equal(data[i].delta, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "third window has correct x");
|
|
equal(data[i].values[0], 0.3, "third window has 3 frames in interpreter");
|
|
equal(data[i].values[1], 0, "third window has 0 frames in baseline");
|
|
equal(data[i].values[2], 0, "third window has 0 frames in ion");
|
|
}
|
|
});
|
|
|
|
var gUniqueStacks = new RecordingUtils.UniqueStacks();
|
|
|
|
function uniqStr(s) {
|
|
return gUniqueStacks.getOrAddStringIndex(s);
|
|
}
|
|
|
|
const TIER_PATTERNS = [
|
|
// 0-99
|
|
["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
|
|
// 100-199
|
|
["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
|
|
// 200-299
|
|
["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
|
|
// 300-399
|
|
["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
|
|
// 400-499
|
|
["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
|
|
|
|
// 500-599
|
|
// Test current frames in all opts
|
|
["A", "A", "A", "A", "X_1", "X_2", "X_1", "X_2", "X_0", "X_0"],
|
|
|
|
// 600-699
|
|
// Nothing for current frame
|
|
["A", "B", "A", "B", "A", "B", "A", "B", "A", "B"],
|
|
|
|
// 700-799
|
|
// A few frames where the frame is not the leaf node
|
|
["X_2 -> Y", "X_2 -> Y", "X_2 -> Y", "X_0", "X_0", "X_0", "A", "A", "A", "A"],
|
|
|
|
// 800-899
|
|
["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
|
|
// 900-999
|
|
["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
|
|
];
|
|
|
|
function createSample (i, frames) {
|
|
let sample = {};
|
|
sample.time = i * TIME_PER_SAMPLE;
|
|
sample.frames = [{ location: "(root)" }];
|
|
if (i === 0) {
|
|
return sample;
|
|
}
|
|
if (frames) {
|
|
frames.split(" -> ").forEach(frame => sample.frames.push({ location: frame }));
|
|
}
|
|
return sample;
|
|
}
|
|
|
|
var SAMPLES = (function () {
|
|
let samples = [];
|
|
|
|
for (let i = 0; i < SAMPLE_COUNT;) {
|
|
let pattern = TIER_PATTERNS[Math.floor(i/100)];
|
|
for (let j = 0; j < pattern.length; j++) {
|
|
samples.push(createSample(i+j, pattern[j]));
|
|
}
|
|
i += 10;
|
|
}
|
|
|
|
return samples;
|
|
})();
|
|
|
|
var gThread = RecordingUtils.deflateThread({ samples: SAMPLES, markers: [] }, gUniqueStacks);
|
|
|
|
var gRawSite1 = {
|
|
line: 12,
|
|
column: 2,
|
|
types: [{
|
|
mirType: uniqStr("Object"),
|
|
site: uniqStr("B (http://foo/bar:10)"),
|
|
typeset: [{
|
|
keyedBy: uniqStr("constructor"),
|
|
name: uniqStr("Foo"),
|
|
location: uniqStr("B (http://foo/bar:10)")
|
|
}, {
|
|
keyedBy: uniqStr("primitive"),
|
|
location: uniqStr("self-hosted")
|
|
}]
|
|
}],
|
|
attempts: {
|
|
schema: {
|
|
outcome: 0,
|
|
strategy: 1
|
|
},
|
|
data: [
|
|
[uniqStr("Failure1"), uniqStr("SomeGetter1")],
|
|
[uniqStr("Failure2"), uniqStr("SomeGetter2")],
|
|
[uniqStr("Inlined"), uniqStr("SomeGetter3")]
|
|
]
|
|
}
|
|
};
|
|
|
|
function serialize (x) {
|
|
return JSON.parse(JSON.stringify(x));
|
|
}
|
|
|
|
gThread.frameTable.data.forEach((frame) => {
|
|
const LOCATION_SLOT = gThread.frameTable.schema.location;
|
|
const OPTIMIZATIONS_SLOT = gThread.frameTable.schema.optimizations;
|
|
const IMPLEMENTATION_SLOT = gThread.frameTable.schema.implementation;
|
|
|
|
let l = gThread.stringTable[frame[LOCATION_SLOT]];
|
|
switch (l) {
|
|
// Rename some of the location sites so we can register different
|
|
// frames with different opt sites
|
|
case "X_0":
|
|
frame[LOCATION_SLOT] = uniqStr("X");
|
|
frame[OPTIMIZATIONS_SLOT] = serialize(gRawSite1);
|
|
frame[IMPLEMENTATION_SLOT] = null;
|
|
break;
|
|
case "X_1":
|
|
frame[LOCATION_SLOT] = uniqStr("X");
|
|
frame[OPTIMIZATIONS_SLOT] = serialize(gRawSite1);
|
|
frame[IMPLEMENTATION_SLOT] = uniqStr("baseline");
|
|
break;
|
|
case "X_2":
|
|
frame[LOCATION_SLOT] = uniqStr("X");
|
|
frame[OPTIMIZATIONS_SLOT] = serialize(gRawSite1);
|
|
frame[IMPLEMENTATION_SLOT] = uniqStr("ion");
|
|
break;
|
|
}
|
|
});
|