Skip to content

Instantly share code, notes, and snippets.

@TennyZhuang
Created May 11, 2026 03:27
Show Gist options
  • Select an option

  • Save TennyZhuang/cb57391783e5ef43aadcfc88faf84a93 to your computer and use it in GitHub Desktop.

Select an option

Save TennyZhuang/cb57391783e5ef43aadcfc88faf84a93 to your computer and use it in GitHub Desktop.
rust-lang/rust#146895 synthetic rustdoc regression reproducer

Evidence: rust-lang/rust #146895 - Synthetic MCVE

Summary

cargo doc in this synthetic large workspace is ~7-8x slower after nightly-2025-08-20. The regression shape is consistent with rust-lang/rust #146895 and the suspected rustdoc search-index merge path discussed there. This artifact is intended as a compact reproducer/evidence bundle, not a standalone root-cause proof or fix proposal.

Prerequisites

# Install required toolchains
rustup toolchain install nightly-2025-08-19 --profile minimal
rustup toolchain install nightly-2025-08-20 --profile minimal
# Current nightly (for -Zrustdoc-mergeable-info workaround test)
rustup toolchain install nightly --profile minimal

Regenerate Workspace

cd /Users/tianyizhuang/rust-harness-stg0140
python3 gen_synth_ws_v2.py 100 100 synthetic-ws-large

Generator parameters (deterministic, seed=42):

  • 100 crates, 100 items per crate (~40,000 public items: funcs + structs + traits + enums)
  • Dependency graph:
    • 5 core crates (no dependencies)
    • 15 mid crates (each depends on 2-3 core crates)
    • 80 leaf crates (each depends on 2-4 mid crates)
  • Cross-crate pub use re-exports from all deps to stress search-index merge

Run Timing Measurements

Clean-state policy: each run uses a separate target directory, removed beforehand.

Run 1: Pre-regression baseline (nightly-2025-08-19)

cd synthetic-ws-large
rm -rf target-pre-reg
/usr/bin/time -p cargo +nightly-2025-08-19 doc --workspace --target-dir target-pre-reg

Run 2: Post-regression (nightly-2025-08-20)

rm -rf target-post-reg
/usr/bin/time -p cargo +nightly-2025-08-20 doc --workspace --target-dir target-post-reg

Run 3: Current nightly (no workaround)

rm -rf target-current-plain
/usr/bin/time -p cargo +nightly doc --workspace --target-dir target-current-plain

Run 4: Current nightly with workaround

rm -rf target-current-mergeable
/usr/bin/time -p cargo +nightly doc --workspace --target-dir target-current-mergeable -Zrustdoc-mergeable-info

Results (2026-05-11, aarch64-apple-darwin, macOS 26.4.1)

Run Toolchain real (s) user (s) Ratio vs baseline
Pre-regression nightly-2025-08-19 (9eb4a2652) 6.71 25.76 1.00x
Post-regression nightly-2025-08-20 (05f5a58e8) 52.02 63.22 7.75x
Current nightly nightly 2026-05-03 (ad3a598ca) 47.04 59.14 7.01x
Current + mergeable-info nightly 2026-05-03 (ad3a598ca) 7.65 28.60 1.14x

Log Files

Raw timing logs with full metadata (timestamp, host/target, cargo/rustc/rustdoc -Vv, exact command, /usr/bin/time -p output, exit status, clean state):

  • harness-logs/evidence-146895/timing-large-pre-regression-nightly-2025-08-19.log
  • harness-logs/evidence-146895/timing-large-post-regression-nightly-2025-08-20.log
  • harness-logs/evidence-146895/timing-large-current-nightly-no-workaround.log
  • harness-logs/evidence-146895/timing-large-current-nightly-mergeable-info.log

Observations

  1. Regression reproduces clearly at ~7.75x with this synthetic - well above the 3x meaningful-signal threshold.
  2. Regression persists on current nightly (May 2026) - issue is not yet fixed in the default path.
  3. -Zrustdoc-mergeable-info workaround fully mitigates it.
  4. Parallelism collapses: pre-reg uses ~3.8 cores effectively (25.76s user / 6.71s real), post-reg ~1.2 cores (near-serial), consistent with the "single rustdoc consuming CPU" observation in the issue.
  5. Suspected related change from the issue discussion: PR #144476 (commit 8365fcb2b840c95eeb0bc377af8bd498fad22245). This synthetic evidence should still be validated by rustdoc maintainers against the real workload.
#!/usr/bin/env python3
import sys, shutil, random
from pathlib import Path
def gen(workspace_dir, n_crates, m_items):
workspace_dir = Path(workspace_dir)
if workspace_dir.exists():
shutil.rmtree(workspace_dir)
workspace_dir.mkdir(parents=True)
random.seed(42)
members = [f"c{i:03d}" for i in range(n_crates)]
n_core = max(5, n_crates // 20)
n_mid = max(15, n_crates // 7)
core = members[:n_core]
mid = members[n_core:n_core + n_mid]
leaf = members[n_core + n_mid:]
deps_map = {}
for name in core:
deps_map[name] = []
for name in mid:
deps_map[name] = random.sample(core, min(3, len(core)))
for name in leaf:
deps_map[name] = random.sample(mid, min(4, len(mid)))
ws_lines = ["[workspace]", 'resolver = "2"', "members = ["]
for m in members:
ws_lines.append(f' "{m}",')
ws_lines.append("]")
ws_lines.append("")
(workspace_dir / "Cargo.toml").write_text("\n".join(ws_lines))
for name in members:
cdir = workspace_dir / name
(cdir / "src").mkdir(parents=True)
dep_lines = ""
if deps_map[name]:
dep_lines = "\n[dependencies]\n"
for d in deps_map[name]:
dep_lines += f"{d} = {{ path = \"../{d}\" }}\n"
cargo_toml = (
f"[package]\nname = \"{name}\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n"
f"[lib]\npath = \"src/lib.rs\"\n{dep_lines}"
)
(cdir / "Cargo.toml").write_text(cargo_toml)
lines = ["#![allow(dead_code, unused, non_camel_case_types)]"]
lines.append(f"//! Synthetic crate {name} for rustdoc perf evidence (#146895).")
lines.append("")
for d in deps_map[name]:
lines.append(f"pub use {d};")
if deps_map[name]:
lines.append("")
for j in range(m_items):
lines.append(f"/// Function {j} in {name}.")
lines.append(f"pub fn func_{j}(x: u32) -> u32 {{ x + {j} }}")
lines.append(f"/// Struct {j} in {name}.")
lines.append(f"pub struct Struct{j} {{ pub field: u32 }}")
lines.append(f"/// Trait {j} in {name}.")
lines.append(f"pub trait Trait{j} {{ fn method(&self) -> u32; }}")
lines.append(f"impl Trait{j} for Struct{j} {{ fn method(&self) -> u32 {{ self.field }} }}")
lines.append(f"/// Enum {j} in {name}.")
lines.append(f"pub enum Enum{j} {{ A(u32), B {{ x: u32 }}, C }}")
(cdir / "src" / "lib.rs").write_text("\n".join(lines) + "\n")
return workspace_dir
if __name__ == "__main__":
n = int(sys.argv[1]) if len(sys.argv) > 1 else 100
m = int(sys.argv[2]) if len(sys.argv) > 2 else 100
out = Path(sys.argv[3]) if len(sys.argv) > 3 else Path.cwd() / "synthetic-ws-large"
gen(out, n, m)
n_core = max(5, n // 20)
n_mid = max(15, n // 7)
n_leaf = n - n_core - n_mid
print(f"Generated {n} crates x {m} items at {out}")
print(f" Core: {n_core} crates (no deps)")
print(f" Mid: {n_mid} crates (2-3 core deps each)")
print(f" Leaf: {n_leaf} crates (2-4 mid deps each)")
print(f" Total public items: ~{n * m * 4} (funcs + structs + traits + enums)")
# File manifest - rust-lang/rust #146895 synthetic evidence gist
# Generated: 2026-05-11T03:27:44Z
# Host: aarch64-apple-darwin (macOS 26.4.1)
## SHA-256 checksums
0217b2a21fd613b7e0aca55bb56c0622f662f41be876e8934844a0892a75b0e1 gen_synth_ws_v2.py
6e2a03e0dab569737d11b032bd6a550b2dc2a8023c8c2a54e8e7d09b11dabcfe README-146895-synthetic.md
1df266dd1626be0b6a9e1bd8b50ff31e4e733dc8b39afe13024a8f1bbefeabd6 timing-large-current-nightly-mergeable-info.log
81385f1edb37f22cd9388d5e668fe85555d3bb0e7c994a41494fbc19037b04e4 timing-large-current-nightly-no-workaround.log
ed76bc67f9455db7ecd4ea14c1161a94786179a5f1e9c975a7ec0fd4069a1bbd timing-large-post-regression-nightly-2025-08-20.log
7fd29426256fbdce719ce0b908091489cf8137067018aa38f443bc505bbf8362 timing-large-pre-regression-nightly-2025-08-19.log
## File sizes
-rw-r--r--@ 1 tianyizhuang staff 3741 May 11 11:27 README-146895-synthetic.md
-rw-r--r--@ 1 tianyizhuang staff 3230 May 11 11:27 gen_synth_ws_v2.py
-rw-r--r--@ 1 tianyizhuang staff 1634 May 11 11:27 timing-large-current-nightly-mergeable-info.log
-rw-r--r--@ 1 tianyizhuang staff 1705 May 11 11:27 timing-large-current-nightly-no-workaround.log
-rw-r--r--@ 1 tianyizhuang staff 1694 May 11 11:27 timing-large-post-regression-nightly-2025-08-20.log
-rw-r--r--@ 1 tianyizhuang staff 1689 May 11 11:27 timing-large-pre-regression-nightly-2025-08-19.log
=== Run: large-current-mergeable-info (toolchain=nightly, -Zrustdoc-mergeable-info) ===
Timestamp: 2026-05-11T03:00:30Z
Host/Target: aarch64-apple-darwin
git rev-parse HEAD: N/A (synthetic workspace)
--- cargo -Vv ---
cargo 1.97.0-nightly (4f9b52075 2026-05-01)
release: 1.97.0-nightly
commit-hash: 4f9b52075316e9ced380c8fa492858048d5758b6
commit-date: 2026-05-01
host: aarch64-apple-darwin
libgit2: 1.9.2 (sys:0.20.4 vendored)
libcurl: 8.7.1 (sys:0.4.88+curl-8.20.0 system ssl:(SecureTransport) LibreSSL/3.3.6)
ssl: OpenSSL 3.6.2 7 Apr 2026
os: Mac OS 26.4.1 [64-bit]
--- rustc -Vv ---
rustc 1.97.0-nightly (ad3a598ca 2026-05-03)
binary: rustc
commit-hash: ad3a598ca4bc7c68bcbbce3e0d3be9a7618df190
commit-date: 2026-05-03
host: aarch64-apple-darwin
release: 1.97.0-nightly
LLVM version: 22.1.4
--- rustdoc -Vv ---
rustdoc 1.97.0-nightly (ad3a598ca 2026-05-03)
binary: rustdoc
commit-hash: ad3a598ca4bc7c68bcbbce3e0d3be9a7618df190
commit-date: 2026-05-03
host: aarch64-apple-darwin
release: 1.97.0-nightly
LLVM version: 22.1.4
State: clean (fresh target dir)
Command: cargo +nightly doc --workspace --target-dir synthetic-ws-large/target-current-mergeable -Zrustdoc-mergeable-info
--- timing ---
Documenting c035 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c035)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 6.12s
Merging 100 docs for host
Finished documentation merge in 1.50s
Generated /Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/synthetic-ws-large/target-current-mergeable/doc/c000/index.html and 99 other files
real 7.65
user 28.60
sys 9.86
Exit status: 0
=== Run: large-current-nightly-no-workaround (toolchain=nightly, default) ===
Timestamp: 2026-05-11T03:01:26Z
Host/Target: aarch64-apple-darwin
git rev-parse HEAD: N/A (synthetic workspace)
--- cargo -Vv ---
cargo 1.97.0-nightly (4f9b52075 2026-05-01)
release: 1.97.0-nightly
commit-hash: 4f9b52075316e9ced380c8fa492858048d5758b6
commit-date: 2026-05-01
host: aarch64-apple-darwin
libgit2: 1.9.2 (sys:0.20.4 vendored)
libcurl: 8.7.1 (sys:0.4.88+curl-8.20.0 system ssl:(SecureTransport) LibreSSL/3.3.6)
ssl: OpenSSL 3.6.2 7 Apr 2026
os: Mac OS 26.4.1 [64-bit]
--- rustc -Vv ---
rustc 1.97.0-nightly (ad3a598ca 2026-05-03)
binary: rustc
commit-hash: ad3a598ca4bc7c68bcbbce3e0d3be9a7618df190
commit-date: 2026-05-03
host: aarch64-apple-darwin
release: 1.97.0-nightly
LLVM version: 22.1.4
--- rustdoc -Vv ---
rustdoc 1.97.0-nightly (ad3a598ca 2026-05-03)
binary: rustdoc
commit-hash: ad3a598ca4bc7c68bcbbce3e0d3be9a7618df190
commit-date: 2026-05-03
host: aarch64-apple-darwin
release: 1.97.0-nightly
LLVM version: 22.1.4
State: clean (fresh target dir)
Command: cargo +nightly doc --workspace --target-dir synthetic-ws-large/target-current-plain
--- timing ---
Documenting c050 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c050)
Documenting c024 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c024)
Documenting c083 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c083)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 47.02s
Generated /Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/synthetic-ws-large/target-current-plain/doc/c000/index.html and 99 other files
real 47.04
user 59.14
sys 13.41
Exit status: 0
=== Run: large-post-regression (toolchain=nightly-2025-08-20) ===
Timestamp: 2026-05-11T02:59:24Z
Host/Target: aarch64-apple-darwin
git rev-parse HEAD: N/A (synthetic workspace)
--- cargo -Vv ---
cargo 1.91.0-nightly (71eb84f21 2025-08-17)
release: 1.91.0-nightly
commit-hash: 71eb84f21aef43c07580c6aed6f806a6299f5042
commit-date: 2025-08-17
host: aarch64-apple-darwin
libgit2: 1.9.1 (sys:0.20.2 vendored)
libcurl: 8.7.1 (sys:0.4.82+curl-8.14.1 system ssl:(SecureTransport) LibreSSL/3.3.6)
ssl: OpenSSL 3.5.0 8 Apr 2025
os: Mac OS 26.4.1 [64-bit]
--- rustc -Vv ---
rustc 1.91.0-nightly (05f5a58e8 2025-08-19)
binary: rustc
commit-hash: 05f5a58e84a9c3a68586d70bf3d7442c571e379e
commit-date: 2025-08-19
host: aarch64-apple-darwin
release: 1.91.0-nightly
LLVM version: 21.1.0
--- rustdoc -Vv ---
rustdoc 1.91.0-nightly (05f5a58e8 2025-08-19)
binary: rustdoc
commit-hash: 05f5a58e84a9c3a68586d70bf3d7442c571e379e
commit-date: 2025-08-19
host: aarch64-apple-darwin
release: 1.91.0-nightly
LLVM version: 21.1.0
State: clean (fresh target dir)
Command: cargo +nightly-2025-08-20 doc --workspace --target-dir synthetic-ws-large/target-post-reg
--- timing ---
Documenting c094 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c094)
Documenting c050 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c050)
Documenting c026 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c026)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 52.00s
Generated /Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/synthetic-ws-large/target-post-reg/doc/c000/index.html and 99 other files
real 52.02
user 63.22
sys 11.92
Exit status: 0
=== Run: large-pre-regression (toolchain=nightly-2025-08-19) ===
Timestamp: 2026-05-11T02:57:52Z
Host/Target: aarch64-apple-darwin
git rev-parse HEAD: N/A (synthetic workspace)
--- cargo -Vv ---
cargo 1.91.0-nightly (71eb84f21 2025-08-17)
release: 1.91.0-nightly
commit-hash: 71eb84f21aef43c07580c6aed6f806a6299f5042
commit-date: 2025-08-17
host: aarch64-apple-darwin
libgit2: 1.9.1 (sys:0.20.2 vendored)
libcurl: 8.7.1 (sys:0.4.82+curl-8.14.1 system ssl:(SecureTransport) LibreSSL/3.3.6)
ssl: OpenSSL 3.5.0 8 Apr 2025
os: Mac OS 26.4.1 [64-bit]
--- rustc -Vv ---
rustc 1.91.0-nightly (9eb4a2652 2025-08-18)
binary: rustc
commit-hash: 9eb4a2652031ed5ba97c29ef21c79db1645f7883
commit-date: 2025-08-18
host: aarch64-apple-darwin
release: 1.91.0-nightly
LLVM version: 21.1.0
--- rustdoc -Vv ---
rustdoc 1.91.0-nightly (9eb4a2652 2025-08-18)
binary: rustdoc
commit-hash: 9eb4a2652031ed5ba97c29ef21c79db1645f7883
commit-date: 2025-08-18
host: aarch64-apple-darwin
release: 1.91.0-nightly
LLVM version: 21.1.0
State: clean (fresh target dir)
Command: cargo +nightly-2025-08-19 doc --workspace --target-dir synthetic-ws-large/target-pre-reg
--- timing ---
Documenting c086 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c086)
Documenting c088 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c088)
Documenting c070 v0.1.0 (/Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/c070)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 6.70s
Generated /Users/tianyizhuang/rust-harness-stg0140/synthetic-ws-large/synthetic-ws-large/target-pre-reg/doc/c000/index.html and 99 other files
real 6.71
user 25.76
sys 10.50
Exit status: 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment