Skip to content

Flatten all -L search paths into a single list of files - #158823

Open
Kobzol wants to merge 1 commit into
rust-lang:mainfrom
Kobzol:flatten-search-paths
Open

Flatten all -L search paths into a single list of files#158823
Kobzol wants to merge 1 commit into
rust-lang:mainfrom
Kobzol:flatten-search-paths

Conversation

@Kobzol

@Kobzol Kobzol commented Jul 5, 2026

Copy link
Copy Markdown
Member

View all comments

This is an optimization that mostly targets the new Cargo build dir layout.

Before, Cargo usually used to pass rustc a single -L path to a directory containing potentially a large number of .rlib or other dependency paths. Rustc is optimized for this, and does a preprocessing step, where it preloads all files from this directory into a sorted vector, in which it then performs binary search to look for files having a given prefix and postfix.

With the new build dir layout, this changes, and Cargo will pass potentially many (even hundreds, if your crate has many dependencies) -L directories, where each directory will usually have only 1-2 files. This is not ideal for the current rustc search implementation, because the old preprocessing isn't really worth it when the -L directory typically only has a single file, and because rustc will do a lot of work per each -L directory in the lookup phase, including some quadratic (O(n^2)) work.

With the large-workspace stress test from rustc-perf, where the final binary has ~1000 total and ~500 direct dependencies:

  • With the old build dir layout, rustc does 4274 calls to FilesIndex::query
  • With the new build dir layout, it does 1938314 calls to FilesIndex::query. Not ideal :)

This PR modifies the logic so that instead of going through all -L directories one by one when we are looking for a specific dependency, we pre-gather all files from all passed -L directories at the start, and sort them all together. Then, in the lookup phase, instead of performing <number of -L dirs> * 4 (.rmeta, .rlib, etc.) searched, we only perform the 4 searches across all files. This gets rid of the O(n^2) behavior.

Further improvements could be made, e.g. sort the files just once and then filter it for for both host and target filesearchs. I alsothought about pre-filtering the files further, e.g. based on their kind, but that is not worth it in usual situations, where ~all of the deps will be .rlibs or .rmetas anyway. What might work is pre-filtering based on their actual names (we strip known prefixes from them and then search based on the names alone, in a hashmap or something?), but that can be a follow-up.

Diff vs parent. of #159857: https://perf.rust-lang.org/compare.html?start=1a833e16546c2eb012758ddd499964fd8afee29e&end=6514e2707b7e90fecbc570eeaa36f3780a9b02b4&stat=instructions%3Au

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 5, 2026
@rustbot

rustbot commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

r? @mati865

rustbot has assigned @mati865.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 75 candidates
  • Random selection from 21 candidates

@Kobzol
Kobzol marked this pull request as draft July 5, 2026 16:48
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 5, 2026
@Kobzol

Kobzol commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

Sorry, meant to open this as a draft, but missclicked.

r? @ghost

@rust-log-analyzer

This comment has been minimized.

@petrochenkov petrochenkov self-assigned this Jul 5, 2026
@petrochenkov

Copy link
Copy Markdown
Contributor

This generally makes sense to me.

Cargo will pass potentially many (even hundreds, if your crate has many dependencies) -L directories

Was this considered by cargo team when the new build dir layout was designed? Why wasn't it considered an issue?

@Kobzol

Kobzol commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

I'm sure that it was considered, though I don't know if there were any alternatives. CC @ranger-ross @epage if you have more context.

Recently we identified some optimizations that can be made to reduce that effect, they are being landed now (rust-lang/cargo#17168).

@Kobzol Kobzol mentioned this pull request Jul 6, 2026
@epage

epage commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Splitting rlibs into unique directories is fairly fundamental to the design. The trivial solution from there is hundreds of -Ls. I thought we had talked about performance implications but I can't find the thread and might be getting mixed up. We had acknowledged this will make Cargo's verbose output longer but we've already done that before with [lints] and --check-cfg so it seems less important to be careful about that. Maybe there are things we can further do (e.g. create a one off directory with symlinks to all of the rlibs) but we hadn't seen any concerns found during testing until we got to bootstrap recently and it seemed like those were being addressed.

@Kobzol

Kobzol commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

I thought about the mega-symlink-dir approach too :) Might be interesting to try, as that might also have some performance implications.

I hope that with rust-lang/cargo#17168 and this PR landing and rust-lang/cargo#17183 being resolved, it will become workable, but we'll have to see how the new build dir layout works in practice to find out.

@Kobzol
Kobzol force-pushed the flatten-search-paths branch from 8bba6cb to 0e1ba38 Compare July 28, 2026 11:42
@Kobzol

Kobzol commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 28, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 28, 2026
Flatten all -L search paths into a single list of files
@Kobzol

Kobzol commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@bors try parent=45bc0d28cc57296e36ef653a442e96367ba73d4a

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 28, 2026
Flatten all -L search paths into a single list of files
@rust-log-analyzer

This comment has been minimized.

@rust-bors

rust-bors Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: a31f58e (a31f58e2ea7fc54ca48521268b73b02ec9202b14)
Base parent: 45bc0d2 (45bc0d28cc57296e36ef653a442e96367ba73d4a)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (a31f58e): comparison URL.

Overall result: ✅ improvements - no action needed

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

@bors rollup=never rustc-perf
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
0.5% [0.4%, 0.7%] 7
Improvements ✅
(primary)
-1.3% [-2.6%, -0.3%] 56
Improvements ✅
(secondary)
-7.5% [-49.2%, -0.3%] 60
All ❌✅ (primary) -1.3% [-2.6%, -0.3%] 56

Max RSS (memory usage)

Results (primary -0.9%, secondary -0.8%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.7% [0.5%, 1.0%] 7
Regressions ❌
(secondary)
1.5% [0.4%, 9.5%] 20
Improvements ✅
(primary)
-0.9% [-2.8%, -0.4%] 121
Improvements ✅
(secondary)
-1.1% [-5.4%, -0.4%] 178
All ❌✅ (primary) -0.9% [-2.8%, 1.0%] 128

Cycles

Results (primary -1.0%, secondary -2.3%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.8% [0.4%, 1.7%] 47
Regressions ❌
(secondary)
1.4% [0.4%, 19.5%] 78
Improvements ✅
(primary)
-1.8% [-5.8%, -0.4%] 109
Improvements ✅
(secondary)
-4.6% [-32.3%, -0.4%] 130
All ❌✅ (primary) -1.0% [-5.8%, 1.7%] 156

Binary size

This perf run didn't have relevant results for this metric.

Bootstrap: 488.239s -> 487.438s (-0.16%)
Artifact size: 388.24 MiB -> 389.11 MiB (0.23%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 28, 2026
@rust-bors

rust-bors Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 6514e27 (6514e2707b7e90fecbc570eeaa36f3780a9b02b4)
Base parent: 83709ee (83709eedfff36840b0749ca429ac43f5479b268f)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (6514e27): comparison URL.

Overall result: ❌✅ regressions and improvements - please read:

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

Next, please: If you can, justify the regressions found in this try perf run in writing along with @rustbot label: +perf-regression-triaged. If not, fix the regressions and do another perf run. Neutral or positive results will clear the label automatically.

@bors rollup=never rustc-perf
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
0.4% [0.2%, 0.6%] 10
Improvements ✅
(primary)
-0.4% [-0.6%, -0.2%] 18
Improvements ✅
(secondary)
-20.1% [-49.2%, -0.0%] 20
All ❌✅ (primary) -0.4% [-0.6%, -0.2%] 18

Max RSS (memory usage)

Results (primary -0.9%, secondary 0.3%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
4.8% [0.8%, 7.1%] 4
Improvements ✅
(primary)
-0.9% [-1.2%, -0.6%] 2
Improvements ✅
(secondary)
-2.0% [-4.7%, -0.4%] 8
All ❌✅ (primary) -0.9% [-1.2%, -0.6%] 2

Cycles

Results (primary -0.8%, secondary -6.7%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.7% [0.5%, 0.9%] 3
Regressions ❌
(secondary)
4.1% [0.4%, 17.0%] 13
Improvements ✅
(primary)
-1.1% [-2.8%, -0.5%] 13
Improvements ✅
(secondary)
-12.2% [-32.8%, -0.6%] 26
All ❌✅ (primary) -0.8% [-2.8%, 0.9%] 16

Binary size

This perf run didn't have relevant results for this metric.

Bootstrap: 491.471s -> 488.53s (-0.60%)
Artifact size: 390.58 MiB -> 390.69 MiB (0.03%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 30, 2026
@Kobzol
Kobzol force-pushed the flatten-search-paths branch from 9aed7c2 to 2702de0 Compare July 30, 2026 11:06
@Kobzol

Kobzol commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

I have some ideas on what to optimize here, but I think that as a baseline, this is good enough.

@Kobzol
Kobzol marked this pull request as ready for review July 30, 2026 11:06
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 30, 2026
@rust-log-analyzer

This comment has been minimized.

@Kobzol
Kobzol force-pushed the flatten-search-paths branch from 2702de0 to 2381c84 Compare July 30, 2026 14:34
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
Comment thread compiler/rustc_codegen_ssa/src/back/link.rs Outdated
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 31, 2026
@Kobzol

Kobzol commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

Thanks, applied the suggested changes.

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 31, 2026
Comment thread compiler/rustc_session/src/filesearch.rs Outdated
@petrochenkov

Copy link
Copy Markdown
Contributor

r=me after addressing #158823 (comment) and squashing commits.
@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 31, 2026
@Kobzol
Kobzol force-pushed the flatten-search-paths branch from b2dd117 to 55500ae Compare July 31, 2026 11:43
@rustbot

rustbot commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@petrochenkov

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-bors Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 55500ae has been approved by petrochenkov

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 31, 2026
@rust-bors

rust-bors Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

⌛ Testing commit 55500ae with merge 6c04025...

Workflow: https://github.com/rust-lang/rust/actions/runs/30669053546

rust-bors Bot pushed a commit that referenced this pull request Jul 31, 2026
Flatten all -L search paths into a single list of files



This is an optimization that mostly targets the new [Cargo build dir layout](https://rust-lang.github.io/rust-project-goals/2025h2/cargo-build-dir-layout.html).

Before, Cargo usually used to pass rustc a single `-L` path to a directory containing potentially a large number of `.rlib` or other dependency paths. Rustc is optimized for this, and does a preprocessing step, where it preloads all files from this directory into a sorted vector, in which it then performs binary search to look for files having a given prefix and postfix.

With the new build dir layout, this changes, and Cargo will pass potentially many (even hundreds, if your crate has many dependencies) `-L` directories, where each directory will usually have only 1-2 files. This is not ideal for the current rustc search implementation, because the old preprocessing isn't really worth it when the `-L` directory typically only has a single file, and because rustc will do a lot of work per each `-L` directory in the lookup phase, including some quadratic (O(n^2)) work.

With the `large-workspace` stress test from rustc-perf, where the final binary has ~1000 total and ~500 direct dependencies:
- With the old build dir layout, rustc does 4274 calls to `FilesIndex::query`
- With the new build dir layout, it does `1938314` calls to `FilesIndex::query`. Not ideal :)

This PR modifies the logic so that instead of going through all `-L` directories one by one when we are looking for a specific dependency, we pre-gather all files from all passed `-L` directories at the start, and sort them all together. Then, in the lookup phase, instead of performing <number of -L dirs> * 4 (.rmeta, .rlib, etc.) searched, we only perform the 4 searches across all files. This gets rid of the O(n^2) behavior.

Further improvements could be made, e.g. sort the files just once and then filter it for for both host and target filesearchs. I alsothought about pre-filtering the files further, e.g. based on their `kind`,  but that is not worth it in usual situations, where ~all of the deps will be `.rlib`s or `.rmeta`s anyway. What might work is pre-filtering based on their actual names (we strip known prefixes from them and then search based on the names alone, in a hashmap or something?), but that can be a follow-up.

Diff vs parent. of #159857: https://perf.rust-lang.org/compare.html?start=1a833e16546c2eb012758ddd499964fd8afee29e&end=6514e2707b7e90fecbc570eeaa36f3780a9b02b4&stat=instructions%3Au
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf-regression Performance regression. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants