S15 - myTeachingURJC/Arq-computadores-01 GitHub Wiki

Sesión de Teoría 15: Nano-RISC-V segmentado

  • 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

Contenido

Introducción

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

Etapas en el NanoRISC-V segmentado

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)

Ejemplo de ejecución de una instrucción

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

Ejemplo de ejecución de dos instrucciones

En esta figura se muestra lo que ocurre al ejecutar las dos instrucciones siguientes:

addi x1,x0,1
addi x2,x0,2

Al 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

Pérdidas de rendimiento

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

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

Riesgos estructurales

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

Riesgos de datos

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,2

Tras 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

Soluciones software

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

Introducción de retardos: nop

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,2

El 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!!!

Reorganización de instrucciones

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

Solución Hardware: Adelantamiento

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,2

Ahora 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,2

Conclusiones

La 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)

Lecturas del libro de referencia

Libro de referencia: "Computer Organization and Design. Hardware/Software interface. Risc-V"

  • Apartado 4.5: An Overview of Pipelining (Pag 267-271)

Ejercicios

Ejercicios para practicar y asimilar los conceptos más importantes

Ejercicio 1

Se tiene un programa de prueba para un procesador Risc-V formado por una única instrucción:

li x5,5

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

Ejercicio 2

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,6

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?

Ejercicio 3

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,x5

El 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

Ejercicio 4

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,x5

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

Resolución de ejercicios del laboratorio

La segunda parte de la clase la vamos a dedicar al Laboratorio, para seguir programando

Autores

Licencia

Créditos

Enlaces