¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Solapar instrucciones para ir más rápido (segmentación)

Después de esta lección: Puedo explicar cómo acelera la segmentación un procesador y qué la detiene.

Lección de 55 min10 comandosLaboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

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

PalabraQué significaEjemplo
Segmentaciónhacer a la vez los pasos de varias instrucciones, cada una en una etapa
Etapaun paso de la segmentación, que dura un ciclo de relojEX
Riesgoalgo que impide que la instrucción siguiente empiece a tiempo
Paradaun ciclo en que una etapa espera sin hacer trabajo útil
Adelantamientopasar un resultado a la instrucción siguiente antes de escribirlo
Predicción de saltosadivinar 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ónCiclo 1Ciclo 2Ciclo 3Ciclo 4Ciclo 5Ciclo 6Ciclo 7
addi t0, zero, 4IFIDEXMEMWB
addi t1, zero, 5IFIDEXMEMWB
addi t2, zero, 6IFIDEXMEMWB

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Entra en la carpeta de arquitectura

Comando
cd ~/arch

Se 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 anteriorCuántas antes de la que la usaParadas sin adelantamientoParadas con adelantamiento
add o addi1 instrucción20
add o addi2 instrucciones10
lw1 instrucción21
lw2 instrucciones10
Cualquiera3 o más00

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Escribe un programa con un riesgo de carga

Comando
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.s

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ensámblalo

Comando
riscv64-linux-gnu-as dependencia.s -o dependencia.o

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Enlázalo

Comando
riscv64-linux-gnu-ld dependencia.o -o dependencia

Se 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

Comando
qemu-riscv64 ./dependencia

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 estado de salida

Comando
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

Comando
riscv64-linux-gnu-objdump -d dependencia

Se 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

Comando
riscv64-linux-gnu-gcc -O2 -march=rv64gc -S loop.c

Se 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

Comando
grep -A 4 'L6:' loop.s

Se 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

Comando
grep -A 4 'L9:' loop.s

Se 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.

Sobre este laboratorio y su código: Laboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.