Skip to content

perf(pm): prefetch lockfile installs with rayon workers#2974

Draft
elrrrrrrr wants to merge 4 commits into
perf/pm-resolver-demand-bfsfrom
exp/pm-install-prefetch-extract-rayon-b33d922
Draft

perf(pm): prefetch lockfile installs with rayon workers#2974
elrrrrrrr wants to merge 4 commits into
perf/pm-resolver-demand-bfsfrom
exp/pm-install-prefetch-extract-rayon-b33d922

Conversation

@elrrrrrrr
Copy link
Copy Markdown
Contributor

@elrrrrrrr elrrrrrrr commented May 18, 2026

Summary

Hypothesis

#2973 has the strongest p4 wall/ctx, but p3 is unstable. #2972 has stronger p3 ctx and stable p3 wall, but weaker p4 than #2973. This branch checks whether prefetch + extract workers can keep #2973 p4 while recovering #2972 p3 ctx.

Validation

  • cargo fmt
  • cargo test -p utoo-pm service::install::tests::test_is_prefetchable_registry_tarball
  • cargo test -p utoo-pm service::install_scheduler::tests
  • cargo test -p utoo-pm util::cloner::tests
  • cargo test -p utoo-pm util::downloader::tests
  • cargo test -p utoo-pm test_extract_and_write_sync
  • cargo clippy -p utoo-pm --all-targets -- -D warnings --no-deps

Benchmark

GHA linux/npmjs, run 26020431477:

phase utoo wall utoo ctx utoo-next wall utoo-next ctx bun wall bun ctx
p0_full_cold 7.58s ±0.13 84.9K / 51.9K 8.18s ±0.09 125.6K / 86.1K 9.06s ±0.06 17.2K / 19.6K
p1_resolve 2.44s ±0.03 16.8K / 21.4K 3.07s ±0.04 75.9K / 104.1K 2.12s ±0.06 9.8K / 4.6K
p3_cold_install 6.34s ±1.90 78.1K / 44.0K 6.01s ±0.16 97.8K / 46.9K 6.83s ±0.17 5.5K / 7.6K
p4_warm_link 2.21s ±0.04 18.4K / 12.1K 2.49s ±0.07 44.7K / 22.0K 3.49s ±0.07 270 / 23

Conclusion: p4 keeps the #2973 low-ctx class, but p3 does not recover the stable #2972 result and has high wall-time variance. Keep this as the combination baseline while testing #2975/#2976/#2977 for p4 cache-hit and p3 critical-path queueing.

@elrrrrrrr elrrrrrrr added A-Pkg Manager Area: Package Manager benchmark Run pm-bench on PR and removed benchmark Run pm-bench on PR labels May 18, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a prefetching mechanism for registry tarballs and refactors package extraction and cloning to use synchronous operations within a Rayon worker pool, including macOS-specific clonefile support. Feedback focuses on improving error handling by treating directory cleanup failures as fatal, removing redundant cleanup logic, and avoiding the use of catch_unwind for worker panics. Additionally, the use of std::thread::sleep within Rayon threads was flagged for potential performance impact.

Comment on lines +480 to +490
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
clone_package_from_cache_sync(
&job.spec.package.name,
&job.spec.package.version,
&job.spec.package.tarball_url,
&job.cache_path,
&job.spec.target,
)
.map_err(|e| format!("{e:#}"))
}))
.unwrap_or_else(|_| Err("install clone worker panicked".to_string()));
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.

high

The use of std::panic::catch_unwind to convert a panic into a recoverable Err violates the general rule that panics should be treated as unrecoverable bugs. If a worker panics, it indicates a bug that should not be handled as a transient error. Removing the catch-unwind logic allows the panic to propagate naturally, which is preferred for unrecoverable issues.

                let result = clone_package_from_cache_sync(
                    &job.spec.package.name,
                    &job.spec.package.version,
                    &job.spec.package.tarball_url,
                    &job.cache_path,
                    &job.spec.target,
                )
                .map_err(|e| format!("{e:#}"));
References
  1. Do not implement recovery logic for panics. Panics should be treated as unrecoverable bugs that need to be fixed, not as transient, recoverable errors.


