¿Qué es la predicción de rama en el contexto de las CPU?

Hay varios tipos de ramas vistas en el código (ensamblado). Suelen verse como:

# 0 AGREGAR c, a, b
# 1 RAMA # 4
# 2 AGREGAR b, a, c
# 3 MULTIPLICAR e, b, a
# 4 AGREGAR d, a, b

En este ejemplo, la instrucción de bifurcación provocaría que el procesador omita las instrucciones n. ° 2 y n. ° 3 y vaya directamente al n. ° 4. Un procesador moderno típico trabaja en múltiples instrucciones a la vez en su cartera. Esto generalmente significa que el procesador comenzará a trabajar en la siguiente instrucción antes de que la anterior haya terminado. En el ejemplo anterior, el procesador comenzaría a trabajar en la instrucción n. ° 2 antes de que finalice la instrucción n. ° 1. Sin embargo, cuando finaliza la instrucción n. ° 1, el procesador se da cuenta de que debería haberse omitido el n. ° 2 y descarta el resultado. Esto es un desperdicio tanto de rendimiento potencial como de potencia.

Para evitar esto, el procesador mantiene un historial de sucursales pasadas (vea el artículo vinculado por uno de los carteles anteriores) y adivina si se tomará una sucursal futura o no. Cuanto más precisa sea la predicción de esta rama, menor será el número de ciclos que el procesador desperdiciará las instrucciones de procesamiento que nunca debieron ejecutarse.

Las ramas vienen en muchas formas. El ejemplo anterior es un tipo de rama muy simple llamada rama incondicional. Se llama así porque la rama siempre se tomará. Este es el tipo de rama más fácil de manejar porque el procesador solo tiene que decodificar (es decir, reconocer que es una instrucción de rama, que puede tomar de 1 a 4 ciclos si no más) antes de saber qué hacer.

Sin embargo, las ramas también pueden venir en forma de ramas condicionales:

# 0 COMPARAR a, b
# 1 BEQ # 4
# 2 AGREGAR b, a, c
# 3 MULTIPLICAR e, b, a
# 4 AGREGAR d, a, b

En el ejemplo anterior, BEQ significa branch-if-equal. La instrucción COMPARE compara los valores de las variables a y b y determina si son iguales. La instrucción de bifurcación observará el resultado de la última comparación realizada y saltará a la instrucción n. ° 4 solo si ayb fueron iguales.

Esto es difícil de resolver para un procesador porque debe esperar a que la instrucción # 0 termine de ejecutarse antes de saber si se ramifica o no. En este caso, el procesador vuelve a hacer una suposición educada basada en el historial de la sucursal. Pero esta vez, no sabrá el resultado hasta que finalice la instrucción # 0. Si comienza a funcionar en una instrucción cada ciclo, entonces podría haber comenzado a procesar muchas instrucciones antes de saber que cometió un error.

El último tipo de rama es uno con un objetivo desconocido. Por ejemplo:

# 0 COMPARAR a, b
# 1 AGREGAR c, a, b
# 2 BEQ c
# 3 AGREGAR b, a, c
# 4 MULTIPLICAR e, b, a
# 5 AGREGAR d, a, b

En este ejemplo, el procesador no solo no sabe si saltar (ramificarse) cuando comienza a procesar la instrucción # 2, sino que tampoco sabe a dónde saltar ya que la variable c aún no se ha determinado; la instrucción n. ° 1 debe terminar primero.

Para este tipo de rama, los procesadores generalmente contienen algo llamado búfer de destino de rama. Este puede ser un búfer de entradas múltiples en el que el procesador almacena direcciones anteriores a las que se ha saltado. Cada vez que se ejecuta una instrucción de bifurcación (digamos, # 2), el procesador almacena el objetivo (el valor de c) al que saltó. La próxima vez que se ejecute la misma instrucción (# 2, por ejemplo en un bucle), utiliza el valor en el búfer de destino de la rama.

Todo esto es una conjetura del procesador. Si acierta, puede ejecutar una secuencia de instrucciones sin interrupciones. Si adivina mal, ha pasado mucho tiempo ejecutando instrucciones que no debería tener y luego tendrá que enjuagar esas instrucciones y comenzar de nuevo con las correctas. En los microprocesadores actuales, las etapas de la tubería (es decir, el número de ciclos que tarda un procesador en procesar una instrucción de principio a fin) varían entre 8 etapas (ARM Cortex A9) y 31 etapas (Pentium 4 a 65 nm).

Poder predecir ramas correctamente es una de las funciones más críticas del rendimiento de un procesador, así como del consumo de energía.

Cada vez que hay un punto de decisión en el código, hay una rama con una de dos opciones. El código puede tomar la opción 1 o la opción 2. La opción que toma el código depende de una condición.

La predicción de bifurcación de la CPU intenta predecir qué dirección tomará el código antes de que se resuelva la condición de la que depende la bifurcación. Entonces, ¿por qué es útil? La CPU puede seguir trabajando haciendo una suposición sobre la dirección de la rama antes de que se resuelva la condición en lugar de esperar y esperar a que se resuelva la condición de la que depende la rama. En el peor de los casos, la predicción es incorrecta y la CPU tiene que descartar el trabajo que realizó en base a la suposición errónea una vez que se resuelve la condición. Sin embargo, esto no es realmente malo, ya que la CPU no habría estado haciendo nada si hubiera esperado a que se resolviera la condición. En el mejor de los casos, la predicción es correcta y la CPU realizó un trabajo útil mientras esperaba que se resolviera la condición.

Entonces, ¿cómo hace la CPU la predicción? Al mirar el pasado. El código generalmente atraviesa el mismo camino que tenía en el pasado. Por ejemplo, si escribe un bucle for con 10 iteraciones, 10 de las 11 veces que se alcanza la condición de bucle, reiniciará el bucle. Entonces, la CPU almacena un historial de lo que sucedió en el pasado y va con lo que sucedió con más frecuencia en el pasado para hacer su predicción. Estoy simplificando demasiado y hay una página de wikipedia sobre esto para más. http://en.wikipedia.org/wiki/Bra

Un problema, su causa y la explicación de la predicción de rama se documenta excelentemente aquí:

http://stackoverflow.com/questio