The main issue here is: - in rust one semantic compilation unit is one crate - in C one semantic compilation unit is one file There are quite a bunch of benefits in the rust approach, but also drawbacks, like huge projects have to be split into multiple workspaces to maximize parallel building. Oversimplified the codegen-units setting tells the compiler into how many parts the compiler is allowed to split the a singl…
Rust has a great compromise between crate and file: module. I wonder why that's not the compilation unit?
Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
41–50 of 89 posts
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#42Earlier quoted context omitted.
C++ is fast in theory, but if they can't get C++ compiler (LLVM) to squeeze any juice from CPU, then what's the value of that language from a software engineering viewpoint. Hopefully, you can see why this reasoning is a problem. The main stumbling point being compilation speed != runtime speed.
I have been using make's -j flag to compile C++ projects with great success. The main point being, Rust focuses on the wrong type of optimizations.
cargo has the `-j` flag and defaults it to #cpus (logical cpus), so it's by default using the most times most optimal choice there
And this will parallelize the compilation of all "jobs", roughly like with make. Where a job is normally (oversimplified) compiling one code unit into one object file (.o).
And cargo does that too.
The problem is that where rust and C/C++ (and I think D) etc. set code unit boundaries differ.
In rust it's per crate. In C/C++ it's (oversimplified!!) per .h+.c file pair.
This has drawbacks and benefits. But one drawback is that it parallelizes less good. Hence why rust internally split one "semantic code unit" into multiple internal code units passed to LLM. So this is an additional level of parallelism to the -j flag.
In general this works fine and if people speak about rust builds being slow it is very rarely related to this aspect. But it puts a limit onto how much code you want in a single crate which people sometimes overlook.
But in the OP article they did run into it due to placing like idk 100k lines of code (with proc macors maybe _way_ more then that) into a single crate. And then also running into a bug where this internal parallelization somehow failed.
Basically imagine 100k+ line of code in a single .cpp file passing `-j` to the build to it will not help ;)
I think one important takeaway is that it could make sense to crate awareness about this by emitting a warning if your crate becomes way to big with a link to a in-depth explanation. Through practically most projects either aren't affected or split it into crates way earlier for various reasons (which sometimes include build time, but related to caching and incremental rebuilds, not fully clean debug builds).
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#43The main issue here is: - in rust one semantic compilation unit is one crate - in C one semantic compilation unit is one file There are quite a bunch of benefits in the rust approach, but also drawbacks, like huge projects have to be split into multiple workspaces to maximize parallel building. Oversimplified the codegen-units setting tells the compiler into how many parts the compiler is allowed to split the a singl…
Rust has a great compromise between crate and file: module. I wonder why that's not the compilation unit?
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#44Earlier quoted context omitted.
Yeah, I read that part too late. In that case it seems that there's indeed a lot of overhead when building many crates from a cold-start, but it pays off in wall time and can probably save resources in incremental builds.
Yes. We found both cold and incremental builds sped up. The incremental builds were the main win -- small changes to the SQL can sometimes complete in seconds for what used to be a full recompilation.
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#45The main issue here is: - in rust one semantic compilation unit is one crate - in C one semantic compilation unit is one file There are quite a bunch of benefits in the rust approach, but also drawbacks, like huge projects have to be split into multiple workspaces to maximize parallel building. Oversimplified the codegen-units setting tells the compiler into how many parts the compiler is allowed to split the a singl…
Agreed, seems like there are some rustc performance bugs at play here.
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#46Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#47> despite having a 64-core machine with 128 threads, Rust barely puts any of them to work. Rust is fast in theory, but if in practice they can't even get their compiler to squeeze any juice from the CPU, then what's the value of that language from a software engineering viewpoint?
It's a single Rust file with 100k lines of code spit out by a code generator.
codegen in the OP article is machine gode generation (i.e. running LLVM)
It's semantically kinda like having a single 100k file, but because rust knows it often generates huge "files" there is a splitting step, somewhere between parsing AST and generating machine code (I think after generating MIR but not fully sure). And the codgen-unit setting is in how many parts rust is allowed to split a thing which semantically is just one code unit. By default for release builds 16 (and as it can affect perf. of generated code it's not based on #cpus). But in there case there seems to be a bug which makes it effective more like 1! Which is much worse then it should be. (But also the statistic they show aren't sufficient to draw too much conclusions).
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#48> Given that we now fully utilize 128 threads or 64 cores for pretty much the entire compile time, we can do a back of the envelope calculation for how long it should take: 25 min / 128 = 12 sec (or maybe 24 sec since hyper-threads aren't real cores). Yet it takes 170s to compile everything. Amdahl’s Law would like to have a word.
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#49> Given that we now fully utilize 128 threads or 64 cores for pretty much the entire compile time, we can do a back of the envelope calculation for how long it should take: 25 min / 128 = 12 sec (or maybe 24 sec since hyper-threads aren't real cores). Yet it takes 170s to compile everything. Amdahl’s Law would like to have a word.
(Disclaimer I am the author of the article and I am quite familiar with the law)
Re: Cutting down Rust compile times from 30 to 2 minutes with one thousand crates
#50> We're using rustc v1.83, and despite having a 64-core machine with 128 threads, Rust barely puts any of them to work. > That’s right — 1,106 crates! Sounds excessive? Maybe. But in the end this is what makes rustc much more effective. > What used to take 30–45 minutes now compiles in under 3 minutes. I wonder if this kind of trick can be implemented in rustc itself in a more automated fashion to benefit more projec…
It partially is, with codegen units. The problem is that you can't generally do that until codegen time, because of circular dependencies.