Un túnel de lavado con cinco zonas
Un túnel de lavado tiene cinco zonas: mojar, enjabonar, cepillar, aclarar y secar. Cada zona tarda un minuto.
Si el túnel lavara un solo coche cada vez, saldría un coche cada cinco minutos. Pero cada zona trabaja con un coche distinto a la vez. Cada coche sigue tardando cinco minutos, y aun así sale uno limpio cada minuto. El procesador hace lo mismo con las instrucciones.
Al final de esta lección
Nota
Puedo explicar cómo acelera la segmentación un procesador y qué la detiene.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Segmentación | hacer a la vez los pasos de varias instrucciones, cada una en una etapa | |
| Etapa | un paso de la segmentación, que dura un ciclo de reloj | EX |
| Riesgo | algo que impide que la instrucción siguiente empiece a tiempo | |
| Parada | un ciclo en que una etapa espera sin hacer trabajo útil | |
| Adelantamiento | pasar un resultado a la instrucción siguiente antes de escribirlo | |
| Predicción de saltos | adivinar hacia dónde irá un salto antes de calcularlo |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Cinco etapas, cinco instrucciones a la vez
Una segmentación clásica de RISC-V tiene cinco etapas. IF busca la instrucción. ID la decodifica y lee los registros. EX hace el cálculo, MEM lee o escribe la memoria y WB escribe el resultado en un registro.
Cada etapa dura un ciclo de reloj. Mientras una instrucción está en EX, la siguiente está en ID y la de después en IF. Así, hasta cinco instrucciones están dentro del procesador a la vez.
Ejemplo resuelto: tres instrucciones sin riesgos
| Instrucción | Ciclo 1 | Ciclo 2 | Ciclo 3 | Ciclo 4 | Ciclo 5 | Ciclo 6 | Ciclo 7 |
|---|---|---|---|---|---|---|---|
| addi t0, zero, 4 | IF | ID | EX | MEM | WB | ||
| addi t1, zero, 5 | IF | ID | EX | MEM | WB | ||
| addi t2, zero, 6 | IF | ID | EX | MEM | WB |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Entra en la carpeta de arquitectura
cd ~/archSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Más rápido sin acelerar ninguna instrucción
Una tras otra, 50 instrucciones de 5 ciclos tardan 250 ciclos. Con segmentación, la primera acaba tras 5 ciclos y después acaba una más en cada ciclo. Así que 50 instrucciones tardan 5 + 49, es decir, 54 ciclos.
Cada instrucción sigue tardando 5 ciclos de principio a fin. Lo que crece es cuántas terminan en cada ciclo. Eso solo se cumple mientras nada obliga a una instrucción a esperar.
Un resultado que aún no está listo
Un riesgo es un motivo por el que la instrucción siguiente no puede seguir a tiempo. El más común es el riesgo de datos: una instrucción necesita un registro que otra anterior aún no ha terminado.
Sin ayuda, la segmentación hace una parada hasta que el valor se escribe. El adelantamiento ahorra casi toda la espera: el resultado de EX pasa directo a la instrucción siguiente. Una carga es distinta. Su valor solo existe tras MEM, así que la instrucción de justo después espera un ciclo.
Ejemplo resuelto: ciclos de parada en nuestro modelo
| La instrucción anterior | Cuántas antes de la que la usa | Paradas sin adelantamiento | Paradas con adelantamiento |
|---|---|---|---|
| add o addi | 1 instrucción | 2 | 0 |
| add o addi | 2 instrucciones | 1 | 0 |
| lw | 1 instrucción | 2 | 1 |
| lw | 2 instrucciones | 1 | 0 |
| Cualquiera | 3 o más | 0 | 0 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Escribe un programa con un riesgo de carga
printf '.globl _start\n_start:\n addi sp, sp, -16\n li t0, 20\n sw t0, 0(sp)\n lw a0, 0(sp)\n addi a0, a0, 5\n li a7, 93\n ecall\n' > dependencia.sSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ensámblalo
riscv64-linux-gnu-as dependencia.s -o dependencia.oSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Enlázalo
riscv64-linux-gnu-ld dependencia.o -o dependenciaSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecútalo en el emulador
qemu-riscv64 ./dependenciaSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lee el estado de salida
echo $?Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lee el código máquina
riscv64-linux-gnu-objdump -d dependenciaSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un error frecuente
Advertencia
Mucha gente cree que la segmentación hace que cada instrucción vaya más rápido. No es así: cada instrucción sigue pasando por las cinco etapas. Lo que hace es terminar más instrucciones por ciclo. Una parada tira parte de esa ganancia, y por eso importa el orden de las instrucciones.
El compilador rellena el hueco
Un compilador conoce las reglas de parada. Si a una carga le sigue una instrucción que la necesita, busca otra instrucción que no la necesite y la coloca en medio.
Los Run siguientes compilan el loop.c del laboratorio para RISC-V. Mira los dos bucles que suman, .L6 y .L9, y busca qué hay entre cada carga y su suma.
Compila loop.c a ensamblador RISC-V
riscv64-linux-gnu-gcc -O2 -march=rv64gc -S loop.cSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
El bucle por filas
grep -A 4 'L6:' loop.sSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
El bucle por columnas
grep -A 4 'L9:' loop.sSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Adivinar hacia dónde va un salto
Un salto crea un riesgo de control: hasta que EX resuelve la prueba, la segmentación no sabe qué buscar después. Esperar costaría ciclos en cada salto.
Por eso el procesador usa la predicción de saltos. Adivina y sigue adelante. Si acierta, no pierde nada; si falla, tira el trabajo buscado desde el salto y vuelve a empezar. El bne del final de un bucle vuelve atrás casi siempre, así que es fácil de adivinar.
Para ir más lejos: reordenar sin paradas
Toma este programa: lw t0, 0(a1), sub t1, t0, a2, lw t2, 8(a1), sub t3, t2, a2. Cuenta sus paradas con adelantamiento usando tu función.
Después reordena las cuatro líneas para que el resultado sea el mismo y no haya ninguna parada. Explica qué regla usaste para decidir que un cambio de orden era seguro.