Después de actualizar Rust a la versión 1.38.0 desde 1.36.0, noté que mi programa se ejecuta más lentamente, en aproximadamente un 50%.
Utilizando perf
, descubrí que la mitad del tiempo del programa se gasta alloc::vec::Vec<T>::retain
en la nueva versión. En la versión anterior, esta función ni siquiera aparece. ¿Por qué retain
tomaría tanto tiempo en 1.38.0?
La llamada a retain
se hace así:
some_vec.retain(|&x| x < DEADLINE);
deadline
es una constante u32
y some_vec
es una Vec<u32>
.
Ejecuté el programa sin las retain
llamadas en ambas versiones. En este caso, 1.38.0 fue aún más lento en promedio, pero solo en ~ 10% en lugar del> 50% visto anteriormente.
Para recapitular lo que sucedió en las pruebas:
Versión 1.36.0
- con
retain
: ~ 18 segundos - sin
retain
: ~ 11 segundos
Versión 1.38.0
- con
retain
: ~ 28 segundos - sin
retain
: ~ 12 segundos
Para un ejemplo reproducible, puedes probar:
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);
}
Con cargo +1.36.0 run --release
y luego cargo +1.38.0 run --release
.
Para este pequeño ejemplo, obtuve:
$ cargo +1.36.0 run --release
Program took: 4.624297719s
$ cargo +1.38.0 run --release
Program took: 8.293383522s
fuente
Respuestas:
En general, rust.godbolt.org es útil para verificar la calidad del código generado (¡pero no olvide agregar indicadores de optimización!)
En su caso, el código generado para
retain
ha cambiado claramente para peor: https://rust.godbolt.org/z/ZhVCDgPor lo tanto, debe informarlo a Rust como una regresión de rendimiento.
fuente