Skip to content

Commit

Permalink
Rollup merge of #82248 - nhwn:optimize-counting-digits, r=varkor
Browse files Browse the repository at this point in the history
Optimize counting digits in line numbers during error reporting

Replaces `.to_string().len()` with simple loop and integer division, which avoids an unnecessary allocation.

Although I couldn't figure out how to directly profile `rustc`'s error reporting, I ran a microbenchmark on my machine (2.9 GHz Dual-Core Intel Core i5) on the two strategies for `0..100_000`, and the results seem promising:
```
test to_string_len ... bench:  12,124,792 ns/iter (+/- 700,652)
test while_loop    ... bench:      30,333 ns/iter (+/- 562)
```
The x86_64 disassembly reduces integer division to a multiplication + shift, so I don't think there's any problems with using integer division.

For more (micro)optimization, it would be nice if we could avoid the initial check to see if the line number is nonzero, but I don't think `self.get_max_line_num(span, children)` _guarantees_ a nonzero line number.
  • Loading branch information
Dylan-DPC authored Feb 18, 2021
2 parents 3266eb2 + 8a5c568 commit d744e0b
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1713,7 +1713,18 @@ impl EmitterWriter {
let max_line_num_len = if self.ui_testing {
ANONYMIZED_LINE_NUM.len()
} else {
self.get_max_line_num(span, children).to_string().len()
// Instead of using .to_string().len(), we iteratively count the
// number of digits to avoid allocation. This strategy has sizable
// performance gains over the old string strategy.
let mut n = self.get_max_line_num(span, children);
let mut num_digits = 0;
loop {
num_digits += 1;
n /= 10;
if n == 0 {
break num_digits;
}
}
};

match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
Expand Down

0 comments on commit d744e0b

Please sign in to comment.