for delay in std::iter::once(std::time::Duration::ZERO).chain(create_retry_strategy()) {
if !delay.is_zero() {
std::thread::sleep(delay);
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.

medium

Using std::thread::sleep inside a Rayon worker thread is generally discouraged as it blocks the worker from executing other tasks in the pool. While retries are necessary for system calls like clonefile, consider if this blocking behavior is acceptable given the configured clone_limit or if a more asynchronous approach is possible.

Comment on lines +268 to +272
if dst.try_exists()?
&& let Err(e) = std::fs::remove_dir_all(dst)
{
tracing::warn!("Failed to clean target directory {}: {}", dst.display(), e);
}
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.

medium

If std::fs::remove_dir_all fails, the subsequent clone_dir_native_sync is highly likely to fail as well (especially on macOS where clonefile requires the destination to not exist). This error should be treated as fatal rather than just a warning to ensure the system doesn't proceed with an inconsistent state.

    if dst.try_exists()? {
        std::fs::remove_dir_all(dst)
            .with_context(|| format!("Failed to clean target directory {}", dst.display()))?;
    }

Comment on lines +484 to +491
if dst.try_exists()? {
if validate_name_version_sync(dst, name, version) {
return Ok(false);
}
if let Err(e) = std::fs::remove_dir_all(dst) {
tracing::warn!("Failed to clean target directory {}: {}", dst.display(), e);
}
}
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.

medium

This call to remove_dir_all is redundant because clone_sync (called on line 492) also attempts to remove the destination directory if it exists. Additionally, as noted in clone_sync, failure to clean the directory should be a fatal error.

    if dst.try_exists()? && validate_name_version_sync(dst, name, version) {
        return Ok(false);
    }

@github-actions
Copy link
Copy Markdown

📊 pm-bench-phases · b1210ef · linux (ubuntu-latest)

Workflow run — ant-design

PMs: utoo (this branch) · utoo-npm (latest published) · bun (latest)

npmjs.org

p0_full_cold

PM wall ±σ user sys RSS pgMinor
bun 7.57s 0.06s 10.41s 6.30s 608M 293.2K
utoo-next 7.15s 0.21s 10.81s 8.13s 1.01G 121.4K
utoo-npm 7.74s 1.08s 10.99s 8.19s 1.00G 123.3K
utoo 6.81s 0.19s 11.50s 7.67s 956M 149.0K
PM vCtx iCtx netRX netTX cache node_mod lock
bun 23.0K 18.1K 1.20G 7M 1.89G 1.76G 1M
utoo-next 146.0K 112.1K 1.17G 5M 1.73G 1.72G 2M
utoo-npm 155.0K 115.6K 1.17G 6M 1.73G 1.72G 2M
utoo 96.4K 55.2K 1.18G 7M 1.73G 1.72G 3M

p1_resolve

PM wall ±σ user sys RSS pgMinor
bun 2.31s 0.06s 4.30s 0.81s 497M 178.5K
utoo-next 3.02s 0.04s 5.58s 1.53s 621M 83.2K
utoo-npm 3.08s 0.02s 5.70s 1.56s 612M 73.9K
utoo 2.33s 0.02s 6.20s 1.14s 650M 120.5K
PM vCtx iCtx netRX netTX cache node_mod lock
bun 13.3K 4.3K 203M 3M 108M - 1M
utoo-next 88.6K 91.5K 201M 3M 7M 3M 2M
utoo-npm 91.7K 98.5K 202M 3M 7M 3M 2M
utoo 17.7K 20.1K 204M 3M 7M 3M 2M

p3_cold_install

PM wall ±σ user sys RSS pgMinor
bun 5.33s 0.06s 5.91s 6.19s 580M 193.2K
utoo-next 5.73s 0.16s 5.04s 6.98s 486M 62.8K
utoo-npm 5.51s 0.05s 5.05s 6.95s 491M 60.3K
utoo 4.80s 0.26s 4.80s 6.67s 482M 55.7K
PM vCtx iCtx netRX netTX cache node_mod lock
bun 10.4K 7.7K 1.00G 4M 1.77G 1.77G 1M
utoo-next 125.9K 50.4K 999M 4M 1.72G 1.72G 2M
utoo-npm 118.1K 55.0K 999M 3M 1.72G 1.72G 2M
utoo 80.5K 45.6K 999M 3M 1.72G 1.72G 2M

p4_warm_link

PM wall ±σ user sys RSS pgMinor
bun 2.09s 0.03s 0.15s 1.19s 137M 33.3K
utoo-next 1.89s 0.03s 0.50s 2.37s 79M 18.5K
utoo-npm 1.72s 0.08s 0.52s 2.35s 80M 18.9K
utoo 1.95s 0.49s 0.37s 2.09s 50M 11.0K
PM vCtx iCtx netRX netTX cache node_mod lock
bun 254 12 5M 25K 1.93G 1.74G 1M
utoo-next 44.1K 19.9K 3K 10K 1.72G 1.72G 2M
utoo-npm 43.8K 20.2K 4K 8K 1.72G 1.72G 2M
utoo 18.4K 11.2K 2K 5K 1.72G 1.72G 2M

npmmirror.com: no output captured.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Pkg Manager Area: Package Manager benchmark Run pm-bench on PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant