Repository navigation
Tracking issue for speeding up rustc via its build configuration #103595
Description
Activity
- addedT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCWG-compiler-performanceWorking group: Compiler PerformanceWorking group: Compiler Performance
on Oct 26, 2022 Another thing to try that was brought up on zulip is aligning the text segment to 2MB so it can be loaded in a way that transparent huge pages kick in, but I'm not 100% sure if this even works yet, last time I checked large page support in the page cache was still a WIP and I haven't seen it in release notes.
An update for windows:
- I'm trying ThinLTO for
rustc_driver.dllin Enable ThinLTO for rustc on x64 msvc #103591 as local results looked interesting enough (lower than what we saw onx86_64-unknown-linux-gnubut still quite good). - I don't think we actually can ThinLTO LLVM separately on MSVC easily today: that is done by linking to LLVM as a shared library, which is not supported on
x86_64-pc-windows-msvc. It's likely possible to do in the future, but is more involved than a build config tweak.
Reacted by Nicholas Nethercote- I'm trying ThinLTO for
Another thing to try that was brought up on zulip is aligning the text segment to 2MB so it can be loaded in a way that transparent huge pages kick in
Given that it's not even clear that this works, let's leave it off this issue for now.
It looks like file-backed huge pages are supported now. https://www.kernel.org/doc/html/latest/filesystems/proc.html#meminfo
FileHugePages
Memory used for filesystem data (page cache) allocated with huge pages
FilePmdMapped
Page cache mapped into userspace with huge pagesI think it was introduced with this one torvalds/linux@793917d so it needs at least 5.18
It also depends on filesystem support.
I read and actually checked that rustc links dynamically against rustc_driver. The same article said we dlopen codegen backends. Isn't there a way for the common case, a static binary: rustc + rustc_driver + LLVM?
We could do that in theory, but I'm not sure if it would be that useful. Static linking has some benefits, but mostly only for tiny crates, the diminishing returns start to kick in early.
rustcis basically a "one-liner" that calls into the entrypoint ofrustc_driver, and that is now LTO-optimized.I would enable LTO over the full binary. Startup time may also be better.
Well, the "full binary" is one function call into
rustc_driver:) But it's true that I haven't tried benchmarking static linking on top of the current LTO optimizedlibrustc_driver. I'll try it, to see if static linking + LTO could provide substantial benefits.Shipping a statically linked
rustcwould probably only be possible on some OSes (Linux), and it would increase the size of the distributed artifacts by a nontrivial amount.My LLVM folder is full of large statically linked LTO'd binaries (OSX).
Could you also statically link in the LLVM backend?
In theory, yes. In practice, I'm not sure if our current build system supports it (will check).
No worries.
-rwxr-xr-x 1 xxx staff 129M Jul 28 18:44 clang-15It only links against system libraries and no LLVM libraries.
I'm not sure if it helps, but on Windows LLVM can be built with a different allocator using the
-DLLVM_INTEGRATED_CRT_ALLOC=path/to/allocatorflag (supports rpmalloc|mimalloc|snmalloc). However I tried doing that a few months ago, and while the llvm builds seemed to work fine,rustc_llvmfailed to build using a version of LLVM built with mimalloc or snmalloc (I didn't end up testing rpmalloc at the time). The errors at the time were: for snmallocerror: renaming of the library 'INCLUDE' was specified, however this crate contains no '#[link(...)]' attributes referencing this libraryfor mimalloc the error was the same, except it wasFinstead ofINCLUDEThe LLVM pr (https://reviews.llvm.org/D71786) also showed some pretty major performance gains when it was implemented.
Reacted by Rémy Rakic and Per Vognsen4 remaining items
I think that we could start with the compiler (and its stdlib),
Doesn't the compiler link the same stdlib it uses to build programs?
Do you have any ideas where we could start using x86 v2 CPU features?
Adopting the utf8 validation impl from simdutf8. Other than that it'll need some exploration. Maybe the stdsimd folks have some ideas on tap.
There's always a difference between "if I had all the most recent CPU features I could..." and more modest optimizations 😅Maybe rustc hash could be replaced with a different mixing function? ... odd, I can't find the feature level of the PCLMULQDQ instruction.
Reacted by Jakub Beránek and Jiahao XUDoesn't the compiler link the same stdlib it uses to build programs?
IIRC it doesn't, it has its own copy. Conceptually, it needs to be able to use to add any (target) stdlib to the resulting program to cross-compile. But I might be wrong.
The targets on the Platform Support page look like legit target triples. Could you encode v4 in triple and ship two Linux versions for x86?
In theory yes, but I'm not sure if it's the best solution. Maybe we could bump the defaut target to v2/v3 and keep an unoptimized v1 target for people with old CPUs. In any case, maintaining a target is not for free, so maybe there are better solutions.
To clarify, it's a very different thing to ship a v2 compiler and to make the x86 Linux target v2 by default. We're really only considering the first thing for now.
Shipping a highly tuned v4 compiler with -mtune=icelake should give some speedup and you can use current cpu features: AVX512, PCLMULQDQ, ..
Haswell was launched June 4, 2013.
x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2 x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VLYes, our measurements show that v3 produces ~1-3% speedup for the compiler. But on it's own, that hasn't been worth it to use it so far, because there is non-trivial maintenance costs for doing that, plus we would drop some existing users. We'll need to tread carefully.
AVX-512 is not really viable for broad use because AMD only started shipping it recently and intel has only shipped it to some of their market segments (workstation/server chips) and even disabled it on some recent chips due to inconsistencies between P and E cores.
AVX2 has a much larger user base.See https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=linux
99% for SSE42 (~v2)
93% for AVX2 (~v3)
6.5% for AVX512 (~v4)Reacted by scottmcmAttempted to tune ColdFuncOpt option for PGO (llvm/llvm-project#69030) #132779 to decrease file size, but sadly, no good results. Possible reasons: current linux dist uses bolt on top of pgo, which increases size; i forgot to apply the same optimization for libllvm (applied only for rustc_driver).
With the recent-ish promotion of
aarch64-apple-darwinto tier 1, and all recent apple hardware being shipped with architecture, will this issue be updated to add (or replace) that as a Mac target for optimization? It's not clear to me what the optimization status is for that toolchain, and this seemed the best place to attempt to find it.It has LTO and jemalloc, but not the 1CGU config. It’s not going to be earth shattering or anything, but I’ll make some local tests and a PR for try builds soon, to see the potential improvements there.
Reacted by David Hewitt, Jiahao XU and Jon GjengsetI’ll make some local tests and a PR for try builds soon
done in #133747 -- I've updated the OP now that it has merged.
There are several ways to speed up rustc by changing its build configuration, without changing its code: use a single codegen unit (CGU), profile-guided optimization (PGO), link-time optimization (LTO), post-link optimization (via BOLT), and using a better allocator (e.g. jemalloc or mimalloc).
This is a tracking issue for doing these for the most popular Tier 1 platforms: Linux64 (
x86_64-unknown-linux-gnu), Win64 (x86_64-pc-windows-msvc), and Mac (x86_64-apple-darwin, and more recentlyaarch64-apple-darwin).Items marked with [2022] are on the Compiler performance roadmap for 2022.
Single CGU
Benefits: rustc is faster, uses less memory, has a smaller binary.
Costs: rustc takes longer to build.
rustcwith a single CGU on x64 Linux #115554, merged 2023-10-01.rustcwith 1CGU onx86_64-pc-windows-msvc#112267, merged 2024-03-12.rustcwith 1CGU onx86_64-apple-darwin#112268, merged 2024-03-12.rustcwith 1 CGU onaarch64-apple-darwin#133747, merged 2024-12-03.PGO
Benefits: rustc is faster.
Costs: rustc takes longer to build.
Other PGO attempts:
libstd: Apply PGO to libstd on CI #97038, no speed-up measured.LTO
Benefits: rustc is faster.
Costs: rustc takes longer to build.
x86_64-apple-darwin#103647 and Re-enable ThinLTO for rustc onx86_64-apple-darwin#105845, merged 2022-12-19.This is all thin LTO, which gets most of the benefits of fat LTO with a much lower link-time cost.
Other LTO attempts:
rustdoc: [perftest] Use LTO for compilingrustdoc#102885, no speed-up measured.rustc#103453, no speed-up measured, large CI build cost.BOLT
Benefits: rustc is faster.
Costs: rustc takes longer to build.
librustc_driver.sowith BOLT #116352, merged 2023-10-14.Bolt only works on ELF binaries, and thus is Linux-only.
Instruction set
Benefits: rustc is faster?
Costs: rustc won't run on old CPUs.
Linker
Benefits: rustc (linking) is faster.
Costs: hard to get working.
lldby default onx86_64-unknown-linux-gnu:rust-lldon nightlyx86_64-unknown-linux-gnu#124129, merged 2024-05-17Better allocator
Benefits: rustc (linking) is faster.
Costs: rustc uses more memory?
Note: #92249 and #92317 tried using two different versions of mimalloc (one 1.7-based, one 2.0-based) instead of jemalloc, but the speed/memory tradeoffs in both cases were deemed inferior (the max-rss regressions expected to be fixed in the 2.x series still exist as of 2.0.6, see #103944).
Note: we use a better allocator by simply overriding malloc/free, rather than using
#[global_allocator]. See this Zulip thread for some discussion about the sub-optimality of this.About tracking issues
Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.