2012-10-07 52 views
24

Pregunta:Costo de empuje vs mov (frente de pila cerca de la memoria), y la sobrecarga de llamadas de funciones a

accede a la pila la misma velocidad que acceder a la memoria?

Por ejemplo, podría elegir hacer algún trabajo dentro de la pila, o podría trabajar directamente con una ubicación etiquetada en la memoria.

Entonces, específicamente: ¿es push ax la misma velocidad que mov [bx], ax? ¿Igual es pop ax la misma velocidad que mov ax, [bx]? (BX asumir cuenta con una ubicación en la memoria near.)

La motivación para la pregunta:

Es común en C para desalentar funciones triviales que tienen parámetros.

Siempre he pensado que esto se debe a que los parámetros se insertan en la pila y luego se eliminan de la pila una vez que la función retorna, pero también porque la llamada de función debe preservar el contexto de la CPU, lo que significa uso.

Pero suponiendo que uno conoce la respuesta a la pregunta principal, debería ser posible cuantificar la sobrecarga que la función utiliza para establecerse (pulsar/abrir/preservar contexto, etc.) en términos de un número equivalente de directo accesos de memoria. De ahí la pregunta principal.


( Editar: Aclaración: near utilizado anteriormente es en contraposición a far en la arquitectura x86 segmented memory model de 16 bits.)

+5

Wow. Soy un explorador Acabo de encontrar una buena pregunta que no sea n00b en StackOverflow. ¡Celebrando mi exploración con champán y un voto popular! –

+1

Siempre consideré las operaciones de incremento/decremento de llamadas push/pop en ESP como una sobrecarga en comparación con mov .... pero creo que debería haber mucho más. – loxxy

Respuesta

17

Hoy en día su compilador C que puede ser más astuto. Puede alinear funciones simples y, si lo hace, no habrá llamadas ni retornos de funciones y, tal vez, no habrá manipulaciones adicionales de la pila relacionadas con pasar y acceder a los parámetros de funciones formales (o una operación equivalente cuando la función esté en línea pero el los registros disponibles están agotados) si todo puede hacerse en registros o, mejor aún, si el resultado es un valor constante y el compilador puede ver eso y aprovecharlo.

Las llamadas a función pueden ser relativamente baratas (pero no necesariamente de costo cero) en las CPU modernas, si se repiten y si hay una caché de instrucciones separada y varios mecanismos de predicción, lo que ayuda a la ejecución eficiente del código.

Aparte de eso, esperaría que las implicaciones de rendimiento de la opción "var local versus var global" dependan de los patrones de uso de la memoria. Si hay un caché de memoria en la CPU, es probable que la pila esté en ese caché, a menos que asigne y desasigne arreglos o estructuras grandes en él o tenga llamadas a funciones profundas o recursión profunda, lo que provocará errores de caché. Si se accede a la variable global de interés a menudo o si se accede a sus vecinos a menudo, también esperaría que la variable esté en el caché la mayor parte del tiempo. Nuevamente, si accede a grandes espacios de memoria que no caben en la memoria caché, tendrá fallas en la memoria caché y posiblemente un rendimiento reducido (posiblemente porque puede haber o no una mejor manera de hacer lo que quiero hacer).

Si el hardware es bastante tonto (cachés o cachés pequeños, sin predicción, sin reordenamiento de instrucciones, sin ejecución especulativa, nada), claramente quiere reducir la presión de memoria y el número de llamadas a funciones porque cada uno contará .

Otro factor más es la longitud de la instrucción y la decodificación. Las instrucciones para acceder a una ubicación en la pila (relativa al puntero de la pila) pueden ser más cortas que las instrucciones para acceder a una ubicación de memoria arbitraria en una dirección determinada. Las instrucciones más cortas se pueden decodificar y ejecutar más rápido.

yo diría que no hay una respuesta definitiva para todos los casos ya que el rendimiento depende de:

  • su hardware
  • su compilador
  • su programa y sus patrones de memoria para acceder a
+0

Gracias Alexey: un buen punto acerca de var local (pila, ¿correcto?) Vs. var global (memoria, ¿correcto?) - no lo había pensado de esa manera. –

+0

Re: ubicación de memoria arbitraria - es por eso que estoy restringiendo la consideración a la memoria 'cerca'. ¿Esto hace la diferencia? –

+0

Re: su punto acerca de la variación de la duración de la instrucción y el tiempo de decodificación: ¿quiere decir una diferencia entre, por ejemplo, 'mov [bx], ax' vs.' mov [loc], ax', suponiendo 'loc equ 0xfff'' (o alguna cerca de la compensación)? (¡Gracias, como siempre, por sus excelentes respuestas!) –

11

Para el reloj-ciclo-curioso ...

Para aquellos que deseen ver ciclos de reloj específicos, instruction/latency tables para una variedad de modernas CPU x86 y x86-64 están disponibles here (gracias a hirschhornsalz para señalarlos).

A continuación, obtener, en un chip Pentium 4:

  • push ax y mov [bx], ax (rojo en caja) son prácticamente idénticos en su eficiencia con latencias y rendimientos idénticos.
  • pop ax y mov ax, [bx] (azul en caja) son igualmente eficiente, con rendimientos idénticos a pesar mov ax, [bx] tener el doble de la latencia de pop ax

Pentium 4 Instruction Timing Table

En cuanto a la pregunta de seguimiento en los comentarios (tercera comentario):

  • direccionamiento indirecto (es decir mov [bx], ax) no es materialmente diferente de direccionamiento directo (es decir mov [loc], ax), donde loc es una variable que tiene un valor inmediato, p. loc equ 0xfffd.

Conclusión: combinar esto con Alexey's thorough answer, y hay un caso bastante sólido para la eficiencia del uso de la pila y dejar que el compilador de decidir cuando una función debe ser inline.

(Nota al margen: De hecho, incluso ya en el 8086 a partir de 1978, mediante la pila todavía no era menos eficiente que mov correspondiente de la memoria, como puede verse a partir these old 8086 instruction timing tables.)


Descripción de la latencia & Rendimiento

Es posible que se necesite un poco más para comprender las tablas de tiempo para las CPU modernas.Estos deben ayudar:

Cuestiones relacionadas