2010-10-29 15 views
35

Antes de leer la pregunta:
Esta pregunta no es acerca de cuán útil es usar dynamic_cast. Es solo su rendimiento.Rendimiento de dynamic_cast?

Recientemente he desarrollado un diseño en el que dynamic_cast se utiliza mucho.
Al hablar de esto con los compañeros de trabajo, casi todos dicen que dynamic_cast no se debe utilizar debido a su mal rendimiento (estos 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 solo creerlo. se utilizó

El siguiente código:

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 utiliza métodos de boost::date_time en Linux para obtener valores utilizables.
He hecho 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

La primera fundido siempre se 74-111 microsegundos, la siguiente los moldes en la misma ejecución tomaron 1-3 microsec.

Así que finalmente mis preguntas:
¿dynamic_cast realmente está teniendo problemas?
De acuerdo con el testresults no es. ¿Mi código de prueba es correcto?
¿Por qué tantos desarrolladores piensan que es lento si no lo es?

+13

¿Echo de menos algo? No puedo ver ningún código para cast2 o cast3. – Flexo

+4

¿Quién puede decir qué es malo? ¿Tu programa funciona lo suficientemente bien? Si es así, entonces el rendimiento no es malo. ¿El tiempo total en dinámica arroja un gran porcentaje de su tiempo de ejecución? Si no, entonces preocúpate por otras cosas primero. En términos más generales, 74 microsegundos es terriblemente lento para algunas aplicaciones: en mi último trabajo, habría recibido y analizado un registro de actualización completo de la bolsa de valores, actualizado la base de datos y se lo conté a las aplicaciones cliente en la mitad del tiempo. Si le interesa, compárelo con otras formas de obtener el mismo comportamiento. –

+3

Tener un montón de dynamic_casts en el código es un indicador seguro de los problemas de diseño. –

Respuesta

42

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 proporciona resultados falsos al optimizar múltiples moldes dinámicos en el mismo puntero (utilice un bucle, pero use un puntero de entrada diferente cada vez).

La fundició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 comprobar que la conversión sea válida. 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.

Yo sé que no quieres hablar de esto, pero "un diseño donde dynamic_cast se utiliza mucho" es probablemente un indicador de que estás haciendo algo mal ...

+5

+1, pero las iteraciones de 10K probablemente no sean suficientes. Algo así como 100 millones es mejor. – sharptooth

+0

@sharptooth: ¡Punto justo! –

+0

@Oliver Charlesworth "... para usarlo correctamente, necesitará agregar un código de control de errores que verifique si el puntero devuelto es NULL". Hay una versión análoga del cheque que menciona en todos los métodos para encontrar el tipo de tiempo de ejecución de un objeto, por lo que este no es un argumento. – spectre

24

rendimiento no tiene sentido sin comparando la funcionalidad equivalente. La mayoría de las personas dicen 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.

Existen varias formas de implementar dynamic_cast, y algunas son más rápidas que otras. Stroustrup publicó un documento sobre el uso de primes to improve 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 se siempre será más rápido que el uso de ella - pero si no lo hace realmente necesita dynamic_cast, entonces no lo use! Si necesita una búsqueda dinámica, habrá una sobrecarga y podrá comparar varias estrategias.

+4

+1. Sí, por cierto, cada persona viviente finalmente muere. Lo cual no significa que sea una mala idea estar vivo. – sharptooth

4

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 molde dinámico será más lento que un elenco estático o un elenco de reinterpretación, porque, en el nivel de conjunto, los dos últimos equivaldrán a una asignación (muy rápido, orden de 1 marcación de reloj) y el lanzamiento dinámico requiere que el código vaya e inspeccione el objeto para determinar su tipo real.

No puedo decir de improviso qué tan lento es en realidad, que probablemente varíe de compilador a compilador, necesitaría ver el código de 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.

+0

dynamic_cast necesita acceder a RTTI, esto tomará ciclos. – doron

16

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 realiza casi lo mismo que reinterpret_cast.

Voy a citar la conclusión del primer artículo:

  • dynamic_cast es lento para otra cosa que convertir al tipo de base; que elenco particular, se optimiza a cabo
  • el nivel de la herencia tiene un gran impacto en dynamic_cast
  • variable miembro + reinterpret_cast es la manera más rápida confiable para determinar el tipo de
    ; sin embargo, que tiene mucho mayor sobrecarga de mantenimiento
    al codificar

números absolutos son del orden de 100 ns para un solo molde. Valores como 74 mseg no parecen cercanos a la realidad.

+1

El valor que obtuvo fue de 74 usec (microsegundos), no de 74 msec (milisegundos). Aun así, todavía no parece realista. – Ponkadoodle

Cuestiones relacionadas