Repository navigation
rustdoc sidebar duplicate-anchor de-duplication appears to be quadratic #158174
Copy link
Copy link
Closed
Closed
Copy link
Labels
C-bugCategory: This is a bug.Category: This is a bug.I-compiletimeIssue: Problems and improvements with respect to compile times.Issue: Problems and improvements with respect to compile times.T-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.Relevant to the rustdoc team, which will review and decide on the PR/issue.
Description
I tried this with the Rust build-tree rustdoc binary, rustdoc 1.98.0-dev, 4008bbdf34b.
cat > rustdoc_sidebar_deref_repro.py <<'PY'
#!/usr/bin/env python3
import os
import shutil
import subprocess
import time
from pathlib import Path
N = int(os.environ.get("N", "1600"))
RUSTDOC = os.environ.get("RUSTDOC", "rustdoc")
def write_deref_chain(path: Path) -> None:
with path.open("w", encoding="ascii") as f:
f.write("pub struct S0;\n")
for i in range(1, N + 1):
f.write(f"pub struct S{i};\n")
for i in range(1, N + 1):
f.write(f"impl S{i} {{ pub fn foo(&self) {{}} }}\n")
for i in range(N):
j = i + 1
f.write(
f"impl std::ops::Deref for S{i} {{ "
f"type Target = S{j}; "
f"fn deref(&self) -> &S{j} {{ static V: S{j} = S{j}; &V }} "
"}\n"
)
src = Path(f"sidebar_deref_{N}.rs")
write_deref_chain(src)
out = Path(f"rustdoc_sidebar_{N}")
if out.exists():
shutil.rmtree(out)
start = time.perf_counter()
subprocess.run([RUSTDOC, str(src), "--crate-name", "sidebarpoc", "-o", str(out)], check=True)
seconds = time.perf_counter() - start
print(f"deref_depth={N} elapsed={seconds:.3f}s source={src.stat().st_size}")
PY
RUSTDOC=/path/to/rustdoc N=1600 python3 rustdoc_sidebar_deref_repro.py
It creates legal Rust code with a deep Deref chain:
pub struct S0;
pub struct S1;
pub struct S2;
// ...
impl S1 { pub fn foo(&self) {} }
impl S2 { pub fn foo(&self) {} }
impl S3 { pub fn foo(&self) {} }
// ...
impl std::ops::Deref for S0 { type Target = S1; /* ... */ }
impl std::ops::Deref for S1 { type Target = S2; /* ... */ }
impl std::ops::Deref for S2 { type Target = S3; /* ... */ }
// ...When rustdoc renders the page for S0, it recursively collects methods from the
Deref targets for the sidebar. Every target contributes a method named foo, so
the sidebar needs many links with the same base anchor method.foo.
With N=1600, I see rustdoc spend about 49 seconds generating the docs:
deref_depth=1600 elapsed=49.054s source=261063
Here are the timings I collected with the same rustdoc binary:
deref_depth source_bytes exit_status elapsed_ms
100 15357 0 357
200 31457 0 524
400 63657 0 1396
800 128057 0 7333
1600 261063 0 49054
The total number of hash
lookups and temporary string constructions is approximately 1 + 2 + ... + N.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
C-bugCategory: This is a bug.Category: This is a bug.I-compiletimeIssue: Problems and improvements with respect to compile times.Issue: Problems and improvements with respect to compile times.T-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.Relevant to the rustdoc team, which will review and decide on the PR/issue.
Activity
GuillaumeGomez commentedon Jul 7, 2026
Maybe something you might be interested into @yotamofek ? :)
yotamofek commentedon Jul 10, 2026
Sounds fun!
I'll take a look next week 😬
Rollup merge of rust-lang#162976 - xonx4l:rustdoc-sidebar-quadratic, …
Rollup merge of rust-lang#162976 - xonx4l:rustdoc-sidebar-quadratic, …
Unrolled build for #162976 in rollup 163244
Rollup merge of #162976 - xonx4l:rustdoc-sidebar-quadratic, r=lolbina…