Skip to content

cargo doc in large workspace is 10 times slower on nightly #146895

Open

Description

@madsmtm

View all comments

EDIT: Workaround for now is to use cargo +nightly doc -Zrustdoc-mergeable-info, see #130676 for more info.

Reproduction Steps

Logs from my CI on ubuntu-latest:

Bisection

searched nightlies: from nightly-2025-08-19 to nightly-2025-08-20
regressed nightly: nightly-2025-08-20
searched commit range: 9eb4a26...05f5a58
regressed commit: 8365fcb

bisected with cargo-bisect-rustc v0.6.8

Host triple: aarch64-apple-darwin
Reproduce with:

cargo bisect-rustc --timeout 120 --start 2025-08-19 --end 2025-08-20 -- doc 

Additional Details

I'd guess this is probably from #144476, CC @notriddle @lolbinarycat @GuillaumeGomez. I see that the regression was spotted by the perf test suite, but probably not to the degree that I'm hitting.

I tried creating a more minimal reproducer for this, but that was kinda hard, since it's a performance thing, so it only really shows up in larger cases :/.

I did try looking at Activity Monitor, it looks like often there's only a single rustdoc process consuming CPU, and only intermittently, so there might be some global locking going on? fseventsd also seemed very active, but that might be normal, idk.

