[c++] Predeterminado en caso de interruptor


Answers

Aunque haya aceptado la que probablemente sea la mejor respuesta, quería brindarle una alternativa.

Tenga en cuenta que se aplica la advertencia estándar: la optimización no es optimización a menos que haya perfilado su código.

Sin embargo, si tiene un rendimiento bajo en relación con las sucursales, puede reducirlas o eliminarlas. Que su código tenga una o más comparaciones de desigualdad no es un obstáculo: puede reducir sus casos a un conjunto de igualdades directas y, si es necesario, usar eso para indexar una tabla, en lugar de ramificar.

void doSomething(int len)
{
    static const char* str[] =
    {   "%2d > 3\n",
        "%2d < 2\n",
        "%2d = 2\n",
        "%2d = 3\n"
    };

    int m1 = (len-2)>>31;
    int m2 = (len-4)>>31;

    int r = (len & m2 & ~m1) + !!m1;

    printf(str[r],len); 
}

Tenga en cuenta que estos códigos hacen varias suposiciones que pueden no ser válidas en la práctica, pero a medida que vamos asumiendo la salvaje suposición de que esto incluso necesita optimizar en primer lugar ...

Además, tenga en cuenta que es posible realizar mejores optimizaciones con más conocimiento sobre el rango real y el tipo del parámetro de entrada, y de hecho cuáles deben ser las acciones reales que se toman.

Question

El siguiente es el código que necesito optimizar y planeé que sería bueno moverse para cambiar. Pero puedo comparar en el caso. Así que planeé hacer el comaparision (len> 3) como caso por defecto.

Si hago la parte de comparación (len> 3) como caso por defecto y agrego el valor predeterminado como first in swith, ¿será más rápido?

¿O cómo puedo hacer que el siguiente código sea una declaración de cambio?

            if ( len > 3 ) {
                    which will happen more often;
            }               
            else if ( len == 3 ) {
                    next case which may occur often;
            } else if ( len == 2 ) {        
                   the next priority case;
            } else {
                    and this case occurs rarely;
            }



Puede usar un rango en un caso:

switch (len) {
  case 3 ... INT_MAX:
    // ...
    break;
  case 2:
    // ...
    break;
  default:
    // ...
    break;
 }

Editar: pero esa es una extensión proporcionada por GCC ...




La única forma en que lo sabrás es compararlo con tu compilador. Si el rendimiento es un problema, debe usar la opción para proporcionar al compilador el resultado del generador de perfiles y dejar que decida; generalmente encontrará la mejor solución. (Tenga en cuenta que incluso en una arquitectura específica, como Intel, la mejor solución en términos de instrucciones de la máquina puede variar de un procesador a otro).

En su caso, el cambio probablemente se vería así:

switch ( len ) {
case 2:
    //  ...
    break;

case 3:
    //  ...
    break;

default:
    if ( len > 3 ) {
        // ...
    } else {
        // ...
    }
}

Con solo dos casos efectivos, el compilador no tiene mucho con lo que trabajar. Una implementación típica (sin optimización extrema) haría la comprobación de límites, luego una búsqueda de tablas para los dos casos explícitos. Cualquier compilador decente se dará cuenta de que la comparación en su caso default corresponde a una de las verificaciones de límites que ya ha hecho, y no la duplica. Pero con solo dos casos, la tabla de saltos probablemente no hará una diferencia significativa en comparación con las dos comparaciones, especialmente porque estarás fuera de límites en el caso más frecuente.

Hasta que no tenga información real del generador de perfiles que este es un cuello de botella en su código, no me preocuparía. Una vez que tenga esa información, puede perfilar diferentes variantes para ver cuál es más rápida, pero sospecho que si utiliza la optimización máxima y la información de perfil de alimentación de nuevo en el compilador, no habrá diferencia.






Links