[perf] Constructors where `this` escapes are slow

Abierto
#582 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
35/100
Tipo de issue
Refactorización
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
cpp, rust

Línea de trabajo

The issue describes how the translator emits constructors for C++ types whose this escapes, so start in the code that generates the Rust new function for constructors. Read the godbolt example linked in the issue to compare the inline and escaping cases. The proposed change is to allocate the storage before the constructor call and pass it in; done means escaping-this output no longer copies the struct and the existing transpiler tests still pass. The Rc/RefCell case is a separate, related cost.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

In unsafe constructors are translated as:

fn new() -> Self {
  let this = Self { ... };
  ... body of the constructor ...
  this
}

When this escapes in the body of the constructor, for example init(&mut this), the translated new becomes slower than necessary: this is constructed inside the body then memcpy'ed in the caller.

When this does not escape in the body of the constructor, Rust returns the this inline, without a memcpy. See this example.

C++ does no memcpy. The semantics of the constructor is: a storage, i.e. this, is passed to the constructor, the constructor initialises this, then the storage is returned.

I think that the solution for this performance problem is to follow what C++ does: create this before calling the constructor and pass the storage to the constructor. This would also fix #248.


In performance terms, refcount is worse because it does 3 memcpy's even when this does not escape:

fn new() -> Self {
  let __this = Rc::new(RefCell::new(Self { ... }));
  let this = __this.as_pointer();
  Rc::try_unwrap(this) // memcpy 1: transforms Rc<RefCell<S>> into Result<RefCell<S>, Rc<RefCell<S>>>
    .ok().unwrap() // memory 2: transforms Result<RefCell<S>, Rc<RefCell<S>>> into RefCell<S>
    .into_inner() // memcp 3: transforms RefCell<S> into S
}

The solution is the same as unsafe: create this before calling the constructor and pass the storage to the constructor.

Lenguaje dominante
Rust
Estrellas
310
Forks
18
Merge medio
10 h 18 min
PR fusionados (30 d)
125

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Cpp2Rust/cpp2rust

Todos los issues de Cpp2Rust/cpp2rust

Issues similares

Más issues de Rust

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.