You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Compiling #[derive(Debug)] enum + dbg! is quadratic with enum variants #133945
I then compiled the code with cargo build --release. It takes 21.00s to compile on my machine, which is rather slow. It would be nice if it compiled faster.
Note that reducing the number of variants from 10000 to 1000 makes the compilation take only 0.20s to compile on my machine. I suspect that something in the Debug trait impl is taking quadratic time, but only if you actually try to debug-print something.
This issue was discovered by tongke on the rust community discord.
changed the title [-]Debug-printing an enum with very many variants takes a long time to compile[/-][+]Compiling `#[derive(Debug)] enum` + `dbg!` is quadratic with enum variants[/+]on Dec 6, 2024
The solution here would probably be to change the derive, like how PartialEq already special-cases field-less variants, not anything related to borrowcheck.
For example, it could have one arm for all the field-less variants that does a slice lookup using the discriminant.
(Or just tell people not to derive debug on enums like this...)
For example, it could have one arm for all the field-less variants that does a slice lookup using the discriminant.
This could be a nice improvement for other reasons too. Considering compile time, code size, performance, binary size, and data cache footprint, I think the pareto-optimal way to implement “one of these N static strings, indexed by small dense integers” for all but the smallest N is probably something like this:
static START: [u16; MAX_INDEX + 1] = [0, … /* prefix sum of string lengths */];
static STRINGS: &str = "all strings concatenated";
// indices without associated string can be mapped to an empty string without extra code
fn get_str(i: usize) -> &str {
let (start, end) = (START[i], START[i+1]);
&STRINGS[usize::from(start)..usize::from(end)]
}
One non-obvious benefit of using indices into a single strong is that it reduces the number of relocations (an array of &strs not only takes more space but also has one pointer per string that needs relocation for position independent code).
I’ve written this code myself once for a fieldless enum with ca. 150 variants and it did generate a smaller wasm module. But it’s real chore to do manually and it’s rarely worth the complexity, especially for further optimizations like unchecked indexing and using u8 instead of u16 if possible. Having the compiler generate this kind of lookup table automatically for derive(Debug) could be a nice improvement even for modest number of variants.
Activity
[-]Debug-printing an enum with very many variants takes a long time to compile[/-][+]Compiling `#[derive(Debug)] enum` + `dbg!` is quadratic with enum variants[/+]randyli commentedon Dec 20, 2024
I runned the compiling with -Z self-profile, and the result like this:
Is it a good idea to assign lable
A-borrow-checker?scottmcm commentedon Apr 11, 2025
The solution here would probably be to change the derive, like how
PartialEqalready special-cases field-less variants, not anything related to borrowcheck.For example, it could have one arm for all the field-less variants that does a slice lookup using the discriminant.
(Or just tell people not to derive debug on enums like this...)
hanna-kruppe commentedon Apr 11, 2025
This could be a nice improvement for other reasons too. Considering compile time, code size, performance, binary size, and data cache footprint, I think the pareto-optimal way to implement “one of these N static strings, indexed by small dense integers” for all but the smallest N is probably something like this:
One non-obvious benefit of using indices into a single strong is that it reduces the number of relocations (an array of
&strs not only takes more space but also has one pointer per string that needs relocation for position independent code).I’ve written this code myself once for a fieldless enum with ca. 150 variants and it did generate a smaller wasm module. But it’s real chore to do manually and it’s rarely worth the complexity, especially for further optimizations like unchecked indexing and using u8 instead of u16 if possible. Having the compiler generate this kind of lookup table automatically for derive(Debug) could be a nice improvement even for modest number of variants.
Auto merge of #155452 - makai410:enum-debug-array, r=nnethercote
Auto merge of #155452 - makai410:enum-debug-array, r=nnethercote
Auto merge of #155452 - makai410:enum-debug-array, r=nnethercote
Auto merge of #155452 - makai410:enum-debug-array, r=nnethercote
theemathas commentedon Oct 5, 2026
#155452 got reverted, so reopening.
panstromek commentedon Oct 9, 2026
I'm trying to reland some reduced version of #155452 in #162535
Rollup merge of rust-lang#162535 - panstromek:reland-debug-opt, r=nne…
Unrolled build for #162535 in rollup 164713