diff --git a/tools/bench/README.md b/tools/bench/README.md new file mode 100644 index 0000000000..78529d1063 --- /dev/null +++ b/tools/bench/README.md @@ -0,0 +1,33 @@ +## Re-bootstrapping + +Re-bootstrapping allows deno devs to bench/profile/test JS-side changes without +doing a full `cargo build --release --bin deno` which takes roughly ~4mn on M1s +more on other machines which significantly slows down iteration & +experimentation. + +## Example + +```js +import { benchSync, rebootstrap } from "./tools/bench/mod.js"; + +const bootstrap = rebootstrap([ + "webidl", + "console", + "url", + "web", + "fetch", +]); + +benchSync("resp_w_h", 1e6, () => + new bootstrap.fetch.Response("yolo", { + status: 200, + headers: { + server: "deno", + "content-type": "text/plain", + }, + })); +``` + +This code can then benched and profiled (using Chrome's DevTools) similar to +regular userland code and the original source files appear in the DevTools as +you would expect. diff --git a/tools/bench/mod.js b/tools/bench/mod.js new file mode 100644 index 0000000000..6858342813 --- /dev/null +++ b/tools/bench/mod.js @@ -0,0 +1,2 @@ +export * from "./rebench.js"; +export * from "./rebootstrap.js"; diff --git a/tools/bench/rebench.js b/tools/bench/rebench.js new file mode 100644 index 0000000000..bbc5a3c2f4 --- /dev/null +++ b/tools/bench/rebench.js @@ -0,0 +1,25 @@ +export function benchSync(name, n, innerLoop) { + const t1 = Date.now(); + for (let i = 0; i < n; i++) { + innerLoop(i); + } + const t2 = Date.now(); + console.log(benchStats(name, n, t1, t2)); +} + +export async function benchAsync(name, n, innerLoop) { + const t1 = Date.now(); + for (let i = 0; i < n; i++) { + await innerLoop(i); + } + const t2 = Date.now(); + console.log(benchStats(name, n, t1, t2)); +} + +function benchStats(name, n, t1, t2) { + const dt = (t2 - t1) / 1e3; + const r = n / dt; + const ns = Math.floor(dt / n * 1e9); + return `${name}:${" ".repeat(20 - name.length)}\t` + + `n = ${n}, dt = ${dt.toFixed(3)}s, r = ${r.toFixed(0)}/s, t = ${ns}ns/op`; +} diff --git a/tools/bench/rebootstrap.js b/tools/bench/rebootstrap.js new file mode 100644 index 0000000000..b85276ef3f --- /dev/null +++ b/tools/bench/rebootstrap.js @@ -0,0 +1,25 @@ +import { dirname, fromFileUrl, join } from "https://deno.land/std/path/mod.ts"; +import { expandGlobSync } from "https://deno.land/std/fs/mod.ts"; + +const ROOT_DIR = join(dirname(fromFileUrl(import.meta.url)), "..", ".."); + +export function rebootstrap(exts) { + [ + "core/00_primordials.js", + ...exts.map((e) => `ext/${e}/*.js`), + ] + .map((pattern) => join(ROOT_DIR, pattern)) + .map((pattern) => [...expandGlobSync(pattern)]) + .flat() + .map((entry) => entry.path) + .forEach((file) => { + Deno.core.evalContext(Deno.readTextFileSync(file), file); + }); + const bootstrap = globalThis.__bootstrap; + delete globalThis.__bootstrap; + // Patch dispatchEvent so we don't crash when MainWorker exits via: + // `window.dispatchEvent(new Event('unload'))` + // which fails since symbols are mangled during rebootstrap + globalThis.dispatchEvent = () => {}; + return bootstrap; +}