Atlasingeniería

Arquitectura y sistemas operativosArquitectura del procesadorTema 3

Pipeline y riesgos

Segmentar el ciclo en etapas permite tener varias instrucciones en vuelo y multiplicar el rendimiento. Los problemas empiezan cuando una instrucción necesita algo que la anterior todavía no terminó.

Para este tema conviene tener claro:Ciclo de instrucción y camino de datos

Si cada instrucción pasa por cinco etapas y se espera a terminar una para empezar la siguiente, cuatro quintos del procesador están ociosos todo el tiempo. El pipeline resuelve eso como una línea de montaje: cada etapa trabaja sobre una instrucción distinta, simultáneamente.

Una instrucción por ciclo aunque cada una tarde cinco

Con cinco etapas y el pipeline lleno, se completa una instrucción por ciclo aunque cada una tarde cinco. El rendimiento se multiplica sin que la latencia individual baje.

Además, como cada etapa es más corta que el ciclo completo, el reloj puede ser más rápido. Ese es el doble beneficio, y es el motivo por el que todos los procesadores modernos están segmentados —los actuales con quince etapas o más, no cinco—.

Antes de seguir, predecí

Un salto condicional mal predicho en un procesador con pipeline profundo. ¿Qué cuesta?

El riesgo de datos y el adelantamiento

El primer problema es el riesgo de datos: una instrucción necesita un resultado que la anterior todavía no escribió. Sumar y usar inmediatamente esa suma significa leer un registro que aún no se actualizó.

La solución es el adelantamiento: conectar la salida de la ALU directo a la entrada de la etapa siguiente, sin esperar a que pase por el banco de registros. Resuelve la mayoría de los casos, pero no todos: una carga de memoria seguida del uso inmediato del dato obliga a una burbuja, porque el dato no existe hasta la etapa de memoria.

El riesgo de control, que es el caro

El riesgo más caro es el de control. Cuando se decodifica un salto condicional, el procesador ya empezó a traer las instrucciones siguientes en secuencia. Si el salto se toma, todas están mal y hay que descartarlas.

Con un pipeline profundo eso son diez o veinte ciclos perdidos por salto mal resuelto. Y los saltos son frecuentísimos: cada if, cada ciclo, cada llamada. Sin una solución, la segmentación no rendiría lo prometido.

Predecir y ejecutar especulativamente

La solución es predecir. El predictor de saltos apuesta a si se va a tomar y por dónde, y el procesador ejecuta especulativamente por ese camino; si acertó, no se perdió nada, y si erró, descarta el trabajo.

Los predictores modernos aciertan más del 95% usando historia por salto y patrones globales. De ahí sale un consejo práctico real: un ciclo con una condición predecible corre mucho más rápido que uno con una condición aleatoria, y por eso ordenar los datos a veces acelera código que ni siquiera depende del orden.

Superescalar y fuera de orden

Los procesadores actuales van bastante más lejos. Son superescalares —varias instrucciones por ciclo en paralelo— y ejecutan fuera de orden: si una instrucción espera un dato de memoria, se adelantan las que ya tienen todo listo, conservando la ilusión de orden al confirmar los resultados.

Eso convierte al procesador en algo bastante distinto de lo que el ensamblador sugiere. Y tiene un costo que se descubrió tarde: la ejecución especulativa deja rastros en la caché, y de ahí salieron Spectre y Meltdown, vulnerabilidades en la arquitectura misma y no en el software.

Qué significa esto al escribir código

Para quien escribe código, esto se traduce en unas pocas cosas. Las ramas impredecibles cuestan, y a veces conviene reemplazarlas por operaciones sin salto —una asignación condicional, una operación aritmética—.

Las cadenas de dependencias limitan el paralelismo: cinco sumas independientes se ejecutan casi gratis, cinco sumas encadenadas no. Y, sobre todo, el rendimiento real deja de ser “contar instrucciones”: una instrucción que espera memoria vale cientos de las otras.

El riesgo, ciclo por ciclo

Sin pipeline: cada instrucción espera a que termine la anterior. Cinco ciclos por instrucción y cuatro quintos del procesador sin hacer nada.

1 / 6
Seguí el ciclo 4: la segunda instrucción está decodificando y necesita r1, que la primera recién va a escribir en el ciclo 6. Dos ciclos de diferencia, y el hardware tiene que hacer algo con eso: frenar o adelantar el valor. Ése es todo el problema, y se ve mirando una columna.

Los tres riesgos y qué los resuelve

RiesgoQué lo causaCómo se resuelve
De datosuna instrucción necesita un resultado que todavía no se escribióadelantamiento, y burbujas si no alcanza
De controlun salto: no se sabe qué instrucción siguepredicción, y descartar si falla
Estructuraldos instrucciones quieren el mismo recursoduplicar el recurso, o esperar
El de control es el más caro en procesadores profundos: con veinte etapas, una predicción fallida descarta veinte instrucciones a medio ejecutar.

Cierre

El pipeline solapa etapas y completa una instrucción por ciclo. Los riesgos de datos se resuelven adelantando resultados; los de control, prediciendo y especulando. Lo que queda para el programador es evitar ramas impredecibles y cadenas largas de dependencias.

Autoevaluación

¿Lo entendiste?

Con el pipeline lleno, ¿qué mejora?
¿Qué es un riesgo de datos?
¿Qué caso el adelantamiento no puede resolver?
¿Por qué los procesadores modernos tienen quince etapas o más?