Repository navigation
S15

- Tiempo: 2h
-
Objetivos de la sesión:
- Aplicar el modelo de segmentación al NanoRisc-V
- Calcular el rendimiento
- Conocer las causas por las que el rendimiento disminuye
- Introducción
- Etapas en el Nano-RISC-V segmentado
- Pérdidas de rendimiento
- Riesgos
- Conclusiones
- Lecturas del Libro de Referencia
- Ejercicios
- Resolución de ejercicios del laboratorio
- Autores
- Licencia
- Créditos
- Enlaces
El procesador NanoRisc-V lo segmentamos en 5 etapas, y esto hace que su rendimiento mejore. Sin embargo, no conseguiremos la mejora del rendimiento teórica. Este rendimiento será menor debido al balanceo de las etapas y los riesgos
En el modelo segmentando del NanoRisc-V cada etapa se ejecuta en un ciclo de reloj. Las etapas se separan mediante los registros de etapa, que contienen el resultado de la ejecución de esa etapa. En cada una de las etapas se usa sólo un recurso
El modelo lo describimos así. A este nivel se han omitido varios detalles. Sólo se deja lo esencial para comprender el modelo

Tenemos en total 5 etapas separadas por 4 registros de etapa. El resultado de la etapa 5 (Write-Back) se almacena en el banco de registros o en la memoria de datos
- Fetch: La instrucción capturada se guarda en el registro IR (Instruction Register)
- Decodificación: Se leen los operandos indicados por la instrucción, y se almacenan en los registros OP1 y OP2
- Ejecución: Se ejecuta la instrucción. La salida de la ALU se guarda en el registro Res (Result)
- Acc. Memoria: El dato leído de memoria se almacena en el registro MD (Memory data)
- Write-Back: Se almacena el registro destino o el dato en memoria (si es una instrucción store)
Con el modelo segmentando se llegan a ejecutar 5 instrucciones en paralelo, cuando el pipeline se ha llenado. En este ejemplo sólo vamos a ejecutar una instrucción, y supondremos que en paralelo se ejecuta la instrucción nop (No operation)
La instrucción a probar es addi x1, x0, 1 (Que se corresponde con la pseudoinstrucción li x1,1). En total tarda 5 ciclos de reloj en ejecutarse. Al final de cada ciclo se actualizan los registros de etapa. Supondremos que inicialmente el registro x1 vale 0

Al finalizar el ciclo 5, el valor del registro x1 es 1
En esta figura se muestra lo que ocurre al ejecutar las dos instrucciones siguientes:
addi x1,x0,1
addi x2,x0,2Al terminar de ejecutarlas, los registros tendrán los siguientes valores: x1=1, y x2=2

Al terminar el ciclo 5, se actualiza el valor del registro x1 a 1. En el siguiente ciclo el registro x2 vale 2. Esta es la magina del pipeline: una vez ejecutada la primera instrucción, las demás sólo tardan 1 ciclo de reloj
Este funcionamiento ya lo conocíamos, pero lo hemos aplicado para asentar su funcionamento y encontrar qué problemas ocurren
Dado que el NanoRISC-v segmentado tiene 5 etapas, el rendimiento relativo teórico que obtendríamos sería de 5. Es decir, que iría 5 veces más rápido que el monociclo, a partir de la ejecución de la primera instrucción (el pipeline está lleno). Intutitivamente sabemos que va 5 veces más rápido porque hay 5 instrucciones ejecutándose en paralelo
Sin embargo, debido a que NO todas las etapas duran lo mismo, hay que elegir la etapa peor. Por lo que el rendimiento ya no será el teórico, sino menor. Con los datos que usamos en este apartado de la sesión anterior, el rendimiento relativo será ahora de 5 / 1.25 = 4. Ha caído de 4 a 5
Además, el rendimiento cae debido a otros factores que veremos a continuación: LOS RIESGOS
En condiciones normales, el pipeline estará lleno: todas las etapas estarán ejecutando instrucciones útiles. Y por tanto tendremos el máximo rendimiento posible. Sin embargo, existen situaciones en las que la siguiente instrución NO se puede ejecutar en el siguiente ciclo de reloj. Estos eventos los denominamos riesgos. Existen tres tipos de riesgos
El hardware NO puede ejecutar las instrucciones en el mismo ciclo. Esto ocurre por ejemplo si un mismo recurso se tiene que usar en dos etapas diferentes. Estos riesgos aparecen porque NO se ha diseñado adecuadamente la segmentación
El juego de instrucciones de los RISC-V se ha diseñado para que se pueda segmentar fácilmente y se eviten los riesgos estructurales.
Si por ejemplo se utilizase una única memoria (física) para el código y los datos, en vez de dos separadas como hemos hecho en nuestro Nano-RISC-V, habría un riesgo estructural: las etapas de fetch y de lectura del operando no se podrían realizar a la vez si una de las instrucciones es de load, ya que al llegar a la fase de memoria no se podría hacer Fetch de la siguiente instrucción
Los riesgos de datos ocurren si una etapa debe esperar a que termine otra para poder completarse. El pipeline se debe detener en ese momento, o de lo contrario se tendrían resultados incorrectos
Como ejemplo vamos a analizar lo que ocurre con este programa de dos instrucciones, CASI igual al que hemos simulado en los apartados anteriores. Supondremos que inicialmente todos los registros están inicializados a 0
addi x1,x0,1
addi x2,x1,2Tras ejecutar el programa, el registro x2 debería valer 3 (x1 = 1, x2 = x1 + 2 = 3). Pero veamos lo que sucede:

