2012-07-09 6 views
5

EDITAR: Después de quitar el UB (punto bueno, lo perdí), los tiempos son más o menos idénticos. Marcará a un moderador para eliminarlo.¿Por qué el movimiento de regreso al final de la función es menos eficiente?

Estas dos funciones son idénticos excepto por el hecho de que foo tiene el retorno dentro de la if, en ambas ramas, mientras que goo tiene un único return al final:

int foo() 
{ 
    static int x = 0; 
    if (x) 
    { 
     x > 2 ? x = 0 : ++x; 
     return x-1; 
    } 
    else 
    { 
     x++; 
     return x-1; 
    } 
} 
int goo() 
{ 
    static int x = 0; 
    if (x) 
    { 
     x > 2 ? x = 0 : ++x; 
    } 
    else 
    { 
     x++; 
    } 
    return x-1; 
} 

Los números están ahí tan las optimizaciones no se activan demasiado y la llamada de función no se optimiza. Compilado con optimización completa en MSVS 2010.

Llamar a la función 4000000000 veces, la muestra 10 veces, foo fue siempre más rápido:

  • foo - 8830 ms promedio
  • goo - 8703 ms promedio

La diferencia es pequeña, pero está ahí. ¿Por qué? Además, ¿por qué el compilador no los optimiza para lo mismo?

+1

¿Ha comprobado la salida del ensamblador? –

+0

@larsmans sí, la función está en línea y la primera es * más grande * (aunque toma menos). También estoy investigando los motivos ** por los que ** el compilador no ve las optimizaciones que está haciendo para uno de ellos. –

+0

¿Miraste el código ASM que se produjo? –

Respuesta

3

Eche un vistazo a la salida del ensamblador, puede haber un salto al final de la función en la primera rama de goo().

+0

Sí, pero esa primera rama nunca se toma. – TerryE

+1

Estoy pensando que tiene algo que ver con la predicción de sucursales y la canalización. –

+1

@TerryE x es estático, por lo que se incrementa en el segundo brunch y, por lo tanto, se llama a la primera rama en una llamada a la siguiente función. –

0

Asumo que es porque tener la vuelta en cada if, el momento en que se realiza la operación, foo volverá la variable calculada.

goo, aunque piense que hace lo mismo, a excepción de las dos devoluciones, todavía tendrá que comprobar la declaración else.Eso usa algo de tiempo (extremadamente pequeño) pero como puede ver, es mesurable.

+4

¿Qué quieres decir con que todavía tiene que comprobar la declaración 'else'? –

+0

No creo que deba verificarse el resto. Primero, no hay un "control" de otro. De lo contrario, es cierto si todo lo anterior era falso. Además, si la condición 'if' es verdadera, el bloque' else' nunca se ejecuta, por lo que no veo ninguna diferencia en el trabajo. Como dijeron los demás, el código de ensamblaje puede ser diferente. – Brandon

-3

En el caso de las llaves del extremo foo "if" y "else" no se ejecutarán. Después de la devolución

declaración, el control tendrá o la llave de la función directamente.

Es por eso que tomará menos tiempo para foo.

+1

Naren, un núcleo no ejecuta "llaves". Ejecuta instrucciones. Sin embargo, tiene razón en que algunos compiladores alinean los destinos de las ramificaciones en límites de 4/8 bytes para ayudar a mejorar el almacenamiento en caché de las instrucciones, y tener un objetivo adicional así como el código adicional para el primer 'retorno x + 1 'podría afectar el tiempo . – TerryE

+0

Sé que esto no se ejecuta, pero lo intenté dando puntos de interrupción y la ejecución fue directamente al final de la función de refuerzo .... También prueba con el punto de ruptura y el control. – Narendra

Cuestiones relacionadas