¿Por qué Vec :: retiene la ejecución más lenta después de actualizar a Rust 1.38.0?


8

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>::retainen la nueva versión. En la versión anterior, esta función ni siquiera aparece. ¿Por qué retaintomaría tanto tiempo en 1.38.0?

La llamada a retainse hace así:

some_vec.retain(|&x| x < DEADLINE);

deadlinees una constante u32y some_veces una Vec<u32>.

Ejecuté el programa sin las retainllamadas 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 --releasey 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

3

Gracias por mejorar su pregunta en respuesta a sus comentarios. ¡Realmente lo cambiaste! Espero que obtengas una respuesta.
trentcl

2
Cavé un poco: 1.37.0 es rápido como 1.36.0; todas las noches es lento El MIR generado de 1.37 y 1.38 me parece igual si no tiene en cuenta los comentarios y el orden relativo de las funciones, lo que implica: rustc cambió el número / orden / tipo de pases LLVM, o la versión de LLVM utilizada por rustc cambió entre 1.37 y 1.38, en cuyo caso esta es una regresión LLVM así como también una regresión rustc. No sé cómo decir cuál, desafortunadamente.
trentcl

Aquí está el informe de error que presentó
@Miguel

Respuestas:


2

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 retainha cambiado claramente para peor: https://rust.godbolt.org/z/ZhVCDg

Por lo tanto, debe informarlo a Rust como una regresión de rendimiento.


1
Ya he informado que se oxida como lo sugirió @Peter Hall también.
Miguel

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.