bench: add baselines for each package manager x node_modules layout#1176
Conversation
Adds a new bench target that resolves the same 16-specifier workload against eight realistic monorepo fixtures (npm-flat, pnpm-isolated, pnpm-hoisted, yarn-nm, yarn-pnpm, yarn-pnp, bun-flat, bun-isolated). Each combo asserts correct resolution before timing — the resolved path must end with the package's intra-package file and pass through a layout-specific segment for the package name. Fixtures live under fixtures/bench-pm/<slug>/ and ship only the package.json, lockfile, and PM config. node_modules / .pnp.cjs are generated by the new `just install-bench-fixtures` recipe. The existing `just benchmark` recipe is unchanged (scoped to the resolver bench to keep CodSpeed CI isolated); the new benches are run via `just benchmark-pm`.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4b8dc78fdc
ℹ️ 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".
Merging this PR will degrade performance by 3.56%
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
- Add `just` and `oven-sh/setup-bun@v2` so the benchmark job can run all four package managers needed by `just install-bench-fixtures`. - Build with `--features codspeed,yarn_pnp` so the yarn-pnp combo is included.
Previous lockfiles were generated before apps/web/package.json declared
the workspace-internal deps (@bench/{ui,utils}, plus the external deps
that yarn-pnp's strict resolution requires). Regenerated against the
current package.json so `pnpm install` (which CI runs frozen) succeeds.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cd0b119a50
ℹ️ 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".
Aligns yarn combo slugs with the layout-based naming used by the other PMs (npm-flat, pnpm-isolated/hoisted, bun-flat/isolated). The nodeLinker is still node-modules and pnpm respectively; only the slug, package.json name, and Combo variants change.
…figs Replace 8 near-duplicate monorepos with: - fixtures/bench-pm/template/ — single shared monorepo (uses workspace:* deps) - fixtures/bench-pm/configs/<combo>/ — per-PM config snippets + the small set of files that genuinely differ (npm-flat needs "*" instead of "workspace:*"; yarn-* combos need packageManager: yarn@4.9.2) - fixtures/bench-pm/installs/<combo>/ — materialized monorepos (gitignored) just install-bench-fixtures now: rm -rf installs/, copies template/ then configs/<combo>/ into installs/<combo>/, installs each. Lockfiles regenerate each run (no committed lockfile, no --frozen-lockfile in CI). Bench code looks for fixtures under installs/<slug>/. Committed fixture file count: 88 -> 20.
Yarn berry enables "hardened mode" automatically on public PRs, which forbids lockfile regeneration. Other PMs default to frozen-lockfile in CI too. Commit each combo's lockfile alongside its PM config so `just install-bench-fixtures` can run as a non-mutating verify step.
- Justfile: bun install was guarded by `command -v bun && (...) || echo`, which swallowed any non-zero exit from `bun install` itself. Use if/then/else so a real install failure surfaces. - Justfile: drop `touch yarn.lock` — yarn.lock now ships in configs/yarn-*/ and is copied during materialization. - Bench docstrings: update fixture path (installs/<slug>/) and refresh slug references after the yarn-nm->yarn-flat / yarn-pnpm->yarn-isolated rename.
Drop the single-thread / cold / multi-thread split. Each combo now has one bench: build a fresh Resolver and fan the 16-request workload across worker threads via rayon — modelling a bundler's per-build resolver. The resolver construction is inside the timed body so PnP manifest parse, store discovery, and initial cache warmup all count. Result: 24 -> 8 named benches under `pm/<combo>`.
## 🤖 New release * `oxc_resolver`: 11.20.0 -> 11.21.0 * `oxc_resolver_napi`: 11.20.0 -> 11.21.0 <details><summary><i><b>Changelog</b></i></summary><p> ## `oxc_resolver` <blockquote> ## [11.21.0](v11.20.0...v11.21.0) - 2026-06-03 ### <!-- 0 -->🚀 Features - *(tsconfig)* support package.json imports field in extends ([#1199](#1199)) (by @Boshen) ### <!-- 1 -->🐛 Bug Fixes - *(tsconfig)* apply each referenced project's own `allowJs` ([#1198](#1198)) (by @shulaoda) - make symlink_metadata VPath-aware for Yarn PnP ([#1183](#1183)) (by @Boshen) ### <!-- 4 -->⚡ Performance - borrow relative main field instead of allocating a "./" prefix ([#1187](#1187)) (by @Boshen) - *(cache)* move package.json path into parse instead of cloning ([#1186](#1186)) (by @Boshen) - eliminate symlink stat syscalls by reusing canonicalization ([#1184](#1184)) (by @Boshen) - reduce resolution syscalls by unifying stat and lstat ([#1182](#1182)) (by @Boshen) ### <!-- 9 -->💼 Other - add baselines for each package manager x node_modules layout ([#1176](#1176)) (by @Boshen) ### Contributors * @shulaoda * @Boshen * @renovate[bot] </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). Co-authored-by: oxc-guard[bot] <276638029+oxc-guard[bot]@users.noreply.github.com>
Summary
Adds a new bench target that resolves the same 16-specifier workload against eight realistic monorepo fixtures, one per package manager × node_modules layout combination:
npm-flatpnpm-isolated.pnpm/virtual storepnpm-hoistedshamefullyHoist: trueyarn-nmnode-modulesyarn-pnpmpnpm.store/virtual storeyarn-pnppnpnode_modules/,.pnp.cjsmanifestbun-flathoistedbun-isolatedisolated.bun/virtual storeEach combo asserts correct resolution before timing — the resolved path must end with the package's intra-package file and pass through a layout-specific segment for the package name (
/<pkg>/,/<pkg>@,/<pkg>-{npm,patch,virtual,workspace}-, plus the+/-scoped variants). This catches wrong resolutions across all 8 layouts using a single suffix per request.Layout
Fixtures live under
fixtures/bench-pm/<slug>/as a nested monorepo so the resolver exercises ancestornode_moduleswalking from a depth-3 importer:Lockfiles and PM configs are committed.
node_modules/and.pnp.cjsare gitignored and generated by the newjust install-bench-fixturesrecipe.The new
just benchmark-pmruns the bench (with--features yarn_pnpso all 8 combos are included). The existingjust benchmarkis scoped to--bench resolverso CodSpeed CI behavior is unchanged. CI is not touched in this PR — heavy fixtures and bun installation are deferred.Local results (cold, single resolver, 16 resolves)
yarn-nmbun-flatnpm-flatpnpm-hoistedpnpm-isolatedbun-isolatedyarn-pnpmyarn-pnpFlat layouts cluster ~270 µs; symlinked/isolated cluster ~420 µs (symlink canonicalize tax); PnP cold dominated by
.pnp.cjsparse.This is a baseline PR — follow-up PRs will introduce per-layout resolver optimizations measured against these numbers.