vftable penalización de rendimiento vs instrucción switch


C++ pregunta aquí. Tengo un sistema donde voy a tener cientos de mini-subclases de una superclase. Todos ellos tendrán un método " foo " que hace algo. O... Voy a tener una clase con un entero llamado "type" y usar una sentencia de interruptor gigante para decidir qué hacer cuando foo.

El rendimiento es una gran consideración aquí. Importantísima.

La pregunta es, ¿cuáles son los beneficios/penalizaciones de rendimiento de usar una instrucción switch frente a dejar que C++ hacerlo a través de la vftable? Si lo tengo como una instrucción switch, puedo poner el foo que ocurre comúnmente en la parte superior de la instrucción switch y los menos comunes en la parte inferior, con suerte cortocircuitando la comparación. Tratar de obtener un efecto como este con el vftable está destinado a ser dependiente del compilador, incluso si puedo averiguar cómo hacerlo...

Por otro lado, mi código sería mucho más fácil de manejar sin estas feas sentencias switch.

Author: eeeeaaii, 2010-12-17

5 answers

Si lo tengo como una instrucción switch, puedo poner los foo que ocurren comúnmente en la parte superior de la instrucción switch y los menos comunes en la parte inferior, con suerte cortocircuitando la comparación.

Una instrucción switch generalmente se compila en una tabla de saltos en lugar de un bloque de condicionales if-else como su pregunta implica. En la práctica, la tabla virtual y la tabla de salto switch deben tener un rendimiento similar, aunque pruebe si realmente está preocupado.

 13
Author: chrisaycock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-17 03:54:54

Ha habido algunas investigaciones sobre este tema en el campo del diseño de máquinas virtuales. Generalmente, una instrucción switch va a ser más rápida, muchas máquinas virtuales usan semántica switch en lugar de búsqueda virtual. Teóricamente, uno asumiría que una tabla virtual-siendo un algoritmo de tiempo constante-será más rápida, pero tenemos que examinar cómo el hardware ve una tabla virtual.

Una instrucción switch es más fácil de insertar para el compilador. Esta es una gran consideración, el real el acto de llamar a una función virtual es mínimo, sin embargo, empujar y hacer estallar todo el marco de la pila es necesario porque el compilador no tiene idea de qué función se llamará en tiempo de ejecución.

La predicción de ramificaciones y la prefetch de hardware deberían ser más fáciles en una sentencia switch, aunque las arquitecturas modernas están mejorando en la predicción de llamadas virtuales.

Una gran cantidad de código que utiliza virtual dispatch requiere el uso de esquemas de asignación basados en montones. La asignación dinámica de memoria es cuello de botella en muchas aplicaciones C++.

 12
Author: Anthony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-24 18:14:54

El compilador determina cómo se manejan las instrucciones switch, pero hay algunas técnicas básicas que utilizan.

  1. if-else binary-sort: La comparación se realiza como una serie de if-else, pero de una manera similar a la binaria, el rendimiento es comparable a la búsqueda en un mapa de N elementos
  2. tabla de salto: si los elementos están lo suficientemente cerca entre sí, se producirá una tabla de direcciones. La búsqueda es entonces en tiempo constante

Donde las sentencias case se encuentran en el conmutador la declaración no hace ninguna diferencia en ningún caso.

Las funciones virtuales tienen una sobrecarga en comparación con la llamada directa. Implica un desplazamiento adicional y búsqueda de puntero. Para todas las consideraciones de rendimiento, excepto las más extremas, este costo es insignificante. Cuando se compara con un interruptor, la sobrecarga no está en la búsqueda virtual, sino que la función se llama a sí misma. Por lo tanto, una instrucción switch que simplemente llama a funciones en cada caso realizará básicamente lo mismo que las funciones virtuales.

Así que esencialmente el las "semánticas de despacho" de una instrucción switch (con tabla de salto) en comparación con una llamada a una función virtual son casi irrelevantes. Si todos sus métodos "foo" son relativamente pequeños y se pueden insertar, la instrucción switch comenzará a funcionar mejor. La otra ventaja de switch es que puede poner código común antes del switch y obtener mejores optimizaciones de registro / pila.

Sin embargo, hay una sobrecarga de mantenimiento significativa. Esta debería ser su principal preocupación en este punto. ¿Por qué? Porque el rendimiento bottle-neck en su código no es probable que el inicio de sesión de conmutación, o incluso las llamadas a la función, pero algo más. Hasta que arregle esa otra cosa, no tiene sentido abordar estos problemas de rendimiento de bajo nivel. Así que apégate a lo que proporcione código más mantenible en este momento.

 3
Author: edA-qa mort-ora-y,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-17 08:53:46

A las otras respuestas aquí añadiría dos más.

1) Es más difícil y menos común para un compilador realizar optimizaciones clásicas (incluyendo registro) a través de una interfaz de llamada a función virtual que a través de instrucciones etiquetadas con mayúsculas y minúsculas en una instrucción switch en una sola función.

2) Cualquier diferencia de rendimiento en el envío depende en gran medida del hardware de predicción de ramas del procesador. Incluso una dirección de destino de llamada de función virtual (y retorno) puede ser predijo correctamente y tiene una sobrecarga de rendimiento insignificante en la tubería de un procesador moderno fuera de orden.

Si el rendimiento de esta operación realmente importa, realmente tienes que probarlo en ambos sentidos y medirlo, en el contexto del sistema real.

Feliz hackeo!

 2
Author: Jan Gray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-17 15:42:16

Vtable debería ser más rápido en casi todos los casos, pero si el rendimiento es tan crítico, lo correcto es preguntar por cuánto.

La llamada Vtable es una indirecta triple (tres accesos de memoria para obtener la dirección de la LLAMADA de destino). Las fallas de caché no deberían ser un problema si hay muchas llamadas. Por lo tanto, es aproximadamente 2-3 comparaciones de etiquetas de conmutadores (aunque este último ofrece aún menos posibilidades de error de caché de CPU, pero menos para el uso de tuberías).

Por supuesto, no debes confiar en nada de lo que dije aquí, y probar todo ello con mediciones de rendimiento reales en la arquitectura de destino.

 0
Author: Pavel Radzivilovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-17 03:52:04