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í
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.
Los tres riesgos y qué los resuelve
| Riesgo | Qué lo causa | Cómo se resuelve |
|---|---|---|
| De datos | una instrucción necesita un resultado que todavía no se escribió | adelantamiento, y burbujas si no alcanza |
| De control | un salto: no se sabe qué instrucción sigue | predicción, y descartar si falla |
| Estructural | dos instrucciones quieren el mismo recurso | duplicar el recurso, o esperar |
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?
Práctica