¡x2 vale 2!. Es un resultado INCORRECTO!!! ¿Qué ha pasado?
Hay una dependencia de datos. La segunda instrucción sólo funcionará correctamente una vez que el registro x1 tenga el valor correcto

El valor de x1 sólo se obtiene en el ciclo 5. Por tanto, hasta que no se llegue al ciclo 5, la segunda intrucción NO puede usar el valor del registro x1
¿Cómo se puede solucionar?
Hay dos soluciones, una software (a nivel del compilador) y otra Hardware
Estas soluciones se implementan a nivel de las instrucciones de ensamblador. Añadiendo instrucciones nop para introducir ciclos de retraso o bien reorganizando su orden de ejecución
Siguiendo con el ejemplo anterior, logramos que el programa funcione correctamente retrasando al menos 3 ciclos la ejecución de la segunda instrucción. De esta forma garantizamos que cuando se ejecuta la segunda ya está disponible el valor correcto del registro x1

Cuando se detiene el pipeline un ciclo, decimos informalmente que aparece una burbuja. Con ello indicamos que la etapa NO está haciendo trabajo útil (y cuando no se hace trabajo útil, el rendimiento cae)
El programa correcto, que soluciona ese riesgo de datos es este:
addi x1,x0,1
nop
nop
nop
addi x2,x1,2El precio a pagar es que el rendimiento cae mucho. Un programa de 2 instrucciones sin riesgo tarda 6 ciclos. Al haber riesgo de datos ahora sube a 9 ciclos!!!
En vez de introducir instrucción nop en algunos casos puede ser posible meter otras instrucciones del programa que sea útil, pero que no generen riesgo de datos. En esta solución se reorganiza el orden de ejecución de las instrucciones para que no haya riesgos de datos, o al menos, reducirlos
Imaginemos que tenemos este programa que inicializa los registros x3,x4 y x5 y luego ejecuta las dos instrucciones anteriores que tiene el riesgo de datos:
addi x3,x0,3 #-- Inicializar x3
addi x4,x0,4 #-- Inicializar x4
addi x5,x0,5 #-- Inicializar x5
addi x1,x0,1 #-- Inicializar x1
addi x2,x1,1 #-- x2 = x1 + 1 (Riesgo de datos)Este código se podría reorganizar de manera que se elimine el riesgo de datos, y el resultado sea exactamente el mismo. Bastaría con llevarnos la inicialización del registro x1 al comienzo
addi x1,x0,1 #-- Inicializar x1
addi x3,x0,3 #-- Inicializar x3
addi x4,x0,4 #-- Inicializar x4
addi x5,x0,5 #-- Inicializar x5
addi x2,x1,1 #-- x2 = x1 + 1 (YA NO HAY Riesgo de datos)Esta reorganización del código la realiza el compilador, y no siempre será posible solucionarlo totalmente. Al final, siempre habrá algún caso en el que se tengan introducir instrucciones nop
En esta solución es necesario añadir hardware. NO se pueden solucionar todos los riesgos, pero al menos se minimizan el número de instrucciones nop a introducir
Vamos visualizar las siguientes dos instrucciones en el diagrama de segmentación:
addi x1,x0,1
addi x2,x1,2
En la solución hardware no hace falta esperar a que se escriba el registro x1 en la etapa de write-back. El valor que se escribirá en x1 está disponible al final de la etapa de ejecución (ALU), que se almacena en el registro res. Este valor se puede reintroducir en la etapa de ejecución de la instrucción siguiente, si detecta que es necesario
De esta manera, se solucionaría por completo ese riesgo de datos concreto
Pero ¿qué ocurre en este caso?
ld x1, 0(x5)
addi x2,x1,2Ahora el registro x1 se carga desde la memoria de datos. El valor a introducir en x1 está disponible al finalizar la etapa de acceso a memoria (ciclo 3, 800ps). Sin embargo la etapa de ejecución de la siguiente instrucción ya ha comenzado (ha empezado en el ciclo 2, 600ps). Por tanto, el adelantamiento NO ES POSIBLE

