poner likes historias hashtags halloween for food español como and c++ optimization architecture memory

c++ - likes - hashtag halloween español



¿Cuál es el costo de una llamada a función? (15)

Comparado con

  • Acceso simple a la memoria
  • Acceso al disco
  • Acceso a la memoria en otra computadora (en la misma red)
  • Acceso al disco en otra computadora (en la misma red)

en C ++ en Windows.


¿El costo de llamar realmente a la función, pero no ejecutarla en su totalidad? o el costo de realmente ejecutar la función? simplemente configurar una llamada de función no es una operación costosa (¿actualizar la PC?). pero obviamente el costo de una función que se ejecuta en su totalidad depende de lo que esté haciendo la función.


Depende de lo que haga esa función, estaría en segundo lugar en su lista si estuviese haciendo lógica con los objetos en la memoria. Más abajo en la lista si incluye acceso a disco / red.


El costo de una llamada a función depende de la arquitectura. x86 es considerablemente más lento (unos pocos relojes más un reloj más o menos por argumento de función) mientras que 64 bits es mucho menos porque la mayoría de los argumentos de función se pasan en registros en lugar de en la pila.


En comparación con un simple acceso a la memoria, un poco más, realmente insignificante.

Comparado con todo lo demás en la lista: órdenes de magnitud menos.

Esto debería ser cierto para casi cualquier idioma en cualquier sistema operativo.


En general, una llamada de función va a ser un poco más lenta que el acceso a la memoria, ya que de hecho tiene que hacer múltiples accesos de memoria para realizar la llamada. Por ejemplo, se requieren múltiples pulsaciones y saltos de la pila para la mayoría de las llamadas de función usando __stdcall en x86. Pero si su acceso a la memoria está en una página que no está ni siquiera en la caché L2, la llamada a la función puede ser mucho más rápida si el destino y la pila están todos en la memoria caché de la CPU.

Para todo lo demás, una llamada a función es muchas (muchas) magnitudes más rápidas.


Es difícil de responder porque hay muchos factores involucrados.

En primer lugar, "Simple Memory Access" no es simple. Dado que a velocidades de reloj modernas, una CPU puede agregar dos números más rápido que obtener un número de un lado del chip al otro (La velocidad de la luz: no es solo una buena idea, es la LEY)

Entonces, ¿se está llamando a la función dentro de la memoria caché de la CPU? ¿El acceso a la memoria lo está comparando también?

Luego tenemos la llamada a la función que borrará la tubería de instrucciones de la CPU, lo que afectará la velocidad de una manera no determinista.


Este enlace aparece mucho en Google. Para referencia futura, ejecuté un programa corto en C # sobre el costo de una llamada a función, y la respuesta es: "aproximadamente seis veces el costo de en línea". A continuación hay detalles, vea // Salida en la parte inferior. ACTUALIZACIÓN: Para comparar mejor las manzanas con manzanas, cambié Class1.Method para devolver ''void'', así: public void Method1 () {// return 0; }
Aún así, en línea es más rápido en 2x: en línea (avg): 610 ms; llamada de función (avg): 1380 ms. Entonces, la respuesta, actualizada, es "aproximadamente dos veces".

usando el sistema; utilizando System.Collections.Generic; utilizando System.Linq; usando System.Text; usando System.Diagnostics;

espacio de nombres FunctionCallCost {clase Programa {static void Main (cadena [] args) {Debug.WriteLine ("stop1"); int iMax = 100000000; // 100M DateTime funcCall1 = DateTime.Now; Cronómetro sw = Stopwatch.StartNew ();

for (int i = 0; i < iMax; i++) { //gives about 5.94 seconds to do a billion loops, // or 0.594 for 100M, about 6 times faster than //the method call. } sw.Stop(); long iE = sw.ElapsedMilliseconds; Debug.WriteLine("elapsed time of main function (ms) is: " + iE.ToString()); Debug.WriteLine("stop2"); Class1 myClass1 = new Class1(); Stopwatch sw2 = Stopwatch.StartNew(); int dummyI; for (int ie = 0; ie < iMax; ie++) { dummyI = myClass1.Method1(); } sw2.Stop(); long iE2 = sw2.ElapsedMilliseconds; Debug.WriteLine("elapsed time of helper class function (ms) is: " + iE2.ToString()); Debug.WriteLine("Hi3"); } }

// Clase 1 aquí usando System; utilizando System.Collections.Generic; utilizando System.Linq; usando System.Text;

espacio de nombres FunctionCallCost {clase Class1 {

public Class1() { } public int Method1 () { return 0; } }

}

// Salida: tiempo transcurrido stop1 de la función principal (ms) es: 595 tiempo transcurrido de stop2 de la función de clase auxiliar (ms) es: 3780

stop1 tiempo transcurrido de la función principal (ms) es: 592 stop2 tiempo transcurrido de la función de clase auxiliar (ms) es: 4042

stop1 tiempo transcurrido de la función principal (ms) es: 626 stop2 tiempo transcurrido de la función de clase auxiliar (ms) es: 3755


Llamada de función es en realidad una copia de los parámetros en la pila (acceso a memoria múltiple), guardar registro, la ejecución del código real y, finalmente, copiar y restaurar el resultado (los registros guardar / restaurar dependen del sistema).

Entonces ... hablando relativamente:

  • Llamada a función> Acceso a memoria simple.
  • Llamada de función << Acceso a disco: en comparación con la memoria, puede ser cientos de veces más costosa.
  • Llamada de función << Acceso a la memoria en otra computadora: el ancho de banda de la red y el protocolo son los principales asesinos de tiempo aquí.
  • Llamada de función <<< Acceso a disco en otra computadora: todas las anteriores y más :)

No olvidemos que C ++ tiene llamadas virtuales (significativamente más caras, alrededor de x10) y en Windows, puede esperar VS a llamadas en línea (costo 0 por definición, ya que no hay llamadas en el binario)


Si la función está en línea en el momento de la compilación, el costo de la función se vuelve igual a 0.

0 por supuesto, lo que habría obtenido al no tener una llamada de función, es decir: lo ha escrito usted mismo.

Esto, por supuesto, suena excesivamente obvio cuando lo escribo así.


Solo el acceso a la memoria es más rápido que una llamada a función.

Pero la llamada se puede evitar si el compilador con optimización en línea (para compilador (s) de GCC y no solo se activa cuando se utiliza el nivel 3 de optimización (-O3)).


Suponiendo que se refiera a la sobrecarga de la llamada en sí, en lugar de lo que podría hacer el destinatario, definitivamente es mucho, mucho más rápido que todos, excepto el acceso a la memoria "simple".

Probablemente sea más lento que el acceso a la memoria, pero tenga en cuenta que, dado que el compilador puede hacer la alineación, la sobrecarga de llamada a la función a veces es cero. Incluso si no, al menos es posible en algunas arquitecturas que algunas llamadas al código que ya están en la memoria caché de instrucciones sean más rápidas que el acceso a la memoria principal (que no está en la caché). Depende de cuántos registros se deben derramar para apilar antes de realizar la llamada, y ese tipo de cosas. Consulte su compilación y la documentación de la convención de llamadas, aunque es poco probable que pueda resolverlo más rápido que desensamblando el código emitido.

También tenga en cuenta que el acceso a la memoria "simple" a veces no lo es: si el sistema operativo tiene que traer la página desde el disco, entonces tiene una larga espera en sus manos. Lo mismo sería cierto si ingresa al código actualmente asignado al disco.

Si la pregunta subyacente es "¿cuándo debería optimizar mi código para minimizar el número total de llamadas a función realizadas?", Entonces la respuesta es "muy cerca de nunca".


Una llamada a una función generalmente implica solo un par de copias de memoria (a menudo en registros, por lo que no deberían ocupar mucho tiempo) y luego una operación de salto. Esto será más lento que el acceso a la memoria, pero más rápido que cualquiera de las otras operaciones mencionadas anteriormente, ya que requieren comunicación con otro hardware. Lo mismo debería ser cierto en cualquier combinación de OS / idioma.


tiempos relativos (no debería estar fuera de más de un factor de 100 ;-)

  • acceso a memoria en caché = 1
  • función llamada / retorno en caché = 2
  • acceso a la memoria fuera de la memoria caché = 10 .. 300
  • acceso al disco = 1000 .. 1e8 (amortizado depende de la cantidad de bytes transferidos)
    • dependiendo principalmente de los tiempos de búsqueda
    • la transferencia en sí puede ser bastante rápida
    • implica al menos unos pocos miles de operaciones, ya que el umbral del usuario / sistema debe cruzarse al menos dos veces; una solicitud de E / S debe programarse, el resultado debe escribirse; posiblemente se asignan almacenamientos intermedios ...
  • llamadas a la red = 1000 ... 1e9 (amortizado depende de la cantidad de bytes transferidos)
    • mismo argumento que con el disco I / O
    • la velocidad de transferencia bruta puede ser bastante alta, pero algún proceso en la otra computadora debe hacer el trabajo real

Una llamada a la función es simplemente un cambio del puntero del cuadro en la memoria en la pila y la adición de un nuevo cuadro en la parte superior. Los parámetros de la función se desplazan a los registros locales para su uso y el puntero de la pila se avanza a la nueva parte superior de la pila para la ejecución de la función.

En comparación con el tiempo

Llamada de función ~ acceso a memoria simple
Llamada de función <Acceso a disco
Llamada de función <acceso a memoria en otra computadora
Llamada de función <acceso a disco en otra computadora