After updating Rust to version 1.38.0 from 1.36.0, I noticed that my program runs slower — by about 50%.
Using perf
, I discovered that half of the program time is spent in alloc::vec::Vec<T>::retain
in the new version. In the older version, this function does not even show up. Why would retain
take so much longer in 1.38.0?
The call to retain
is done like this:
some_vec.retain(|&x| x < DEADLINE);
deadline
is a constant u32
and some_vec
is a Vec<u32>
.
I ran the program without the retain
calls in both versions. In this case, 1.38.0 was still slower on average, but only by ~10% instead of the > 50% seen before.
To recap what happened in the tests:
Version 1.36.0
retain
: ~18secretain
: ~11secVersion 1.38.0
retain
: ~28secretain
: ~12secFor a reproducible example, you can try:
use std::time::Instant;
fn main() {
let start = Instant::now();
let mut my_vec: Vec<u32>;
for _ in 0..100_000 {
my_vec = (0..10_000).collect();
my_vec.retain(|&x| x < 9000);
my_vec.retain(|&x| x < 8000);
my_vec.retain(|&x| x < 7000);
my_vec.retain(|&x| x < 6000);
my_vec.retain(|&x| x < 5000);
my_vec.retain(|&x| (x < 5) & (x > 2));
}
let duration = start.elapsed();
println!("Program took: {:?}", duration);
}
With cargo +1.36.0 run --release
and then cargo +1.38.0 run --release
.
For this small example, I got:
$ cargo +1.36.0 run --release
Program took: 4.624297719s
$ cargo +1.38.0 run --release
Program took: 8.293383522s
In general, rust.godbolt.org is useful for checking quality of the generated code (but don't forget to add optimization flags!)
In your case code generated for retain
has clearly changed for worse: https://rust.godbolt.org/z/ZhVCDg
So you should report that to Rust as a performance regression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With