c++ - Rendimiento de dynamic_cast?
performance dynamic-cast (4)
Aquí hay algunos puntos de referencia:
http://tinodidriksen.com/2010/04/14/cpp-dynamic-cast-performance/
http://www.nerdblog.com/2006/12/how-slow-is-dynamiccast.html
Según ellos, dynamic_cast es 5-30 veces más lento que reinterpret_cast, y la mejor alternativa tiene casi el mismo rendimiento que reinterpret_cast.
Citaré la conclusión del primer artículo:
- dynamic_cast es lento para todo menos para el tipo de base; ese elenco particular está optimizado
- el nivel de herencia tiene un gran impacto en dynamic_cast
- La variable miembro + reinterpret_cast es la forma más rápida y confiable de
determinar el tipo; sin embargo, eso tiene una sobrecarga de mantenimiento mucho mayor
cuando se codifica
Los números absolutos son del orden de 100 ns para un solo elenco. Valores como 74 mseg no parecen cercanos a la realidad.
Antes de leer la pregunta:
Esta pregunta no trata de cuán útil es usar dynamic_cast
. Es solo su rendimiento.
Recientemente desarrollé un diseño donde dynamic_cast
se usa mucho.
Al discutirlo con compañeros de trabajo, casi todos dicen que dynamic_cast
no debe usarse debido a su mal desempeño (son compañeros de trabajo que tienen diferentes antecedentes y en algunos casos no se conocen. Estoy trabajando en una gran empresa )
Decidí probar el rendimiento de este método en lugar de simplemente creer en ellos.
El siguiente código fue utilizado:
ptime firstValue( microsec_clock::local_time() );
ChildObject* castedObject = dynamic_cast<ChildObject*>(parentObject);
ptime secondValue( microsec_clock::local_time() );
time_duration diff = secondValue - firstValue;
std::cout << "Cast1 lasts:/t" << diff.fractional_seconds() << " microsec" << std::endl;
El código anterior usa métodos de boost::date_time
en Linux para obtener valores utilizables.
He realizado 3 dynamic_cast
en una ejecución, el código para medirlos es el mismo.
Los resultados de 1 ejecución fueron los siguientes:
Cast1 dura: 74 microsec
Cast2 dura: 2 microsec
Cast3 dura: 1 microsec
El primer elenco siempre tomó 74-111 microsec, los siguientes moldes en la misma ejecución tomaron 1-3 microsec.
Así que finalmente mis preguntas:
¿ dynamic_cast
realmente está funcionando mal?
Según los resultados de la prueba, no. ¿Mi código de prueba es correcto?
¿Por qué tantos desarrolladores piensan que es lento si no lo es?
En primer lugar, debe medir el rendimiento en mucho más que unas pocas iteraciones, ya que sus resultados estarán dominados por la resolución del temporizador. Pruebe, por ejemplo, 1 millón +, para construir una imagen representativa. Además, este resultado no tiene sentido a menos que lo compare con algo, es decir, haciendo el equivalente pero sin el lanzamiento dinámico.
En segundo lugar, debe asegurarse de que el compilador no le proporcione resultados falsos al optimizar múltiples moldes dinámicos en el mismo puntero (de modo que utilice un bucle, pero use un puntero de entrada diferente cada vez).
La conversión dinámica será más lenta, ya que necesita acceder a la tabla RTTI (información de tipo de tiempo de ejecución) para el objeto y verificar que el lanzamiento sea válido. Luego, para usarlo correctamente, deberá agregar un código de control de errores que verifique si el puntero devuelto es NULL
. Todo esto toma ciclos.
Sé que no querías hablar de esto, pero "un diseño donde dynamic_cast se usa mucho" es probablemente un indicador de que estás haciendo algo mal ...
Lamento decir esto, pero su prueba es prácticamente inútil para determinar si el lanzamiento es lento o no. La resolución de microsegundos no es lo suficientemente buena. Estamos hablando de una operación que, incluso en el peor de los casos, no debería tomar más de, digamos, 100 tics de reloj, o menos de 50 nanosegundos en una PC típica.
No hay duda de que el lanzamiento dinámico será más lento que un elenco estático o un elenco de reinterpretación, porque, en el nivel de ensamblaje, los dos últimos equivaldrán a una asignación (muy rápido, orden de 1 marcación de reloj), y el elenco dinámico requiere el código para ir e inspeccionar el objeto para determinar su tipo real.
No puedo decir de improviso qué tan lento es realmente, que probablemente varíe de compilador a compilador, necesitaría ver el código ensamblado generado para esa línea de código. Pero, como dije, 50 nanosegundos por llamada es el límite superior de lo que se espera que sea razonable.
El rendimiento no tiene sentido sin comparar la funcionalidad equivalente. La mayoría de la gente dice que dynamic_cast es lento sin comparar con el comportamiento equivalente. Llámalos en esto. Dicho de otra manera:
Si ''works'' no es un requisito, puedo escribir código que falla más rápido que el tuyo.
Hay varias formas de implementar dynamic_cast, y algunas son más rápidas que otras. Stroustrup publicó un artículo sobre el uso de primos para mejorar dynamic_cast , por ejemplo. Lamentablemente, es inusual controlar cómo el compilador implementa el molde, pero si el rendimiento realmente es importante para usted, entonces usted tiene control sobre qué compilador utiliza.
Sin embargo, no usar dynamic_cast siempre será más rápido que usarlo, pero si realmente no necesitas dynamic_cast, ¡entonces no lo uses! Si necesita una búsqueda dinámica, habrá una sobrecarga y podrá comparar varias estrategias.