Activity

  1. added
    T-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.
    I-compiletimeIssue: Problems and improvements with respect to compile times.
    C-bugCategory: This is a bug.
    on Sep 22, 2025
  2. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Sep 22, 2025
  3. added this to the 1.91.0 milestone on Oct 1, 2025
  4. removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Oct 5, 2025
  5. apiraino commented on Oct 7, 2025

    @apiraino
  6. fmease commented on Oct 7, 2025

    @fmease
  7. added and removed
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Oct 7, 2025
  8. 54 remaining items

  9. TennyZhuang commented on May 11, 2026

    @TennyZhuang
    Contributor

    I have a synthetic reproducer that appears to capture the large-workspace rustdoc/search-index regression shape from this issue, without depending on the full objc2 workspace.

    Caveat: this is a synthetic workload intended to stress cross-crate rustdoc search/index merging via many public items and cross-crate re-exports. It reproduces the measured regression shape locally, but maintainers should still validate whether it matches the real-workload behavior they care about.

    Host triple: aarch64-apple-darwin (macOS 26.4.1, Apple Silicon)
    Target triple: aarch64-apple-darwin (default host target; no --target flag was passed)

    Reproducer shape

    Generator: python3 gen_synth_ws_v2.py 100 100 synthetic-ws-large

    Workspace shape:

    • 100 crates, 100 generated item groups per crate, about 40,000 public items total
    • fan-in/fan-out dependency graph with seed 42
    • 5 core crates with no dependencies
    • 15 mid crates, each depending on 2-3 core crates
    • 80 leaf crates, each depending on 2-4 mid crates
    • each crate performs cross-crate pub use re-exports from all dependencies to increase search-index merge pressure

    All measurements were clean builds using separate target directories.

    Commands

    # pre-regression
    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
    
    # post-regression
    rm -rf target-post-reg
    /usr/bin/time -p cargo +nightly-2025-08-20 doc --workspace --target-dir target-post-reg
    
    # current nightly, default path
    rm -rf target-current-plain
    /usr/bin/time -p cargo +nightly doc --workspace --target-dir target-current-plain
    
    # current nightly, mergeable-info path
    rm -rf target-current-mergeable
    /usr/bin/time -p cargo +nightly doc --workspace --target-dir target-current-mergeable -Zrustdoc-mergeable-info

    Timings

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

    The user / real ratio drops from about 3.8x before the regression to about 1.2x after it, which is consistent with this issue's observation that the slow path appears much more serialized. This is an inference from /usr/bin/time output, not direct process sampling.

    Artifacts

    Public gist with the generator, rerun instructions, raw timing logs, and checksum manifest:
    https://gist.github.com/TennyZhuang/cb57391783e5ef43aadcfc88faf84a93

    MANIFEST.txt SHA-256:
    0c2583496d2fa0804d264c1c8feaaebca0955c00d567bc7ceb7dd9963f8045c0

  10. SimonSapin commented on Jun 30, 2026

    @SimonSapin
    Contributor

    Documenting Servo (1839 crates) with rustdoc 1.95.0 on a fast 2026 laptop takes 62 minutes. Compiling takes 2.5 minutes.

  11. taladar commented on Jul 5, 2026

    @taladar

    I am running into this on stable rustdoc 1.96.1 more and more too where documenting the whole workspace not only takes hours (many, many times more than compiling it does), it also seems to trigger entire rebuilds quite often despite me using a separate target dir for the doc run in my pre-commit hook. It might also be my imagination but it seems to take longer to do it all on an existing target dir than on a freshly deleted one (when it does decide to do all dependencies again).

  12. egrieco commented on Aug 2, 2026

    @egrieco

    Everyone is talking about large workspaces, but building local docs is also agonizingly slow on small projects. We're back to "I guess I'll go grab lunch/dinner while docs build."

    It looks like there is progress on related issues. Definitely looking forward being able to use local docs once again. Currently local-first dev for Rust projects is non-viable.

  13. taladar commented on Aug 2, 2026

    @taladar

    This seems to be mostly that issue nightly already has some options to fix where it regenerates the search index after every single crate, reading sometimes 100s of MB, adding the one crate, then writing it again. On nightly cargo docs there seem to be options to only do it once at the end.

  14. GuillaumeGomez commented on Aug 2, 2026

    @GuillaumeGomez
    Member

    Everyone is talking about large workspaces, but building local docs is also agonizingly slow on small projects. We're back to "I guess I'll go grab lunch/dinner while docs build."

    It looks like there is progress on related issues. Definitely looking forward being able to use local docs once again. Currently local-first dev for Rust projects is non-viable.

    That's new. Do you have a repo so we can check?

  15. ijackson commented on Aug 4, 2026

    @ijackson
    Contributor

    That's new. Do you have a repo so we can check?

    I don't think it is new. The behaviour on stable is O(n^2) in the number of crates in the dependency stack, not the workspace, with large constants of proportionality.. Even a small crate will take a long time to do a from-scratch docs build if there are lots of dependencies.

    Workspace size is relevant because in large workspace editing a lower-level crate can cause many rebuilds, and in that case the performance is O(size of workspace * total number of dependencies) which is also often unacceptable.

    Trivial package with many dependencies, docs build time regresses 6x since 1.90.0

    Test package

    Cargo.toml

    [package]
    name = "foo"
    version = "0.1.0"
    edition = "2021"
    rust-version = "1.90.0"
    
    [dependencies]
    arti-client = { version = "0.43", features = ["full"] }
    

    main.rs

    fn main() {}
    

    Docs build time from clean tree with current stable on my Framework 13 AMD (not a slow machine):

    Commands (rustc 1.97.1 (8bab26f 2026-07-14)):

    cargo +nightly update # to get MSRV-aware lockfile
    cargo --locked fetch
    cargo clean
    time cargo +stable --locked doc
    

    Timing output

    real    7m9.402s
    user    12m14.385s
    sys     2m43.685s
    

    Docs build time in 1.90.0, before the regression

    cargo clean
    time cargo +1.90.0 --locked doc
    
    real    1m11.467s
    user    10m40.859s
    sys     1m32.634s
    

    Docs build time with -Z rustdoc-mergeable-info

    cargo clean
    time cargo +nightly --locked doc -Z rustdoc-mergeable-info
    
    real    0m53.668s
    user    8m14.234s
    sys     1m13.042s
    

    That's with 1.99.0-nightly (dc3f851 2026-07-26).

    Conclusion

    We should stabilise rustdoc-mergeable-info making it the default.

    The primary use case for cargo doc is precisely local-first workfllows, where 1.91 onwards are afflicted by this critical perf regression. If there are bugs in rustdoc-mergeable-info they're probalby preferable to the status quo.

  16. GuillaumeGomez commented on Aug 4, 2026

    @GuillaumeGomez
    Member

    I don't think it is new. The behaviour on stable is O(n^2) in the number of crates in the dependency stack, not the workspace, with large constants of proportionality.. Even a small crate will take a long time to do a from-scratch docs build if there are lots of dependencies.

    So that's not a small project.

    We should stabilise rustdoc-mergeable-info making it the default.

    The primary use case for cargo doc is precisely local-first workfllows, where 1.91 onwards are afflicted by this critical perf regression. If there are bugs in rustdoc-mergeable-info they're probalby preferable to the status quo.

    Thank you random person on the internet for telling us what is already written in this discussion multiple times and explaining us how to fix the situation even though we've been working on it for months.

  17. egrieco commented on Aug 4, 2026

    @egrieco

    That's new. Do you have a repo so we can check?

    Yes free-launch (repo). It's a little hobby project. I haven't pushed recent changes, but the version that is up (v0.2.9 02e1006) demonstrates this issue.

    time cargo doc
    cargo doc  1286.16s user 541.42s system 145% cpu 20:54.58 total
    

    The behaviour on stable is O(n^2) in the number of crates in the dependency stack...

    This tracks with the fact that the first ~300/1043 docs build very quickly while ~600+ start going slower and slower.

    While 1043 total deps might seem big, there are only ~25 direct dependencies (a few could be eliminated). I'd consider this a small Rust project as opposed to something like Servo, which is truly large.

    The bigger issue is that building docs shouldn't take this long. It seems like compiling should always take longer than building docs, but right now building docs takes ~10x longer than a full build:

    time cargo build --release
    cargo build --release  1478.88s user 139.41s system 1134% cpu 2:22.69 total
    

    Interestingly, the doc build lists 1043 units, while the actual build lists 598. I'm guessing that's due to disabled features being documented.

    I do understand that the fix is in progress, and am grateful for the efforts of those working on the fixes. I think the frustration here is that this is a serious regression that occurred in 1.91 and is still an issue in 1.99. I'd tend to agree that:

    If there are bugs in rustdoc-mergeable-info they're probalby preferable to the status quo.

    Please take all of the interest and discussion here from "random people on the internet 😃" in the best light. We're only keeping pressure on because of how important and useful Rust is to us all. We're grateful for all of the Rust team's work for an outstanding language and toolchain.

  18. GuillaumeGomez commented on Aug 4, 2026

    @GuillaumeGomez
    Member

    If there are bugs in rustdoc-mergeable-info they're probalby preferable to the status quo.

    Well, it's wrong. It means stabilizing new CLI options, and as we discovered in the recent weeks, it could be simplified greatly, and partially removed. Also, adding new CLI options means that cargo needs to be updated, but also all other build tools which use rustdoc. All this is a nightmare for both sides. For now, you can use the workaround provided in the first comment of this issue.

    We're only keeping pressure on because of how important and useful Rust is to us all.

    Keeping pressure on a project (or on a team or an individual) is never a good idea. As much as you love Rust, this kind of behaviour only tends to create tension and frustration on both sides.

  19. added a commit that references this issue on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-rustdoc-searchArea: Rustdoc's search featureC-bugCategory: This is a bug.E-needs-mcveCall for participation: This issue has a repro, but needs a Minimal Complete and Verifiable ExampleI-compiletimeIssue: Problems and improvements with respect to compile times.P-highHigh priorityS-has-bisectionStatus: A bisection has been found for this issueT-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.T-rustdoc-frontendRelevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output.perf-regressionPerformance regression.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions