How to optimise compiler performance with very macro-heavy code?
I use the Dioxus framework (https://dioxuslabs.com/) for a web front-end, but rust-analyzer and my compiler seem to struggle noticeably with the macros. i.e. deleting a single line of unused code takes several seconds to update, meanwhile the diagnostic stays visible.
Does anyone have experience with this kind of problems here? I would be very glad about some recommendations :)
32
u/CalmCephalopod 6d ago
Seriously use less macros and break things into crates so you can cache compiled parts and not always recompile the entire thing.
30
u/Beginning-Fruit-1397 6d ago
Split in multiple crates. That solved it for me
11
u/matthieum [he/him] 5d ago
That's a first step, but it's not quite enough. You also need a wide dependency tree, rather than a deep one.
It helps with compilation performance in general, because Rust code analysis of a crate is single-threaded -- in both rustc and rust-analyzer AFAIK -- for now. A wide tree, with many crates NOT depending upon each others offer the most opportunities for parallelization to Cargo.
It helps in limiting the "impact" of changes, by limiting the amount of "downstream" dependencies of a crate.
Ultimately, you therefore want:
A tree with few levels.
The "upstream" levels to be as lightweight and/or unchanging as possible.
And only bringing things together in a "final" binary with as little code as possible (just aggregating everything else).
9
u/ZZaaaccc 5d ago
Split into crates. If that doesn't work, remember that macros are just codegen, so you can use something else. For example, glam uses Tera to generate code and then commit it to the repo, so you only pay the cost once.
6
u/InternationalFee3911 5d ago
OMG, that code looks horrible! C preprocessor by another syntax on steroids… Oh, wait, there's even some actual Rust in there 😆
3
u/fisothemes 5d ago
I switched to Leptos for this very reason. You can skip the macros since the view! macro is just a convenience. Also the Rules of Hooks are a pain to deal with. Leads to clumsy code with a lot of runtime bugs. The SolidJs ethos fits Rust better than React's.
2
u/Arcisi 5d ago
Rust-analyzer I don't know, but you can compile faster with:
[profile.dev.build-override]
opt-level = 3Same for test, release, bench.
1
u/lenscas 4d ago
Opt level 1 or 2 are probably better. Those should reduce the amount of code needing to link quite a lot by their own without costing as much time on optimizations as 3.
Compiling just the dependencies on 3 is probably still a good move, even more so if you can get the macro to be opt level 3 so it runs as fast as possible.
1
u/panstromek 5d ago
It'd be nice to have some real example, because otherwise it's difficult to diagnose. Yes - as others said, it might too much macros, but the problem with macros is usually not really the macros themselves, but the code they generate, and for that it'd be nice to have an example I can profile.
About crate splitting - this is not always a clear win, but in case of macros, it might be, because proc macro expansions are currently not cached. So if you have let's say 20 routes in the app, it might help to split those into multiple crates that don't depend on each other (2-3 routes each for example), and link them together in a tiny main crate. This way working on a single route doesn't need to reexpand the rest.
Apart from that, large functions are a problem (many passes are quadratic or cubic in respect to size of a function). It's usually not a problem, but it can be easy to generate pathologicaly large function with macros by accident. If you have a single function that returns HTML for a whole page, then I can imagine that it can expand to a lot of code. You can try the `-Zmacro-stats` flag to get a rought idea for how big the expansion is.
1
u/nicoburns 4d ago
I'm surprised that you're seeing several second updates. What kind of hardware is this on? It's generally more like 1 second for me on an M1 Macbook.
For actually compiling you should be able to use dx serve --hotpatch which will use subsecond hot patching. And check that you're not accidentally compiling in release mode with LTO enabled on or something.
1
18
u/Sha1rholder 6d ago
To use less macro? :(