Files
tenfourfox/devtools/client/performance/test/unit/test_jit-graph-data.js
Cameron Kaiser c9b2922b70 hello FPR
2017-04-19 00:56:45 -07:00

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;
}
});