119 lines
3.7 KiB
JavaScript
119 lines
3.7 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
// Test that the HeapAnalyses{Client,Worker} can send SavedFrame stacks from
|
|
// by-allocation-stack reports from the worker.
|
|
|
|
function run_test() {
|
|
run_next_test();
|
|
}
|
|
|
|
add_task(function* test() {
|
|
const client = new HeapAnalysesClient();
|
|
|
|
// Track some allocation stacks.
|
|
|
|
const g = newGlobal();
|
|
const dbg = new Debugger(g);
|
|
g.eval(` // 1
|
|
this.log = []; // 2
|
|
function f() { this.log.push(allocationMarker()); } // 3
|
|
function g() { this.log.push(allocationMarker()); } // 4
|
|
function h() { this.log.push(allocationMarker()); } // 5
|
|
`); // 6
|
|
|
|
// Create one allocationMarker with tracking turned off,
|
|
// so it will have no associated stack.
|
|
g.f();
|
|
|
|
dbg.memory.allocationSamplingProbability = 1;
|
|
|
|
for (let [func, n] of [ [g.f, 20],
|
|
[g.g, 10],
|
|
[g.h, 5] ]) {
|
|
for (let i = 0; i < n; i++) {
|
|
dbg.memory.trackingAllocationSites = true;
|
|
// All allocations of allocationMarker occur with this line as the oldest
|
|
// stack frame.
|
|
func();
|
|
dbg.memory.trackingAllocationSites = false;
|
|
}
|
|
}
|
|
|
|
// Take a heap snapshot.
|
|
|
|
const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg });
|
|
yield client.readHeapSnapshot(snapshotFilePath);
|
|
ok(true, "Should have read the heap snapshot");
|
|
|
|
// Run a census broken down by class name -> allocation stack so we can grab
|
|
// only the AllocationMarker objects we have complete control over.
|
|
|
|
const { report } = yield client.takeCensus(snapshotFilePath, {
|
|
breakdown: { by: "objectClass",
|
|
then: { by: "allocationStack",
|
|
then: { by: "count",
|
|
bytes: true,
|
|
count: true
|
|
},
|
|
noStack: { by: "count",
|
|
bytes: true,
|
|
count: true
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Test the generated report.
|
|
|
|
ok(report, "Should get a report");
|
|
|
|
const map = report.AllocationMarker;
|
|
ok(map, "Should get AllocationMarkers in the report.");
|
|
// From a module with a different global, and therefore a different Map
|
|
// constructor, so we can't use instanceof.
|
|
equal(map.__proto__.constructor.name, "Map");
|
|
|
|
equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)");
|
|
|
|
// Gather the stacks we are expecting to appear as keys, and
|
|
// check that there are no unexpected keys.
|
|
let stacks = {};
|
|
|
|
map.forEach((v, k) => {
|
|
if (k === "noStack") {
|
|
// No need to save this key.
|
|
} else if (k.functionDisplayName === "f" &&
|
|
k.parent.functionDisplayName === "test") {
|
|
stacks.f = k;
|
|
} else if (k.functionDisplayName === "g" &&
|
|
k.parent.functionDisplayName === "test") {
|
|
stacks.g = k;
|
|
} else if (k.functionDisplayName === "h" &&
|
|
k.parent.functionDisplayName === "test") {
|
|
stacks.h = k;
|
|
} else {
|
|
dumpn("Unexpected allocation stack:");
|
|
k.toString().split(/\n/g).forEach(s => dumpn(s));
|
|
ok(false);
|
|
}
|
|
});
|
|
|
|
ok(map.get("noStack"));
|
|
equal(map.get("noStack").count, 1);
|
|
|
|
ok(stacks.f);
|
|
ok(map.get(stacks.f));
|
|
equal(map.get(stacks.f).count, 20);
|
|
|
|
ok(stacks.g);
|
|
ok(map.get(stacks.g));
|
|
equal(map.get(stacks.g).count, 10);
|
|
|
|
ok(stacks.h);
|
|
ok(map.get(stacks.h));
|
|
equal(map.get(stacks.h).count, 5);
|
|
|
|
client.destroy();
|
|
});
|