Skip to content

Bench modules named on the command line - #32

Merged
kawanet merged 3 commits into
kawanet:mainfrom
kawanet-bot:feature/dynamic-adapter
Aug 31, 2026
Merged

Bench modules named on the command line#32
kawanet merged 3 commits into
kawanet:mainfrom
kawanet-bot:feature/dynamic-adapter

Conversation

@kawanet-bot

Copy link
Copy Markdown
Contributor

Comparing this package against itself — a published build, a branch build, the
working tree — used to mean copying a .mjs over dist/, running, and copying
it back. That mutates the tree, leaves a foreign build behind if the run is
interrupted, and puts each version in its own process, so the runner's
counterbalanced shuffle never sees them together.

Naming the files on the command line instead keeps every build in one rotation:

DURATION=500 SETS=5 node builder/bench.cli.ts \
  /tmp/built/0.10.7.mjs /tmp/built/74edcfc.mjs dist/sha256-uint8array.mjs
# node v24.19.0 DURATION=500 SETS=5 FILES=3
# string cccooooooooooooooo
# binary cccooooooooooooooo
...
|module|string|U8A|
|---|---|---|
|/tmp/built/0.10.7.mjs|245ms 🥈|183ms 🥈|
|/tmp/built/74edcfc.mjs|262ms|200ms|
|dist/sha256-uint8array.mjs|198ms 🥇|148ms 🥇|

Paths outrank TARGET and replace the comparison rather than filtering it, so
every cell measures a build of this package and only the code differs. The
header says FILES=n in place of TARGET=, since naming a target would be a
claim the run is not making.

One class per path

Each path builds a class of its own, for the same reason the benchmark closures
are built per adapter: a single class instantiated per path would share its
methods, and every module's createHash — along with the differently shaped
hashes it returns — would meet at the same call sites. The effect measures below
the noise at these input sizes, but the rule already applies a few lines above
and is free to keep.

Loading

Adapter gains a setup() hook, awaited once before any cell is built. A
module load is a cost of the import, not of a digest, so it stays outside every
timed window. The default does nothing, so the existing adapters are unchanged.

The adapter expects the documented createHash() entry point and says so if the
module lacks it. It is deliberately not a general adapter for arbitrary modules.
Correctness comes for free: the measured closures already assert each digest
against crypto, so a bad build fails before the timer starts.

update() is published one input shape at a time, so this file describes the
same function with the union it already accepts at run time, rather than
narrowing at every call site. That widens only this file's view — the package
keeps publishing the overloads it always has, and neither lib/ nor types/ is
touched.

Browsers

node:url joins node:assert and node:crypto in the alias lists of both
browser configs, pointing at a shim that throws rather than returning a
plausible URL — the CLI-only path never runs in a browser, and a fake result
would hide a broken split instead of reporting one. Both bundles build without
warnings and carry no reference to node:url beyond that shim's own comment.

Verified on Node v24.19.0 and Chromium 151: npm test green,
browser/tests.html 61 passes / 0 failures, and the failure modes behave — a
missing path, a module without createHash, and a module returning a wrong
digest.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@kawanet

kawanet commented Aug 31, 2026

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: f46df6a900

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The dynamic module loader currently uses pathToFileURL(path) directly, which throws on relative paths, making common CLI invocations fail.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Updates the benchmark runner so it can compare multiple builds of this package in a single rotation by naming module files on the command line, avoiding mutation of dist/ and keeping all variants in one counterbalanced shuffle.

Changes:

  • Add a CLI mode that benchmarks explicit module paths (paths override TARGET) and updates the run header to report FILES=n.
  • Introduce an Adapter.setup() hook (awaited once before measuring) and a dynamic adapter that loads a module-by-path and uses its documented createHash() export.
  • Add a browser shim + rollup aliases for node:url to keep browser bundles self-contained.
File summaries
File Description
test/utils/adapters.ts Adds Adapter.setup(), simplifies own adapter chaining, and introduces dynamicModule(path) to load benchmark targets from file paths.
builder/bench.cli.ts Accepts module paths from process.argv, preloads adapters via setup(), and switches header output to FILES= when paths are provided.
builder/rollup-test.config.ts Aliases node:url to a local shim for browser test bundling.
builder/rollup-bench.config.ts Aliases node:url to a local shim for browser benchmark bundling.
builder/node-url.shim.ts Adds a throwing browser stand-in for pathToFileURL.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/utils/adapters.ts Outdated
Comment on lines +286 to +287
override async setup(): Promise<void> {
const module = await import(pathToFileURL(path).href) as {createHash?: ICreateHash}
Comment thread builder/node-url.shim.ts Outdated
Comment on lines +5 to +7
export const pathToFileURL = (): never => {
throw new Error("pathToFileURL() not supported")
}
Comparing this package against itself — a published build, a branch, the
working tree — meant swapping dist/ in place between runs, which mutates
the tree and puts each build in its own process, out of reach of the
counterbalanced ordering. Naming the files instead keeps every build in
one rotation, each behind a class of its own so the compared builds do
not meet at shared call sites.

Co-authored-by: Claude <noreply@anthropic.com>
@kawanet-bot
kawanet-bot force-pushed the feature/dynamic-adapter branch from f46df6a to 2f7a53b Compare August 31, 2026 14:06
kawanet-bot and others added 2 commits August 31, 2026 23:08
Every argument is a module to import, so `-h` was resolved as a filename
and reported as a missing module. Print the invocation and the three
environment variables instead, and refuse anything else that leads with a
dash rather than trying to load it.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
@kawanet
kawanet requested a lite review from Copilot August 31, 2026 14:42
@kawanet

kawanet commented Aug 31, 2026

Copy link
Copy Markdown
Owner

@codex review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Relative module paths passed on the command line can be converted into incorrect root-based file URLs in dynamicModule(), causing imports to fail for valid paths like dist/....

Review details

Suppressed comments (1)

test/utils/adapters.ts:290

  • dynamicModule() builds the import specifier with pathToFileURL(path). For relative paths (e.g. the PR description’s example dist/sha256-uint8array.mjs), this becomes a root-based file URL (e.g. file:///dist/...) rather than resolving against the current working directory, so the import can fail even when the file exists in the repo.
    override async setup(): Promise<void> {
        let module = await import(pathToFileURL(path).href)
        if (!hasCreateHash(module)) module = module?.default
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 2963fc4079

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@kawanet
kawanet merged commit 559c6c1 into kawanet:main Aug 31, 2026
6 checks passed
@kawanet-bot
kawanet-bot deleted the feature/dynamic-adapter branch August 31, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants