9 ms·
I know it's early days on this, but compilation speed is the downside to Rust IMO. Having worked in a Rust monorepo, my number one complaint was compilation spe
by insanitybit 3y ago
I know it's early days on this, but compilation speed is the downside to Rust IMO. Having worked in a Rust monorepo, my number one complaint was compilation speed. It made CI/CD more expensive and it could really slow down dev time if we needed to remove the cache (happened sometimes - not cargo's fault, actually it's a docker bug, but still).
Glad to see this progress.
- lucasyvas 3y agoAs someone who has only done small projects in Rust, I'm curious how many LoC are we're talking? And were you splitting your project into crates where it made sense?
- eminence32 3y agoOne thing I've observed is that every smallish projects (~10k LoC) can take a while to build if you're working on slow network filesystems. When using local disks, a 10k LoC project takes ~5 seconds to build When using network FS, the same project takes ~23 seconds to build
- the8472 3y agoThat doesn't seem particularly surprising. Lots of software is slow when your storage is slow.
- eminence32 3y agoYou're right that some slowdown is expected, but for me personally I hadn't realized how bad this particular FS was, nor had I expected how much it impacted build times
- lolinder 3y agoWouldn't this be true of any compiler? Do other compilers have optimizations that avoid excess disk usage when on a slow file system?
- eminence32 3y agoYes, I think that's right, but I don't have any data to compare rust to other compilers.
- ragnese 3y agoI wouldn't be surprised if Rust/Cargo does more disk IO than other build tools, though. Rust does a lot of compile time code gen and caches a lot of stuff on disk.
- insanitybit 3y agoFWIW we did this to significantly reduce storage usage strip = "debuginfo" This was a ~20x reduction in size, 279M -> 19M. If you have slow storage it could really help performance (don't recall, personally).
- eminence32 3y agoGood hint, thank you. I'm trying this out and I do see an improvement in performance. The ~23 second build now takes about ~14 seconds
- insanitybit 3y agoHell yeah! I'm so glad I could help, that's a big win. FWIW it does break debuggers since you won't have the symbols. Just comment it out when you need a build that has all of that info.
- insanitybit 3y agoWe split each service into crates, plus some libraries. There were some native dependencies as well, which could really impact compile times, as well as some codegen for things like protobuf. From a quick tokei, looks like 49kloc of Rust.
- zozbot234 3y agoRust-analyzer is even more of a resource hog than rustc itself. Not sure how directly applicable this work might be, but hopefully we'll see big improvements there as well. It's something that's clearly needed for state-of-the-art IDE support.
- sigmonsays 3y agoI agree. rust-analyzer often eats up more ram and cpu than all my web browser tabs (firefox).
- chubot 3y agoThat’s interesting/surprising. I remember this in the Eclipse days, and it was often attributed to Java’s allocation-heavy style, garbage collection, and lack of value types Also Java style of tiny classes and tiny files. It’s an issue on both the implementation side and the thing-being-implemented I would have thought Rust would be better on both fronts. How many lines are the Rust codebases and their dependencies?
- pdimitar 3y agoTo be fair, I don't care. RA is extremely valuable, and I am _not_ one of the people who think 16GB of RAM and 250GB of SSD is good for a programmer machine.
- echelon 3y agoWe're using a Rust monorepo too. async-stripe takes over two minutes to build due to codegen. We're considering switching to dolladollabills. Our core API server takes a minute to build, and we have about a dozen services and command line apps, a bunch of little shared library crates, two desktop apps, and a Bevy app. Our Github actions docker build takes ~10 minutes if you don't include the tests, but we're starting to shave off more time. (Our monorepo is 105589 Rust LOC total)
- lucasyvas 3y ago> We're considering switching to dolladollabills I thought this was a joke. That has to be one of the best library names I've ever seen.
- FridgeSeal 3y ago> async-stripe takes over two minutes to build due to codegen. We're considering switching to dolladollabills. Ooohh interesting. We also use async-stripe, definitely going to have to check out dolladollabills though. Also in the Rust monorepo camp, our proof release takes ~5 mins from clean, tests are about 6 mins. We’ve invested a bit of effort getting our build-time down: don’t build in a docker container, we just copy the final artefact in-this wiped the most time of our builds. More parallel codegen units too.
- rayiner 3y agoIt’s unlikely that it’ll ever get dramatically better. It’s already been heavily optimized, and the Rust compiler now has more parallelism than pretty much any other mainstream compiler. Language design choices make Rust more challenging to compile than a language (like Go) that is specifically designed for fast compilation.
- kaba0 3y agoIt’s not really that go is better designed for fast compilation - it is just a plain language where the compiler can just spit out vaguely optimized code, and call it a day. Rust’s unique feature itself fundamentally depends on extensive static analysis. It’s not a design choice, it is pretty much what Rust is - a low-level language without a GC that is still memory safe. The price for that is hefty compile times.
- mirashii 3y agoProfiling the compilation process suggests that this isn't the case. Rust's higher level passes are rarely the dominant part of execution time. Check out https://github.com/lqd/rustc-benchmarking-data/tree/main/results/round-16-self-profile-opt/flamegraph https://github.com/lqd/rustc-benchmarking-data/tree/main/res... and the other benchmarks in that repository for some data on how real world crates compilation times are spent. You'll find that backend code generation and optimization dominate most crates compile times. There are a few exceptions: particularly macro heavy crates, a couple crates with deeply nested types that hit some quadratic behavior in the compiler. But overall, the backend is still the largest piece.
- kaba0 3y agoThen there is an open niche for a “development mode”, that outputs barely optimized binaries with proper error handling, fast. (I do know about debug, etc). I think Zig is correct in having different modes.
- littlestymaar 3y ago
- runeks 3y agoHow slow are we talking here? How many minutes to build your monorepo? Don't hesitate to be brutally honest — nothing can shock me as my go-to compiler is GHC.
- insanitybit 3y agoIt was over a year ago so it's a bit hard to recall... Maybe 20 minutes clean? 1 or 2 minutes for cached. Things have probably improved since then but idk. We did stuff like protobuf, we had a few proc-macros of our own, plenty of serde, and I think ~3 native dependencies (zstd, librdkafka, something else I don't recall). The native dependencies could be brutal, it caused long serial stalls, if I recall correctly. Linking took up a lot of time as well, but I forget why we didn't use mold, there was a reason at the time... but, again, over a year ago. Here's the code: https://github.com/grapl-security/grapl/tree/main/src/rust https://github.com/grapl-security/grapl/tree/main/src/rust
- Dowwie 3y agowhat was the caching strategy?
- insanitybit 3y agoWe did our builds in docker, for various reasons. So we relied on the docker buildx cache and some other tricks that I don't recall because I didn't work a ton on the build system.
- Yoric 3y agoOh... Docker-based Rust builds are extremely slow in my experience. I seem to remember that caching was really, really bad.
- insanitybit 3y agoDocker isn't the issue. I just did a clean build, 19 minutes 44 seconds (with a ~year old compiler though).
- stjohnswarts 3y agoI never understood the "gotta clean cache every time" with CI/CD. I'm sure it makes sense sometimes but you can make a compromise. I worked at two places where I only clean up our c++ caches on the build systems on the weekend. We did that "just in case" caching was hiding a problem, but would only have a "small 1 week" set back at most. We were not on heavy release cycles though so we could afford that. We never had a single problem traced back to the cache or build hiding something. This was for internal company software. Not sure why people are willing to pay the cost for a full rebuild every time if that full rebuild takes a long time (rust or c++). I'm sure there are cases for it though, just that it doesn't have to be done everywhere.
- insanitybit 3y agoIt's not that you have to, it's that you have many different builds that are going to stomp on each other's caches, plus your build services are often ephemeral - especially since I was at a small startup where we wanted to shut systems down overnight to keep the money.
- adastra22 3y agoI’m continuously amazed that this opinion is so prevalent. I maintain both a C++ and a Rust project, and incremental compile times on Rust are vastly better. It is, I believe, one of the fastest statically typed compiled languages. Go is faster, but I think that’s it. What improvements are you expecting?
- metaltyphoon 3y agoC# AOT seems to be faster than Rust too.
- pdimitar 3y agoDon't forget OCaml, that one has a scary fast compiler.
- jicea 3y agoI really disagree here: I'm a maintainer of a medium sized open source Rust project [1] and I'm always surprised by Rust compilation time speed (local). On a MacBook Pro, it's a matter of seconds, in debug. Release compilation and CI/CD are slower, but, since the beginning of my Rust journey (2 years ago), Rust compilation seems just very fa... To balance / explain my point: - my day work is Java / Kotlin with Gradle. Now, we can talk about glacial compilation times - on my open source Rust project, we try to minimise dependencies, don't use macros (apart derive[Debug, Clone] etc...), and have a very moderate generics usage If you take the time to `cargo build` my project, I'll be happy to have feedbacks on compilation times [1]: https://github.com/Orange-OpenSource/hurl https://github.com/Orange-OpenSource/hurl
- insanitybit 3y agohttps://github.com/grapl-security/grapl/ https://github.com/grapl-security/grapl/ I just did a clean build `cargo build`, 19 minutes 44 seconds. I added 1 line (`dbg!("foo")`) and it took 14.76s
- jicea 3y agoIn grapl/src/rust: - cloc shows that there are ~70,000 lines of Rust - with `cargo tree`, I see that the project depends on ~600 crates In my toy project: - cloc shows that there are ~40,000 lines of Rust - with `cargo tree`, I see ~40 crates I don't know the scope of grapl, but 600 (transitives) crates seems a lot to me. Maybe that explains why this particular build is so long. I haven't managed to build it (seems to have prerequisites on proto buffer stuff).
- insanitybit 3y agoYes, it'll require a protoc installation to actually compile, as well as some native dependencies. Naturally more crates means more time on compilation. Grapl is a pretty large project, lots of services that do different things, so it isn't too surprising that it has a lot of dependencies relative to what I assume is a more tightly scoped project. For example, Grapl talks to multiple different databases, AWS services, speaks HTTP + JSON and gRPC (with protobuf), has a cli, etc etc.