Repository navigation
Conversation
Copy the OnceMap util module from pm/util to ruborist/util so the resolver can use it for per-name dedup of concurrent manifest fetches. Foundation commit — no usage yet, that lands in the worker-pool wiring commit. The pm-side oncemap.rs stays for cloner/downloader users.
CI pcap analysis against npmjs.org revealed TLS CPU as a major
preload bottleneck. Per-handshake timing on CI:
utoo (ring) bun (BoringSSL)
CH → SH (1 RTT) 11 ms 10 ms (network)
CCS → first AppData 78 ms p50 12 ms p50
154 ms max 17 ms max
TOTAL CH → AppData 162 ms 46 ms
The "CCS → AppData" phase is dominated by post-ChangeCipherSpec
client work (Finished MAC verify, state machine transition,
request dispatch). Observed at CI pcap capture:
utoo: Client CCS spread 154ms (first conn done at 0.975s, last
at 1.129s), then first AppData *all* fire within 11ms at
~1.13s — classic CPU-saturation pattern where 128 parallel
TLS handshakes serialise across 4 blocking threads and HTTP
dispatch is starved until crypto drains.
bun: CCS spread 51ms, AppData spread 43ms — dispatch flows
smoothly as each conn completes.
`ring` (rustls' default provider) is pure Rust + hand-tuned
assembly; `aws-lc-rs` wraps BoringSSL's primitives which are more
aggressively optimised for x86_64 AES-NI + SHA-NI.
Reqwest 0.12's `rustls-tls-native-roots` feature pins `__rustls-ring`
via Cargo's feature unification — no way to override. Swap to
`rustls-tls-native-roots-no-provider`, add a direct `rustls` dep
with the `aws-lc-rs` feature, load native root certs via
`rustls-native-certs` and pass the `ClientConfig` into reqwest via
`use_preconfigured_tls`.
Local M2 (ARM, where ring's hand-tuned ARM assembly is already
near-optimal) shows neutral perf (~2.9s both providers). Waiting
on CI to confirm the x86_64 CCS→AppData gap closes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire the OnceMap from #2832-foundation into UnifiedRegistry's resolve_full_manifest. When N packages all transitively pull on the same dep (e.g. 50 packages → react), only the first hits the network; the others await the shared Arc<result> on Notify and clone it on resolve. DashMap + tokio::sync::Notify keeps the fast path (cache hit) lock-free. cfg-gated on native; wasm path keeps the direct fetch since dashmap + tokio sync are unnecessary there. FullManifestResult derives Clone so OnceMap waiters can each take owned copies.
N long-lived `tokio::spawn` workers pull work from a shared lock-free `SegQueue`. Each worker is independent on tokio's multi-thread runtime, so when one worker is parsing manifest JSON (CPU-bound, simd_json), other workers continue driving their network IO and other parses run on different cores. Replaces `FuturesUnordered` where the main task owned all preload futures and polled them cooperatively — every per- future await continuation (including parse) ran serialised in that single task. The architectural fix alone (proven nop in PR #2830 with spawn_local) needs the network-layer drivers (aws-lc-rs + OnceMap, earlier in this stack) to actually express its benefit. With them: TLS handshake CPU is fast (aws-lc-rs), duplicate fetches are deduped (OnceMap), so worker-pool's N independent task slots are doing actual unique work. ## MaybeSend / MaybeSync shim `tokio::spawn` requires `Future: Send + 'static`, which forces `RegistryClient` trait surface to grow `+ Send` on its `impl Future` returns + `Self: Sync` / `Self::Error: Send` on default impls. Native uses real Send/Sync; wasm32 uses no-op marker traits because `JsFuture` is `!Send` and tasks run via `wasm_bindgen_futures::spawn_local`. `PreloadRegistry` trait alias bundles `RegistryClient + Clone + MaybeSend + MaybeSync + 'static` so the 5 resolver entry points (`build_deps*`, `resolve*`, `run_preload_phase`) read clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the manifest preloading system to use a multi-threaded worker pool with WASM support and introduces a OnceMap utility to deduplicate concurrent network requests. It also migrates the TLS implementation to aws-lc-rs for improved performance. Feedback identifies a race condition in the worker termination logic, the use of unstable let_chains syntax which will break stable Rust compilation, and an inefficient method for calculating processed statistics. Additionally, it is recommended to narrow the scope of the dead_code allowance.
| pending.push(tdep); | ||
| count += 1; | ||
| } | ||
| } | ||
| if count > 0 { | ||
| dispatched.fetch_add(count, Ordering::Release); |
There was a problem hiding this comment.
There is a race condition in the worker termination logic. The dispatched counter must be incremented before pushing new work items to the pending queue. If pending.push happens first, another worker could pop the item, finish it, and increment completed before the current worker increments dispatched. This would cause completed == dispatched to be true prematurely, leading to early shutdown of the preload phase.
let new_added = if let Ok(resolved) = &result {
let mut to_push = Vec::new();
for tdep in extract_transitive_deps(&resolved.manifest, &config_for_worker) {
let key = format!("{}@{}", tdep.0, tdep.1);
if processed.insert(key) {
to_push.push(tdep);
}
}
let count = to_push.len();
if count > 0 {
dispatched.fetch_add(count, Ordering::Release);
for tdep in to_push {
pending.push(tdep);
}
// Wake parked workers so they pick up the new
// work before checking the termination condition.
notify.notify_waiters();
}
count
} else {
0
};| if let Some(entry) = self.map.get(key) | ||
| && matches!(entry.value(), Value::Done(_)) | ||
| { | ||
| return; | ||
| } |
There was a problem hiding this comment.
The use of let_chains (e.g., if let ... && ...) is an unstable Rust feature. Unless this project explicitly targets nightly and enables the feature flag, this will cause a compilation error on stable Rust. It's safer to use nested if let blocks.
| if let Some(entry) = self.map.get(key) | |
| && matches!(entry.value(), Value::Done(_)) | |
| { | |
| return; | |
| } | |
| if let Some(entry) = self.map.get(key) { | |
| if matches!(entry.value(), Value::Done(_)) { | |
| return; | |
| } | |
| } |
| if let Some(entry) = self.map.get(&key) | ||
| && let Value::Done(result) = entry.value() | ||
| { | ||
| return Some(Arc::clone(result)); | ||
| } |
There was a problem hiding this comment.
The use of let_chains is unstable and will break compilation on stable Rust. Please use nested if let instead.
| if let Some(entry) = self.map.get(&key) | |
| && let Value::Done(result) = entry.value() | |
| { | |
| return Some(Arc::clone(result)); | |
| } | |
| if let Some(entry) = self.map.get(&key) { | |
| if let Value::Done(result) = entry.value() { | |
| return Some(Arc::clone(result)); | |
| } | |
| } |
| stats.total_processed = { | ||
| let mut set: HashSet<String> = HashSet::with_capacity(processed.len()); | ||
| for entry in processed.iter() { | ||
| set.insert(entry.key().clone()); | ||
| } | ||
| set.len() | ||
| }; |
There was a problem hiding this comment.
| @@ -0,0 +1,465 @@ | |||
| #![allow(dead_code)] | |||
aws-lc-sys cc_builder.rs:692 panics on wasm32 target (no support). Move the explicit rustls + aws-lc-rs dependency to native-only; reqwest's rustls-tls-native-roots-no-provider feature on wasm is a no-op since wasm uses the fetch API and the browser's TLS stack, not rustls.
📊 pm-bench-phases ·
|
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 9.40s | 0.45s | 10.09s | 10.15s | 648M | 315.8K |
| utoo-npm | 10.11s | 0.39s | 11.60s | 13.24s | 1.32G | 155.8K |
| utoo | 9.53s | 0.90s | 12.47s | 13.04s | 1.33G | 156.5K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 14.7K | 17.0K | 1.16G | 6M | 1.83G | 1.72G | 1M |
| utoo-npm | 165.6K | 153.0K | 1.14G | 4M | 1.68G | 1.68G | 2M |
| utoo | 131.9K | 95.9K | 1.14G | 5M | 1.68G | 1.68G | 2M |
p1_resolve
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 2.17s | 0.05s | 3.91s | 1.07s | 502M | 171.9K |
| utoo-npm | 5.26s | 0.06s | 5.92s | 1.19s | 429M | 67.9K |
| utoo | 3.03s | 0.11s | 6.62s | 1.95s | 569M | 83.1K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 9.7K | 3.9K | 200M | 3M | 104M | - | 1M |
| utoo-npm | 65.3K | 3.0K | 202M | 2M | 9M | 5M | 2M |
| utoo | 39.4K | 20.7K | 198M | 2M | 9M | 5M | 2M |
p3_cold_install
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 7.18s | 0.77s | 6.09s | 9.88s | 588M | 197.5K |
| utoo-npm | 7.29s | 1.26s | 5.57s | 11.33s | 991M | 105.7K |
| utoo | 6.40s | 0.07s | 5.47s | 11.27s | 913M | 125.1K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 5.1K | 6.9K | 993M | 4M | 1.73G | 1.73G | 1M |
| utoo-npm | 109.7K | 72.0K | 964M | 3M | 1.67G | 1.67G | 2M |
| utoo | 104.0K | 79.3K | 964M | 3M | 1.67G | 1.67G | 2M |
p4_warm_link
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 3.29s | 0.16s | 0.22s | 2.34s | 135M | 32.5K |
| utoo-npm | 2.58s | 0.19s | 0.65s | 4.00s | 82M | 18.7K |
| utoo | 2.37s | 0.06s | 0.65s | 4.01s | 82M | 18.4K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 272 | 23 | 7M | 52K | 1.88G | 1.72G | 1M |
| utoo-npm | 50.0K | 21.5K | 21K | 10K | 1.67G | 1.67G | 2M |
| utoo | 50.7K | 22.8K | 21K | 10K | 1.68G | 1.67G | 2M |
npmmirror.com
p0_full_cold
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 35.12s | 11.91s | 9.22s | 9.56s | 532M | 381.8K |
| utoo-npm | 26.95s | 5.05s | 8.66s | 14.38s | 776M | 98.1K |
| utoo | 51.32s | 32.76s | 8.58s | 14.28s | 782M | 105.1K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 53.8K | 4.6K | 1.12G | 9M | 1.84G | 1.72G | 2M |
| utoo-npm | 249.2K | 107.1K | 978M | 8M | 1.67G | 1.68G | 2M |
| utoo | 236.8K | 86.5K | 981M | 8M | 1.67G | 1.68G | 2M |
p1_resolve
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 1.48s | 0.05s | 3.97s | 1.09s | 607M | 186.5K |
| utoo-npm | 5.23s | 0.11s | 2.10s | 0.59s | 75M | 16.1K |
| utoo | 3.22s | 1.83s | 1.50s | 0.54s | 82M | 17.3K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 5.0K | 6.1K | 151M | 2M | 106M | - | 2M |
| utoo-npm | 45.9K | 751 | 12M | 2M | - | 4M | 2M |
| utoo | 26.6K | 1.8K | 16M | 2M | - | 4M | 2M |
p3_cold_install
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 23.97s | 1.28s | 5.43s | 8.24s | 243M | 113.2K |
| utoo-npm | 46.43s | 30.54s | 6.29s | 12.68s | 585M | 89.0K |
| utoo | 51.63s | 30.07s | 6.05s | 12.89s | 582M | 92.6K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 32.7K | 2.3K | 984M | 7M | 1.70G | 1.70G | 2M |
| utoo-npm | 190.7K | 93.8K | 965M | 6M | 1.67G | 1.67G | 2M |
| utoo | 194.9K | 94.6K | 975M | 6M | 1.67G | 1.67G | 2M |
p4_warm_link
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 15.01s | 20.24s | 0.18s | 2.25s | 134M | 30.8K |
| utoo-npm | 2.47s | 0.26s | 0.62s | 3.86s | 82M | 18.9K |
| utoo | 2.27s | 0.09s | 0.63s | 3.90s | 83M | 19.4K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 633 | 22 | 3M | 118K | 1.82G | 1.72G | 2M |
| utoo-npm | 48.1K | 21.9K | 86K | 15K | 1.67G | 1.67G | 2M |
| utoo | 49.6K | 22.0K | 85K | 13K | 1.67G | 1.67G | 2M |
📊 pm-bench-phases ·
|
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 17.54s | 1.87s | 6.20s | 17.47s | 774M | 50.0K |
| utoo-npm | 22.63s | 6.56s | 10.45s | 23.24s | 933M | 96.9K |
| utoo | 17.70s | 3.92s | 9.43s | 20.66s | 1.10G | 109.9K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 16.1K | 143.9K | - | - | 1.79G | 1.90G | 1M |
| utoo-npm | 13.9K | 360.2K | - | - | 1.63G | 1.88G | 2M |
| utoo | 7.2K | 352.2K | - | - | 1.63G | 1.87G | 2M |
p1_resolve
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 2.97s | 0.12s | 3.13s | 1.66s | 475M | 30.8K |
| utoo-npm | 5.71s | 0.29s | 4.50s | 2.70s | 549M | 37.2K |
| utoo | 5.43s | 1.91s | 5.26s | 3.03s | 609M | 40.5K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 34 | 21.6K | - | - | 110M | - | 1M |
| utoo-npm | 14 | 72.6K | - | - | 28M | 5M | 2M |
| utoo | 12 | 81.1K | - | - | 28M | 5M | 2M |
p3_cold_install
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 15.83s | 5.17s | 3.28s | 15.01s | 517M | 33.7K |
| utoo-npm | 14.65s | 4.65s | 3.78s | 15.70s | 791M | 83.1K |
| utoo | 12.77s | 2.78s | 3.84s | 16.47s | 747M | 80.7K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 5.6K | 132.3K | - | - | 1.70G | 1.94G | 1M |
| utoo-npm | 1.6K | 238.7K | - | - | 1.60G | 1.83G | 2M |
| utoo | 1.4K | 220.3K | - | - | 1.60G | 1.83G | 2M |
p4_warm_link
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 6.53s | 1.56s | 0.12s | 2.53s | 52M | 3.9K |
| utoo-npm | 5.53s | 0.84s | 0.69s | 3.77s | 97M | 7.2K |
| utoo | 3.78s | 0.54s | 0.51s | 2.88s | 92M | 7.0K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 17.0K | 1.0K | - | - | 1.87G | 1.91G | 1M |
| utoo-npm | 13.0K | 76.5K | - | - | 1.60G | 1.83G | 2M |
| utoo | 13.5K | 74.2K | - | - | 1.63G | 1.83G | 2M |
npmmirror.com
p0_full_cold
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 50.39s | 36.38s | 7.77s | 24.95s | 598M | 38.6K |
| utoo-npm | 51.90s | 22.80s | 8.93s | 26.08s | 778M | 77.9K |
| utoo | 27.55s | 1.13s | 7.30s | 20.82s | 820M | 86.0K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 15.4K | 151.5K | - | - | 1.78G | 1.90G | 2M |
| utoo-npm | 4.3K | 429.4K | - | - | 1.61G | 1.87G | 2M |
| utoo | 898 | 413.5K | - | - | 1.61G | 1.86G | 2M |
p1_resolve
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 16.45s | 22.35s | 3.13s | 1.88s | 558M | 36.3K |
| utoo-npm | 4.61s | 0.05s | 1.79s | 0.98s | 79M | 5.8K |
| utoo | 4.20s | 3.83s | 1.45s | 0.66s | 83M | 6.0K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 36 | 26.0K | - | - | 111M | - | 2M |
| utoo-npm | 5 | 33.6K | - | - | - | 4M | 2M |
| utoo | 28 | 17.9K | - | - | - | 4M | 2M |
p3_cold_install
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 34.16s | 16.69s | 3.61s | 15.05s | 250M | 16.5K |
| utoo-npm | 54.67s | 33.01s | 5.62s | 20.39s | 641M | 73.5K |
| utoo | 32.00s | 3.78s | 4.84s | 17.24s | 673M | 74.9K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 1.9K | 128.2K | - | - | 1.65G | 1.91G | 2M |
| utoo-npm | 1.8K | 374.4K | - | - | 1.61G | 1.87G | 2M |
| utoo | 1.6K | 369.5K | - | - | 1.61G | 1.87G | 2M |
p4_warm_link
| PM | wall | ±σ | user | sys | RSS | pgMinor |
|---|---|---|---|---|---|---|
| bun | 5.15s | 0.54s | 0.08s | 2.14s | 44M | 3.4K |
| utoo-npm | 3.42s | 0.10s | 0.49s | 2.54s | 91M | 6.8K |
| utoo | 3.75s | 0.48s | 0.49s | 2.76s | 87M | 6.6K |
| PM | vCtx | iCtx | netRX | netTX | cache | node_mod | lock |
|---|---|---|---|---|---|---|---|
| bun | 13.1K | 444 | - | - | 1.75G | 1.90G | 2M |
| utoo-npm | 12.8K | 69.3K | - | - | 1.61G | 1.82G | 2M |
| utoo | 12.6K | 71.5K | - | - | 1.61G | 1.82G | 2M |
Summary
The minimum subset of #2818's 101 commits that, individually validated, capture the perf-driver synergy:
4 commits, ~7 files. No tarball-extract / cap-raise / DNS-tuning / etc. from #2818.
Driver-hunt history
The synergy hypothesis: aws-lc-rs unblocks TLS-CPU bottleneck → OnceMap removes duplicate fetches → worker-pool's N independent task slots finally have unique work to do. None alone shows the win.
Local data
ant-design `utoo deps` cold (mac, system proxy on — absolute numbers polluted but ratio is signal):
12.6× ratio matches the order-of-magnitude expected from TLS 3.5× + OnceMap dedup ~2× + parse parallelism. CI bench-phases on clean network is the real signal.
Test plan
🤖 Generated with Claude Code