mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
949d7a9302
## Summary - update workspace test dependencies to Vitest 5.0.0 - pin Vitest and related tooling to Vite 8.2.2 - migrate removed sequential and benchmark APIs - update the pnpm lockfile
213 lines
7.1 KiB
JavaScript
213 lines
7.1 KiB
JavaScript
import { writeFile } from "node:fs/promises";
|
|
import { join as pathJoin } from "node:path";
|
|
import { describe, test } from "vitest";
|
|
import { parseRawSync } from "./src-js/bindings.js";
|
|
import { parse as parseAsync, parseSync } from "./src-js/index.js";
|
|
|
|
// Internals
|
|
import { DATA_POINTER_POS_32, PROGRAM_OFFSET } from "./src-js/generated/constants.js";
|
|
import { deserialize as deserializeJS } from "./src-js/generated/deserialize/js.js";
|
|
import { deserialize as deserializeTS } from "./src-js/generated/deserialize/ts.js";
|
|
import { walkProgram } from "./src-js/generated/lazy/walk.js";
|
|
import { isJsAst, prepareRaw, returnBufferToCache } from "./src-js/raw-transfer/common.js";
|
|
import { TOKEN } from "./src-js/raw-transfer/lazy-common.js";
|
|
import { getVisitorsArr, Visitor } from "./src-js/raw-transfer/visitor.js";
|
|
|
|
// Same fixtures as used in Rust parser benchmarks
|
|
let fixtureUrls = [
|
|
"https://cdn.jsdelivr.net/gh/microsoft/TypeScript@v5.3.3/src/compiler/checker.ts",
|
|
"https://cdn.jsdelivr.net/gh/excalidraw/excalidraw@f6d85bc80fe328e8f472636eb0d541f7bb891aa0/packages/excalidraw/components/App.tsx",
|
|
"https://cdn.jsdelivr.net/gh/oxc-project/benchmark-files@cd3bc3d431452b640f5dfcabbc22a8d8a388f393/RadixUIAdoptionSection.jsx",
|
|
"https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.269/build/pdf.mjs",
|
|
"https://cdn.jsdelivr.net/npm/antd@4.16.1/dist/antd.js",
|
|
];
|
|
|
|
// For sharding in CI - specify single fixture to run benchmarks on
|
|
let testStandard = test,
|
|
testRaw = test;
|
|
let shard = process.env.SHARD;
|
|
if (shard) {
|
|
shard *= 1;
|
|
if (shard % 2 === 0) {
|
|
testRaw = test.skip;
|
|
} else {
|
|
testStandard = test.skip;
|
|
shard--;
|
|
}
|
|
fixtureUrls = [fixtureUrls[shard / 2]];
|
|
}
|
|
|
|
// Same directory as Rust benchmarks use for downloaded files
|
|
// to avoid re-downloading if Rust benchmarks already downloaded
|
|
const cacheDirPath = pathJoin(import.meta.dirname, "../../target");
|
|
|
|
// Load fixtures
|
|
const fixtures = await Promise.all(
|
|
fixtureUrls.map(async (url) => {
|
|
const filename = url.split("/").at(-1),
|
|
path = pathJoin(cacheDirPath, filename);
|
|
|
|
let code;
|
|
try {
|
|
code = await readFile(path, "utf8");
|
|
} catch {
|
|
const res = await fetch(url);
|
|
code = await res.text();
|
|
await writeFile(path, code);
|
|
}
|
|
|
|
return { filename, code };
|
|
}),
|
|
);
|
|
|
|
const defineBenchmark = (testFunction, name, benchmarkFunction) => {
|
|
testFunction(name, async ({ bench }) => {
|
|
await bench(name, benchmarkFunction).run();
|
|
});
|
|
};
|
|
|
|
// Run benchmarks
|
|
for (const { filename, code } of fixtures) {
|
|
// oxlint-disable-next-line jest/valid-title
|
|
describe(filename, () => {
|
|
defineBenchmark(testStandard, "parser_napi", () => {
|
|
const ret = parseSync(filename, code);
|
|
// Read returned object's properties to execute getters which deserialize
|
|
// oxlint-disable-next-line no-unused-vars
|
|
const { program, comments, module, errors } = ret;
|
|
});
|
|
|
|
defineBenchmark(testRaw, "parser_napi_raw", () => {
|
|
const ret = parseSync(filename, code, { experimentalRawTransfer: true });
|
|
// Read returned object's properties to execute getters
|
|
// oxlint-disable-next-line no-unused-vars
|
|
const { program, comments, module, errors } = ret;
|
|
});
|
|
|
|
defineBenchmark(testStandard, "parser_napi_async", async () => {
|
|
const ret = await parseAsync(filename, code);
|
|
// Read returned object's properties to execute getters which deserialize
|
|
// oxlint-disable-next-line no-unused-vars
|
|
const { program, comments, module, errors } = ret;
|
|
});
|
|
|
|
defineBenchmark(testRaw, "parser_napi_async_raw", async () => {
|
|
const ret = await parseAsync(filename, code, { experimentalRawTransfer: true });
|
|
// Read returned object's properties to execute getters
|
|
// oxlint-disable-next-line no-unused-vars
|
|
const { program, comments, module, errors } = ret;
|
|
});
|
|
|
|
defineBenchmark(testRaw, "parser_napi_raw_no_deser", () => {
|
|
const { buffer, sourceByteLen } = prepareRaw(code);
|
|
parseRawSync(filename, buffer, sourceByteLen, {});
|
|
returnBufferToCache(buffer);
|
|
});
|
|
|
|
// Prepare buffer but don't deserialize
|
|
const { buffer, sourceByteLen } = prepareRaw(code);
|
|
parseRawSync(filename, buffer, sourceByteLen, {});
|
|
const deserialize = isJsAst(buffer) ? deserializeJS : deserializeTS;
|
|
|
|
defineBenchmark(testRaw, "parser_napi_raw_deser_only", () => {
|
|
deserialize(buffer, code, sourceByteLen, true);
|
|
});
|
|
|
|
// oxlint-disable-next-line no-unused-vars
|
|
let debuggerCount = 0;
|
|
const debuggerVisitor = new Visitor({
|
|
DebuggerStatement(_debuggerStmt) {
|
|
debuggerCount++;
|
|
},
|
|
});
|
|
|
|
// oxlint-disable-next-line no-unused-vars
|
|
let identCount = 0;
|
|
const identVisitor = new Visitor({
|
|
BindingIdentifier(_ident) {
|
|
identCount++;
|
|
},
|
|
IdentifierReference(_ident) {
|
|
identCount++;
|
|
},
|
|
IdentifierName(_ident) {
|
|
identCount++;
|
|
},
|
|
});
|
|
|
|
// These 4 currently not working, due to 2 instances of `Visitor` getting loaded via CJS and ESM.
|
|
// TODO: Fix it.
|
|
/*
|
|
defineBenchmark(testRaw, 'parser_napi_raw_lazy_visit(debugger)', () => {
|
|
const { visit, dispose } = parseSync(filename, code, { experimentalLazy: true });
|
|
debuggerCount = 0;
|
|
visit(debuggerVisitor);
|
|
dispose();
|
|
});
|
|
|
|
defineBenchmark(testRaw, 'parser_napi_raw_lazy_visit(ident)', () => {
|
|
const { visit, dispose } = parseSync(filename, code, { experimentalLazy: true });
|
|
identCount = 0;
|
|
visit(identVisitor);
|
|
dispose();
|
|
});
|
|
|
|
defineBenchmark(testRaw, 'parser_napi_raw_lazy_visitor(debugger)', () => {
|
|
const { visit, dispose } = parseSync(filename, code, { experimentalLazy: true });
|
|
debuggerCount = 0;
|
|
const debuggerVisitor = new Visitor({
|
|
DebuggerStatement(_debuggerStmt) {
|
|
debuggerCount++;
|
|
},
|
|
});
|
|
visit(debuggerVisitor);
|
|
dispose();
|
|
});
|
|
|
|
defineBenchmark(testRaw, 'parser_napi_raw_lazy_visitor(ident)', () => {
|
|
const { visit, dispose } = parseSync(filename, code, { experimentalLazy: true });
|
|
identCount = 0;
|
|
const identVisitor = new Visitor({
|
|
BindingIdentifier(_ident) {
|
|
identCount++;
|
|
},
|
|
IdentifierReference(_ident) {
|
|
identCount++;
|
|
},
|
|
IdentifierName(_ident) {
|
|
identCount++;
|
|
},
|
|
});
|
|
visit(identVisitor);
|
|
dispose();
|
|
});
|
|
*/
|
|
|
|
const debuggerVisitorsArr = getVisitorsArr(debuggerVisitor);
|
|
const identVisitorsArr = getVisitorsArr(identVisitor);
|
|
|
|
const ast = {
|
|
buffer,
|
|
sourceText: code,
|
|
sourceByteLen,
|
|
sourceIsAscii: code.length === sourceByteLen,
|
|
nodes: null, // Initialized in bench functions
|
|
token: TOKEN,
|
|
};
|
|
|
|
const programPos = buffer.int32[DATA_POINTER_POS_32] + PROGRAM_OFFSET;
|
|
|
|
defineBenchmark(testRaw, "parser_napi_raw_lazy_visit_only(debugger)", () => {
|
|
ast.nodes = new Map();
|
|
debuggerCount = 0;
|
|
walkProgram(programPos, ast, debuggerVisitorsArr);
|
|
});
|
|
|
|
defineBenchmark(testRaw, "parser_napi_raw_lazy_visit_only(ident)", () => {
|
|
ast.nodes = new Map();
|
|
identCount = 0;
|
|
walkProgram(programPos, ast, identVisitorsArr);
|
|
});
|
|
});
|
|
}
|