blob: 63a1efe26d86edf67beaee08ffccfc658d8aec00 [file] [log] [blame]
load("shell-config.js");
load("startup-helper/StartupBenchmark.js");
load("JetStreamDriver.js");
function assertTrue(condition, message) {
if (!condition) {
throw new Error(message || "Assertion failed");
}
}
function assertFalse(condition, message) {
if (condition) {
throw new Error(message || "Assertion failed");
}
}
function assertEquals(actual, expected, message) {
if (actual !== expected) {
throw new Error(message || `Expected ${expected}, but got ${actual}`);
}
}
function assertThrows(message, func) {
let didThrow = false;
try {
func();
} catch (e) {
didThrow = true;
}
assertTrue(didThrow, message);
}
(function testTagsAreLowerCaseStrings() {
for (const benchmark of BENCHMARKS) {
benchmark.tags.forEach((tag) => {
assertTrue(typeof tag == "string");
assertTrue(tag == tag.toLowerCase());
});
}
})();
(function testTagsAll() {
for (const benchmark of BENCHMARKS) {
const tags = benchmark.tags;
assertTrue(tags instanceof Set);
assertTrue(tags.size > 0);
assertTrue(tags.has("all"));
assertFalse(tags.has("All"));
assertTrue(tags.has("default") ^ tags.has("disabled"));
}
})();
(function testDriverBenchmarksOrder() {
const benchmarks = findBenchmarksByTag("all");
const driver = new Driver(benchmarks);
assertEquals(driver.benchmarks.length, BENCHMARKS.length);
const names = driver.benchmarks
.map((b) => b.name.toLowerCase())
.sort()
.reverse();
for (let i = 0; i < names.length; i++) {
assertEquals(driver.benchmarks[i].name.toLowerCase(), names[i]);
}
})();
(function testEnableByTag() {
const driverA = new Driver(findBenchmarksByTag("Default"));
const driverB = new Driver(findBenchmarksByTag("default"));
assertTrue(driverA.benchmarks.length > 0);
assertEquals(driverA.benchmarks.length, driverB.benchmarks.length);
const enabledBenchmarkNames = new Set(
Array.from(driverA.benchmarks).map((b) => b.name)
);
for (const benchmark of BENCHMARKS) {
if (benchmark.tags.has("default"))
assertTrue(enabledBenchmarkNames.has(benchmark.name));
}
})();
(function testDriverEnableDuplicateAndSort() {
const benchmarks = [
...findBenchmarksByTag("wasm"),
...findBenchmarksByTag("wasm"),
];
assertTrue(benchmarks.length > 0);
const uniqueBenchmarks = new Set(benchmarks);
assertFalse(uniqueBenchmarks.size == benchmarks.length);
const driver = new Driver(benchmarks);
assertEquals(driver.benchmarks.length, uniqueBenchmarks.size);
})();
(function testBenchmarkSubScores() {
for (const benchmark of BENCHMARKS) {
const subScores = benchmark.subScores();
assertTrue(subScores instanceof Object);
assertTrue(Object.keys(subScores).length > 0);
for (const [name, value] of Object.entries(subScores)) {
assertTrue(typeof name == "string");
// "Score" can only be part of allScores().
assertFalse(name == "Score");
// Without running values should be either null (or 0 for GroupedBenchmark)
assertFalse(value);
}
}
})();
(function testBenchmarkAllScores() {
for (const benchmark of BENCHMARKS) {
const subScores = benchmark.subScores();
const allScores = benchmark.allScores();
assertTrue("Score" in allScores);
// All subScore items are part of allScores.
for (const name of Object.keys(subScores)) assertTrue(name in allScores);
}
})();
(function checkUtf16Sources() {
// Test that only explicitly UTF16-enabled benchmarks can have sources
// with non-8-byte characters.
const twoByteCharsRegex = /[^\x00-\xFF]/g;
const jsFileRegex = /\.(js|mjs)$/;
function checkFile(benchmarkName, file, type) {
if (!jsFileRegex.test(file))
return;
const content = read(file);
const match = content.match(twoByteCharsRegex);
if (!match)
return;
const uniqueMatches = Array.from(new Set(match));
const offendingChars = uniqueMatches.map(char => {
const hex = char.charCodeAt(0).toString(16).padStart(4, "0");
return `\n - \\u${hex}: '${char}'`;
}).join("");
throw new Error(
`Benchmark '${benchmarkName}' has two-byte characters in ${type} '${file}':\n` +
` Offending characters: ${offendingChars}`);
}
for (const benchmark of BENCHMARKS) {
if (benchmark.allowUtf16)
continue;
for (const file of benchmark.files) {
checkFile(benchmark.name, file, "file");
}
if (benchmark.plan.preload) {
for (const [name, file] of Object.entries(benchmark.plan.preload)) {
checkFile(benchmark.name, file, `preload.${name}`);
}
}
}
})();
function validateIterationSources(sources) {
for (const source of sources) {
assertTrue(typeof source == "string");
assertFalse(source.includes(CACHE_BUST_COMMENT));
}
}
(async function testStartupBenchmark() {
try {
JetStream.preload = { BUNDLE: "test-bundle.js" };
JetStream.getString = (file) => {
assertEquals(file, "test-bundle.js");
return `function test() {
${CACHE_BUST_COMMENT}
return 1;
}`;
};
await testStartupBenchmarkInnerTests();
} finally {
JetStream.preload = undefined;
JetStream.getString = undefined;
}
})();
async function testStartupBenchmarkInnerTests() {
const benchmark = new StartupBenchmark({
iterationCount: 12,
expectedCacheCommentCount: 1,
});
assertEquals(benchmark.iterationCount, 12);
assertEquals(benchmark.expectedCacheCommentCount, 1);
assertEquals(benchmark.iterationSourceCodes.length, 0);
assertEquals(benchmark.sourceCode, undefined);
assertEquals(benchmark.sourceHash, 0);
await benchmark.init();
assertEquals(benchmark.sourceHash, 177573);
assertEquals(benchmark.sourceCode.length, 68);
assertEquals(benchmark.iterationSourceCodes.length, 12);
assertEquals(new Set(benchmark.iterationSourceCodes).size, 12);
validateIterationSources(benchmark.iterationSourceCodes);
const noReuseBenchmark = new StartupBenchmark({
iterationCount: 12,
expectedCacheCommentCount: 1,
sourceCodeReuseCount: 0,
});
assertEquals(noReuseBenchmark.iterationSourceCodes.length, 0);
await noReuseBenchmark.init();
assertEquals(noReuseBenchmark.iterationSourceCodes.length, 12);
assertEquals(new Set(noReuseBenchmark.iterationSourceCodes).size, 1);
validateIterationSources(noReuseBenchmark.iterationSourceCodes);
const reuseBenchmark = new StartupBenchmark({
iterationCount: 12,
expectedCacheCommentCount: 1,
sourceCodeReuseCount: 3,
});
assertEquals(reuseBenchmark.iterationSourceCodes.length, 0);
await reuseBenchmark.init();
assertEquals(reuseBenchmark.iterationSourceCodes.length, 12);
assertEquals(new Set(reuseBenchmark.iterationSourceCodes).size, 4);
validateIterationSources(reuseBenchmark.iterationSourceCodes);
const reuseBenchmark2 = new StartupBenchmark({
iterationCount: 12,
expectedCacheCommentCount: 1,
sourceCodeReuseCount: 5,
});
assertEquals(reuseBenchmark2.iterationSourceCodes.length, 0);
await reuseBenchmark2.init();
assertEquals(reuseBenchmark2.iterationSourceCodes.length, 12);
assertEquals(new Set(reuseBenchmark2.iterationSourceCodes).size, 3);
validateIterationSources(reuseBenchmark2.iterationSourceCodes);
}
(function testStartupBenchmarkThrow() {
assertThrows(
"StartupBenchmark constructor should throw with no arguments.",
() => new StartupBenchmark()
);
assertThrows(
"StartupBenchmark constructor should throw with missing expectedCacheCommentCount.",
() => new StartupBenchmark({ iterationCount: 1 })
);
assertThrows(
"StartupBenchmark constructor should throw with missing iterationCount.",
() => new StartupBenchmark({ expectedCacheCommentCount: 1 })
);
assertThrows(
"StartupBenchmark constructor should throw with iterationCount=0.",
() => {
new StartupBenchmark({ iterationCount: 0, expectedCacheCommentCount: 1 });
}
);
assertThrows(
"StartupBenchmark constructor should throw with expectedCacheCommentCount=0.",
() => {
new StartupBenchmark({ iterationCount: 1, expectedCacheCommentCount: 0 });
}
);
})();