Skip to content

perf(pm): force HTTP/1.1 for tarball downloads - #3148

Merged
fireairforce merged 4 commits into
nextfrom
perf/pm-tarball-h1
Jun 12, 2026
Merged

fireairforce merged 4 commits into
nextfrom
perf/pm-tarball-h1

Conversation

@elrrrrrrr

Copy link
Copy Markdown
Contributor

Split out of #3146 — single orthogonal change so the benchmark comment shows its isolated effect.

The tarball downloader had no http1_only(): ALPN negotiated h2 and the registry CDN multiplexed every in-flight tarball over one TCP connection (single congestion window, h2 flow-control cap, loss on one stream stalls siblings). The manifest client already forces h1 for the same pcap-backed reason (#2874) — the downloader never got the fix.

Same-runner ablation (same binary, UTOO_TARBALL_HTTP=h2 vs default h1) on ant-design p3 cold install:

registry h1 h2 h2 penalty
npmjs 5.87s ±0.31 6.45s ±0.01 +9.8%
npmmirror 21.06s ±0.98 28.51s ±7.23 +35.4%

p1/p4 don't touch the tarball client and read ±5% — the noise floor.

Also .no_gzip() on the tarball client (tarballs are already gzip), and explicit gzip feature declarations on ruborist's reqwest deps (already active in the utoo binary via feature unification from utoo-pm — documentation, not behavior).

Expected bench signal: p3/p0 improve, p1/p4 unchanged.

🤖 Generated with Claude Code

The tarball downloader client had no http1_only(): ALPN negotiated h2
and the registry CDN multiplexed every in-flight tarball over one TCP
connection (single congestion window + flow-control cap, loss on one
stream stalls siblings). The manifest client already forces h1 for the
same pcap-backed reason (#2874) - the downloader never got the fix.

Same-runner ablation (same binary, UTOO_TARBALL_HTTP=h2 vs default) on
ant-design p3 cold install: h2 is +9.8% slower on npmjs (sigma 0.01)
and +35.4% slower on npmmirror. p1/p4 (no tarballs) show +-5% noise.

Also .no_gzip() on the tarball client (tarballs are already gzip; the
crate-level gzip feature was inviting a second Content-Encoding layer),
and declare the gzip feature explicitly on ruborist's native reqwest
deps - it was already active in the utoo binary via feature unification
from utoo-pm, so this is documentation, not behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@elrrrrrrr elrrrrrrr added the benchmark Run pm-bench on PR label Jun 11, 2026

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request configures the DNS cached client to disable gzip decompression for tarballs and defaults to HTTP/1.1 (unless overridden by the UTOO_TARBALL_HTTP environment variable) to optimize download performance. It also enables the gzip feature on reqwest in Cargo.toml for transparent packument decompression. The review feedback suggests improving the environment variable resolution by supporting both uppercase and lowercase variants and filtering out empty strings.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/pm/src/util/retry.rs Outdated
// loss on one stream stalls siblings) — same rationale as the manifest
// client in ruborist/src/service/http.rs. `UTOO_TARBALL_HTTP=h2` keeps
// ALPN negotiation so CI can A/B the protocols with one binary.
let h2 = std::env::var("UTOO_TARBALL_HTTP").is_ok_and(|v| v.eq_ignore_ascii_case("h2"));

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

To maintain consistency with how environment variables are resolved elsewhere in the codebase (such as proxy settings in ruborist/src/service/http.rs), it is recommended to support both uppercase and lowercase variants of the environment variable. Additionally, filtering out empty strings prevents an empty uppercase env var (which can occur in certain sandbox environments) from shadowing a valid lowercase one.

    let h2 = std::env::var("UTOO_TARBALL_HTTP")
        .ok()
        .filter(|s| !s.is_empty())
        .or_else(|| std::env::var("utoo_tarball_http").ok().filter(|s| !s.is_empty()))
        .is_some_and(|v| v.eq_ignore_ascii_case("h2"));

elrrrrrrr and others added 3 commits June 11, 2026 20:31
The same-runner A/B already settled the question (h2 +9.8% on p3
against npmjs, +35% against npmmirror), so the runtime toggle carries
no remaining value - hard-force http1_only and keep the measured
numbers in the comment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@killagu killagu 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.

LGTM

@github-actions

Copy link
Copy Markdown

📊 pm-bench-phases · 9ee32ce · linux (ubuntu-latest)

Workflow run — ant-design

registry.npmjs.org

utoo (PR) vs utoo-next (baseline): ✅ p0 +1.5% · ✅ p1 +0.4% · ✅ p3 -10.7% · ✅ p4 -7.2%

✅ within noise · 🚀 faster · ⚠️ slower — Δ is the median of per-round paired deltas (interleaved rounds share weather windows); flagged when |Δ| > 5% and ≥80% of rounds agree on sign

p0 · full cold install

PM wall (mean ± σ) min user sys RSS Δ vs baseline
utoo (PR) 8.08s ± 0.09s 7.98s 9.89s 12.0s 908M +1.5% ✅
utoo-next (baseline) 8.00s ± 0.36s 7.63s 9.80s 11.7s 907M —
bun 9.34s ± 0.22s 9.19s 9.99s 10.2s 615M +14.8% ⚠️

p1 · resolve

PM wall (mean ± σ) min user sys RSS Δ vs baseline
utoo (PR) 2.85s ± 0.09s 2.75s 5.05s 1.74s 619M +0.4% ✅
utoo-next (baseline) 2.84s ± 0.06s 2.80s 5.05s 1.76s 619M —
bun 2.54s ± 0.08s 2.45s 3.91s 1.16s 521M -12.6% 🚀

p3 · cold install

PM wall (mean ± σ) min user sys RSS Δ vs baseline
utoo (PR) 6.37s ± 0.49s 6.00s 4.68s 10.7s 429M -10.7% ✅
utoo-next (baseline) 6.80s ± 0.41s 6.35s 4.79s 10.7s 418M —
bun 6.43s ± 0.28s 6.11s 6.00s 9.57s 496M -7.3% ✅

p4 · warm link

PM wall (mean ± σ) min user sys RSS Δ vs baseline
utoo (PR) 2.33s ± 0.06s 2.27s 0.40s 3.59s 52M -7.2% ✅
utoo-next (baseline) 2.53s ± 0.07s 2.46s 0.41s 3.61s 52M —
bun 3.66s ± 0.14s 3.43s 0.17s 2.45s 129M +48.2% ⚠️
Resources & footprint

p0 · full cold install

PM vCtx iCtx netRX netTX cache node_modules lock
utoo 77747 64313 1.10G 8M 1.65G 1.64G 2M
utoo-next 84417 69240 1.10G 5M 1.65G 1.65G 2M
bun 20031 18842 1.12G 7M 1.81G 1.69G 1M

p1 · resolve

PM vCtx iCtx netRX netTX cache node_modules lock
utoo 35382 47978 206M 3M 7M 3M 2M
utoo-next 36125 49796 206M 3M 7M 3M 2M
bun 14013 3419 209M 3M 111M 0B 1M

p3 · cold install

PM vCtx iCtx netRX netTX cache node_modules lock
utoo 75141 50304 917M 5M 1.64G 1.64G 2M
utoo-next 93167 58776 916M 3M 1.64G 1.64G 2M
bun 6268 8509 940M 5M 1.69G 1.69G 1M

p4 · warm link

PM vCtx iCtx netRX netTX cache node_modules lock
utoo 22619 13717 3K 7K 1.64G 1.64G 2M
utoo-next 23029 14056 3K 8K 1.64G 1.64G 2M
bun 226 22 7K 35K 1.69G 1.69G 1M

@fireairforce
fireairforce merged commit c976655 into next Jun 12, 2026
32 checks passed
@fireairforce
fireairforce deleted the perf/pm-tarball-h1 branch June 12, 2026 00:22
elrrrrrrr added a commit that referenced this pull request Jun 17, 2026
Resolve conflicts against #3157 (service refactor) and #3148 (HTTP/1.1
download client):

- downloader.rs: keep the streaming byte-counter (DOWNLOADED_BYTES /
  GaugeGuard) on top of next's fallible `build_download_client`
  (downloader_client() accessor) — both changes compose, the body
  auto-merged.
- script.rs was split into service/script/{exec,lifecycle,node_gyp};
  port the success-path script-output debug logging and the 64 KiB
  `truncate_for_log` cap into script/exec.rs::execute_script (the
  Silent dependency-hook path), where the old method moved.

GaugeGuard (scheduler extract/link) and track_script (package.rs hook
queue) auto-merged cleanly. cargo check/clippy clean, 274 pm tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

benchmark Run pm-bench on PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants