2011-11-02 13 views
7

¿La desreferenciación de un puntero es notablemente más lenta que solo acceder a ese valor directamente? Supongo que mi pregunta es: ¿qué tan rápido es el operador de deferencia?¿Cuánto afecta la indirección del puntero a la eficiencia?

+3

¿Le preocupa la velocidad o la memoria? – ruslik

+0

¿Su pregunta es sobre la velocidad o la memoria? –

+1

Imposible responder en general. Un acceso de memoria que llegue a la memoria caché L1 será cientos (posiblemente miles) de veces más rápido que uno que tenga que acceder a la memoria RAM real. No especules; punto de referencia. – Nemo

Respuesta

20

Pasando por un puntero indirectamente puede ser mucho más lento debido a cómo funciona una CPU moderna. Pero no tiene mucho que ver con la memoria de tiempo de ejecución.

En cambio, la velocidad se ve afectada por la predicción y el caché.

La predicción es fácil cuando el puntero no se ha cambiado o cuando se cambia de forma predecible (por ejemplo, aumentar o disminuir en cuatro en un bucle). Esto permite que la CPU se ejecute esencialmente antes de la ejecución del código real, descubra cuál va a ser el valor del puntero y cargue esa dirección en la memoria caché. La predicción se vuelve imposible cuando el valor del puntero se genera mediante una expresión compleja, como una función hash.

La memoria caché entra en juego porque el puntero puede apuntar a la memoria que no está en la memoria caché y deberá ser captada. Esto se minimiza si la predicción funciona, pero si la predicción es imposible, en el peor de los casos, puede tener un doble impacto: el puntero no está en la memoria caché y el puntero no está en la memoria caché tampoco. En ese peor caso, la CPU se pararía dos veces.

Si el puntero se utiliza para un puntero de función, el predictor de bifurcación de la CPU entra en juego. En las tablas virtuales de C++, los valores de las funciones son todos constantes y el predictor lo tiene fácil. La CPU tendrá el código listo para ejecutarse y en la tubería cuando la ejecución pase por el salto indirecto. Pero, si se trata de un puntero de función impredecible, el impacto en el rendimiento puede ser pesado porque la tubería tendrá que ser enjuagada, lo que desperdicia 20-40 ciclos de CPU con cada salto.

+0

Ok, así que si tengo un par de bucles anidados que utilizan una memoria intermedia (cada vez que se utiliza el búfer se elimina referencia a un puntero dos veces en este FNC), los valores de puntero (presumiblemente) ser predecible? Y realmente no importará en general? – user965369

+2

Si el búfer es lo suficientemente pequeño como para caber en la memoria caché, los accesos a la memoria serán muy rápidos, ya sean predecibles o no. – Nemo

+0

@ user965369: Haga todo lo posible para asegurarse de que el búfer se ajuste a la memoria caché L1, si no puede hacerlo, al menos hágalo encajar en la memoria caché L2. Para velocidad máxima, procese búferes más grandes en bloques del tamaño de caché. –

2

se requiere un acceso a memoria más:

  1. leer la dirección almacenada en el puntero variable de
  2. leer el valor en la dirección de lectura

Esto no podría ser igual a 2 funcionamiento sencillo , porque puede requerir también más tiempo debido al acceso a una dirección que aún no está cargada en la memoria caché.

+0

Se requiere un acceso * Memoria * más, que puede ser prohibitivo en un circuito cerrado. No todas las operaciones de la CPU son iguales. –

+0

yes..you son right..I fijado mi respuesta – Heisenbug

2

Lo hace. Cuesta una búsqueda extra.
Al acceder a una variable por valor, la variable se lee directamente desde su ubicación de memoria.
Al acceder al mismo puntero a través se agrega una sobrecarga para recuperar la dirección de la variable del puntero y luego leer el valor de esa ubicación de memoria.

Por supuesto, suponiendo que la variable no se coloca en un registro, lo que sería en algunos escenarios como bucles apretados. Creo que la Pregunta busca respuesta de un overhead asumiendo que no existen tales escenarios.

3

Depende de cosas como:

  • si el valor "directamente visitada" es en un registro ya, o en la pila (que es también un direccionamiento indirecto de puntero)
  • si la dirección de destino está en la memoria caché ya
  • la arquitectura de memoria caché, etc. arquitectura de bus

es decir, demasiadas variables a especular sobre útilmente sin restringir su alcance.

Si realmente desea saberlo, compárelo en su hardware específico.

2

Suponiendo que usted está tratando con un puntero real (no un puntero inteligente de algún tipo), la operación de eliminar la referencia no consume memoria (datos) en absoluto. Sin embargo, implica (potencialmente) una referencia de memoria adicional: una para cargar el puntero, la otra para acceder a los datos apuntados por el puntero.

Si está utilizando un puntero en un bucle estrecho, sin embargo, que va a ser cargado normalmente en un registro de la duración. En este caso, el costo es principalmente en términos de presión de registro adicional (es decir, si usa un registro para almacenar ese puntero, no puede usarlo para almacenar algo más al mismo tiempo). Si tiene un algoritmo que de otro modo exactamente llena los registros, pero con el registro de un puntero se desbordará a la memoria, puede hacer una diferencia. Hubo un tiempo en que fue una pérdida bastante grande, pero con la mayoría de las CPU modernas (con más registros y caché a bordo) rara vez es un gran problema. La excepción obvia sería una CPU integrada con menos registros y sin caché (y sin memoria en el chip).

La conclusión es que por lo general es bastante insignificante, a menudo por debajo del umbral en el que incluso se puede medir de forma fiable.

Cuestiones relacionadas