La solución es meter una instrucción nop para generar un ciclo de retraso y poder aplicar el adelantamiento

La solución es mixta: se usa el adelantamiento pero hay que introducir una instrucción nop, en este caso
ld x1, 0(x5)
nop
addi x2,x1,2La implementación segmentada nos ofrece un mayor rendimiento. Sin embargo, su implementación no es tan sencilla como parecía al comienzo. La ejecución de instrucciones en paralelo presenta problemas, que se traducen en una caída del rendimiento y un aumento de la complejidad en el hardware y/o en el software (compiladores)
Libro de referencia: "Computer Organization and Design. Hardware/Software interface. Risc-V"
- Apartado 4.5: An Overview of Pipelining (Pag 267-271)
Ejercicios para practicar y asimilar los conceptos más importantes
Se tiene un programa de prueba para un procesador Risc-V formado por una única instrucción:
li x5,5Se dispone de los siguientes computadores:
- Computador A: Risc-V monociclo. Frecuencia: 1Ghz
- Computador B: Risc-V segmentando. 5 etapas. Frecuencia: 3Ghz
Se pide:
- a) Calcular el tiempo que tarda el computador A en ejecutar el programa de pruebas
- b) Calcular el tiempo que tarda el computador B en ejecutar el programa de pruebas
- c) Calcular el rendimiento relativo. Usando sólo ese programa de pruebas, ¿Qué computador ofrece mejor rendimiento?
Seguimos usando los mismos computadores A y B anteriores. Pero ahora tenemos un programa de prueba formado por 2 instrucciones:
li x5,5
li x6,6Se pide:
- a) Calcular el tiempo que tarda el computador A en ejecutar el programa de pruebas
- b) Calcular el tiempo que tarda el computador B en ejecutar el programa de pruebas
- c) Calcular el rendimiento relativo. Usando sólo ese programa de pruebas, ¿Qué computador ofrece mejor rendimiento?
Disponemos de 3 computadores, A, B y C, con las siguientes características:
- Computador A: RISC-V Monociclo. Frecuencia de 1Ghz
- Computador B: RSIC-V segmentando en 5 etapas. SIN adelantamiento de datos. Frecuencia de 3Ghz
- Computador C: RISC-V segmentado en 5 etapas. CON adelantamiento de datos. Frecuencia de 3Ghz
Tenemos el siguiente programa de pruebas formado por 2 instruciones:
li x5,5
mv x6,x5El programa ensamblador, que convierte este programa a código máquina, realiza una primera etapa en la que modifica el programa para que pueda funcionar correctamente en el comptador indicado, solucionando por software los problemas que puede haber. Tras esta fase se genera el programa ejecutable final (código máquina)
Se pide
- a) Tiempo que tarda en ejecutar en el computador A
- b) Tiempo que tarda en ejecutarse en el computador B
- c) Tiempo que tarda en ejecutarse en el computador C
Disponemos de los mismos computadores A,B y C del apartado anterior, y del mismo ensamblador. Pero ahora el programa de pruebas es el siguiente:
ld x5,0(x0)
mv x6,x5Se pide
- a) Tiempo que tarda en ejecutar en el computador A
- b) Tiempo que tarda en ejecutarse en el computador B
- c) Tiempo que tarda en ejecutarse en el computador C
La segunda parte de la clase la vamos a dedicar al Laboratorio, para seguir programando
- Katia Leal Algara
- Juan González-Gómez (Obijuan)


