Pregunta

Perfiles de mi código C ++ con gprof, descubrí que una parte importante de mi tiempo se dedica a llamar a un método virtual y otra vez. El método en sí es corto y probablemente podría ser inline si no fuera virtual.

¿Cuáles son algunas maneras en que podría acelerar este proceso corto de volver a escribir todo a no ser virtual?

¿Fue útil?

Solución

A veces es instructivo considerar cómo le gustaría escribir el código en el bueno de 'C' si no tiene azúcar sintáctico C ++ 's disponibles. A veces la respuesta no está utilizando una llamada indirecta. Ver este respuesta para un ejemplo.

Otros consejos

¿Está seguro el tiempo es todo lo relacionado con el llamado? Podría ser la propia función donde el costo es? Si este es el caso, simplemente inlining cosas podría hacer desaparecer la función de su generador de perfiles, pero no verá mucha velocidad arriba.

Suponiendo que realmente es la sobrecarga de hacer tantas llamadas virtuales que hay un límite a lo que puede hacer sin hacer las cosas no virtual.

Si la llamada tiene early-outs para cosas como el tiempo / banderas entonces voy a menudo utilizan un enfoque de dos niveles. La comprobación se colocarán en línea con una llamada no virtual, con el comportamiento específico de clase única llamada si es necesario.

por ejemplo.

class Foo
{
public:

inline void update( void )
{
  if (can_early_out)
    return;

  updateImpl();
}

protected:

virtual void updateImpl( void ) = 0;    
}; 

Si la llamada virtual realmente es el cuello de botella dar CRTP intentarlo.

Es el tiempo que se gasta en la llamada a la función, o en la propia función?

Una llamada de función virtual es notablemente más lento que una llamada no virtual, porque la llamada virtual requiere un desreferenciar adicional. (Google para 'vtable' si desea leer todos los detalles peludos.)) Actualización: Resulta que el artículo de Wikipedia no es malo en esto.

"Notablemente" aquí, sin embargo, significa un par de instrucciones Si se consume una parte significativa del tiempo de cálculo incluyendo total gastado en la función llamada, que suena como un lugar maravilloso para considerar unvirtualizing y procesos en línea.

Pero en algo cercano a 20 años de C ++, no creo que he visto que realmente ocurra. Me encantaría ver el código.

Por favor, tenga en cuenta que "virtual" y "en línea" no son opuestos - un método puede ser a la vez. El compilador felizmente inline una función virtual si se puede determinar el tipo de objeto en tiempo de compilación:

struct B {
    virtual int f() { return 42; }
};

struct D : public B {
    virtual int f() { return 43; }
};

int main(int argc, char **argv) {
    B b;
    cout << b.f() << endl;   // This call will be inlined

    D d;
    cout << d.f() << endl;   // This call will be inlined

    B& rb = rand() ? b : d;
    cout << rb.f() << endl;  // Must use virtual dispatch (i.e. NOT inlined)
    return 0;
}

[ACTUALIZACIÓN: Hecho cierto tipo de objeto dinámico determinado de rb no puede ser conocido en tiempo de compilación - gracias a MSalters]

Si el tipo del objeto se puede determinar en tiempo de compilación pero la función no es inlineable (por ejemplo, que es grande o se define fuera de la definición de clase), se llama no virtualmente.

Es posible que pueda obtener un poco mejor rendimiento de la llamada virtual cambiando la convención de llamada. El viejo compilador Borland tenía una convención __fastcall que pasó argumentos en registros de la CPU en lugar de en la pila.

Si está atrapado con la llamada virtual y esas pocas operaciones realmente cuentan, a continuación, comprobar la documentación del compilador para convenciones de llamada compatibles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top