S1: Introducción a los computadores
S2: Computadores y Rendimiento (I)
S3: Computadores y Rendimiento (II)
S4: Memorias Caché
Ejercicios
S5: ISA. Repertorios CISC y RISC
S6: Almacenamiento de operandos. ISA-RISCV
S7: Modos de direccionamiento. Tipos de instrucciones
S8: Ejercicios
S9: Nivel de Electrónica Digital
S10: El computador NanoRisc-V
S11: NanoRISC-V Monociclo (I)
S12: NanoRISC-V Moniciclo (II). Ejercicios
S13: Procesador NanoRISC-V Multiciclo
S14: Segmentación y rendimiento
S15: NanoRISC-V segmentado
- TODO
P1: Introducción a la Pico2
P2: Rendimiento en la Pico2
P3: Memoria caché
P4: Display de 7 segmentos
P5: Zumbador
GISAM. Ordinario. 2021-Ene-21
GISAM. Ordinario. 2022-Ene-10
GISAM. Extra. 2022-Jun-29
GISAM. Parcial 1. 2022-Oct-26
GISAM. Parcial 2. 2022-Nov-30
GISAM. Parcial 3. 2022-Dic-21
GISAM. Parcial 1. 2023-Oct-09
GISAM. Parcial 2. 2023-Nov-11
GISAM. Parcial 3. 2023-Dic-20
GISAM. Extra. 2024-Jun-17
GISAM. Parcial 1. 2024-Oct-14
GISAM. Parcial 2. 2024-Nov-11
GISAM. Parcial 3: 2024-Dic-12
GISAM. Parcial 1: 2025-Oct-20
GISAM. Parcial 2: 2025-Nov-19
GISAM. Parcial 3: 2026-Ene-09
GISAM. Extra. 2026-Jun-11
GISAM. Parcial 1: 2026-Oct-21
ROBOTICA. Parcial 1. 2022-Feb-25
ROBOTICA. Parcial 2. 2022-Abr-1
ROBOTICA. Parcial 3. 2022-May-6
ROBOTICA. Parcial 1. 2023-Feb-27
ROBOTICA. Parcial 2. 2023-Mar-27
ROBOTICA. Parcial 3. 2023-May-08
ROBOTICA. Parcial 1. 2024-Feb-25
ROBOTICA. Parcial 2. 2024-Mar-20
ROBOTICA. Parcial 3. 2024-May-06
ROBOTICA.Extra. 2024-Jun-24
ROBOTICA. Parcial 1. 2025-Feb-24
ROBOTICA. Parcial 2. 2025-Mar-31
ROBOTICA. Parcial 3. 2025-May-19
ROBOTICA. Extra. 2025-Jun-24
ROBOTICA. Parcial 1. 2026-Feb-23
ROBOTICA. Parcial 2. 2026-Abr-13
ROBOTICA. Parcial 3. 2026-May-11
TELECO. Parcial 1. 2023-Oct-20
TELECO. Parcial 2. 2023-Nov-17
TELECO. Parcial 3. 2023-Dic-22
TELECO. Parcial 1. 2024-Oct-10
TELECO. Parcial 2. 2024-Nov-21
TELECO. Parcial 3. 2024-Dic-19
TELECO. Parcial 1. 2025-Oct-10
TELECO. Parcial 2. 2025-Nov-13
TELECO. Parcial 3. 2025-Dic-19
TELECO. Parcial 1. 2026-Oct-08
DATOS. Parcial 1. 2025-Oct-15
DATOS. Parcial 2. 2025-Nov-19
DATOS. Parcial 3. 2025-Dic-17
Extra 2026
Tema 1: Sesiones S3 y S4
Tema 2: Sesiones S5, S6 y S7
Tema 3: Sesiones S9, S10, S11 y s13
Tema 4: Sesiones S14 y S15