miércoles, 9 de enero de 2013

PRÁCTICA 8 - WinDLXV vol. II

Desarrollo de la práctica:

El siguiente programa (pract2v1.s) se encarga de multiplicar todos los números de la lista almacenada por el número pi, dejando los resultados almacenados en las mismas posiciones.


.data 0
a: .double 3.14159265358979

x: .double 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
.double 17,18,19,20,21,22,23

xtop: .double 24

.text 256
start: ld f2,a (1)
addi r1,r0,xtop (2)
loop: ld f0,0(r1) (3)
multd f4,f0,f2 (4)
sd 0(r1),f4 (5)
subi r1,r1,8 (6)
bnez r1,loop (7)
trap 6 (8)

Práctica 2.- pract2v1.s

Considerar inicialmente las siguientes opciones de configuración:

- Unidad de suma: latencia 2 ciclos
- Unidad de multiplicación: latencia 5 ciclos
- Unidad de división: latencia 19 ciclos
- Unidades funcionales sin segmentar
- Saltos: predicción de no tomar
- Adelantamiento de resultados: desactivado


1. a) Simular el programa y determinar la ganancia de velocidad que se obtiene si se permiten caminos de bypass (opción adelantamiento de resultados activada).

Para empezar a hacer el ejercicio cargamos el programa Herramientas -> Editar y para introducir las opciones de configuración iniciales Configuración -> Arquitectura he introducimos los datos de latencia (para que salgan los resultados que esperamos 2, 5, 19; debemos poner 1, 4, 18) y desactivamos el segmentado; saltos: Configuración -> Saltos -> Predicción de no tomar, y finalmente, Configuración -> Adelanto de resultados. Para simular el programa le damos a flecha verde.
Nos fijamos en la ventana Estadísticas los ciclos, después activamos el adelanto de resultados Configuración -> Adelanto de resultados, simulamos de nuevo el programa y nos volvemos a fijar en los ciclos.  
Luego B, adelanto de resultados activados es un 33% más rápida que A, adelanto de resultados desactivados.

b) Partiendo de la configuración inicial, considere que se efectúa una mejora en la unidad de multiplicación, reduciendo su retardo a 3 ciclos. Esta mejora supone un incremento del coste del 15%. Determine si, para este programa, compensa realizar dicha mejora desde el punto de vista de la relación coste/prestaciones.

Para hacer este ejercicio debemos modificar la configuración inicial de la latencia de multiplicación: Configuración -> Arquitectura he introducimos 2 para que salga el resultado esperado 3.Ejecutamos el programa. Nos volvemos a fijar en la ventana de Estadísticas -> Ciclos

c) Considere que la mejora consiste en reducir el retardo de la unidad de multiplicación a 2 ciclos, con un incremento del coste del 18%. ¿Compensa la mejora?

Para hacer este ejercicio debemos modificar la configuración inicial de la latencia de multiplicación: Configuración -> Arquitectura he introducimos 1 para que salga el resultado esperado 2.Ejecutamos el programa. Nos volvemos a fijar en la ventana de Estadísticas -> Ciclos


Luego, al mejorarlo se consigue mejorar un 23% y al ser los costes un 18%, nos interesa mejorar porque los costes superan las prestaciones.


d) ¿Tendría interés mejorar la latencia de la unidad suma?

Probablemente no tendrá interés, ya que, aunque se hace una instrucción addi,sólo se hace en un único ciclo y probablemente el coste de la reducción sea elevado.

2. Seleccione la opción “salto retardado” y ejecute el programa. ¿Qué ocurre? ¿Cuál es la causa? ¿Cuál sería la solución?

En el salto retardado se reordena el código de forma que se sitúan instrucciones que no dependan del salto después del mismo para que se vayan ejecutando esas instrucciones (que siempre se van a ejecutar) y cuando se termine de calcular el salto se toma o no. Pero en este programa hay un problema. Lo que pasa es que antes de que se decida el salto, como se siguien ejecutando instrucciones, SE EJECUTA LA TRAP DE SALIDA ANTES DE QUE SE TOME EL SALTO. Por eso solo hace una iteración del bucle y finaliza, con lo cual no se ejecuta bien el programa. La solución sería poner más instrucciones independientes a ejecutarse después del salto, para que no se ejecute el trap antes de coger el salto.

3.La siguiente figura (pract2v2.s) muestra una versión modificada del código inicial, que se ha transformado aplicando una técnica que recibe el nombre de desenrollado de bucle. Esta técnica consiste en realizar los cálculos de varias iteraciones en una única iteración para reducir así el número de instrucciones de salto que se tienen que ejecutar, con lo que además se evitan riesgos de control.

Determinar la ganancia de velocidad que se obtiene con respecto a la versión inicial del programa.


.data 0
a: .double 3.14159265358979

x: .double 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
.double 17,18,19,20,21,22,23

xtop: .double 24

.text 256

start: ld f2,a (1)
addi r1,r0,xtop (2)
loop: ld f0,0(r1) (3)
multd f4,f0,f2 (4)
sd 0(r1),f4 (5)
ld f6,-8(r1) (6)
multd f8,f6,f2 (7)
sd -8(r1),f8 (8)
ld f10,-16(r1) (9)
multd f12,f10,f2 (10)
sd -16(r1),f12 (11)
ld f14,-24(r1) (12)
multd f16,f14,f2 (13)
sd -24(r1),f16 (14)
subi r1,r1,32 (15)
bnez r1,loop (16)
trap 6 (17)

Práctica 2.- pract2v2.s


Para empezar a hacer el ejercicio cargamos el programa Herramientas -> Editar y para introducir las opciones de configuración iniciales Configuración -> Arquitectura he introducimos los datos de latencia (para que salgan los resultados que esperamos 2, 5, 19; debemos poner 1, 4, 18) y desactivamos el segmentado; saltos: Configuración -> Saltos -> Predicción de no tomar, y finalmente, Configuración -> Adelanto de resultados. Para simular el programa le damos a la flechita verde.

Luego B, aplicando la técnica desenrollado de bucle es un 30% más rápida que A, sin aplicar dicha técnica.


4. Para el programa del apartado anterior, pract2v2.s, determinar la ganancia de velocidad que se obtiene con respecto a un procesador DLX sin segmentar de referencia, que denominaremos DLXssr.

En el proceso DLXssr cada instrucción va pasando por distintas fases que se suceden según sean utilizadas por la correspondiente instrucción, de forma que las instrucciones tendrán distinto tiempo de ejecución según del tipo que sean.

Consideramos que en DLXssr las fases IF, ID, intEX, MEM y WB tienen un ciclo de reloj cada una. Las fases faddEX, fmultEX y fdivEX tendrán el mismo número de ciclos que en el caso del procesador segmentado.

Para estimar el tiempo de ejecución del programa en DLXssr hay que tener en cuenta el tiempo que tardaría cada una de sus instrucciones. El tiempo de instrucción se puede determinar a partir del número de etapas por las que pasa. Así, por ejemplo, una instrucción de carga (Id) pasaría por todas las etapas (duración 5 ciclos de reloj) mientras que una instrucción de almacenamiento (sd) no pasaría por WB (duración 4 ciclos de reloj) ya que no tiene que almacenar nada en los registros del procesador. Las instrucciones aritmético-lógicas no pasarían por la etapa de MEM. Hay que tener en cuenta que la duración de la etapa EX depende del tipo de instrucción: si la operación es con enteros, se utilizará intEX y la duración será de un ciclo; si es en coma flotante, se utilizará faddEX, fmulEX o fdivEX y en la duración será la asignada a la correspondiente unidad.

Para las instrucciones de salto condicional considere una duración de 3 ciclos (en la etapa de ejecución se comprueba la condición y se carga en el PC la nueva dirección, si fuese el caso). Para el trap considere 2 ciclos (hasta la etapa de codificación).

Tenemos 24 elementos en el vector. A cada uno de ellos lo sacamos del vector y lo multiplicamos por PI. Entonces por cada elemento hacemos un ld (cargar en registro) multd (multiplicar) y sd (volver a guardarlo en el mismo sitio). Luego 3 instrucciones por elemento 3*24 = 72 instrucciones.

Además, se hacen más instrucciones. En cada iteración del bucle se hace una resta y la comparación del salto. En esta versión del programa se hacen 4 multiplicaciones por bucle, luego 24/4 = 6 iteraciones, es decir 6*2 = 12 instrucciones.

Se ejecutan al principio otras dos instrucciones una carga y una suma. En trap contamos dos ciclos. Entonces, 72+12+2+trap = 87 instrucciones.

Como el DLXssr no es segmentado cada instrucción dura tantos ciclos como tenga (LW dura 5 ciclos, pero sw y add duran solo 4 ciclos, mientras que el salto dura 3 ciclos y la trap 2), solo hay que saber contar cuántas hay de cada una.

LD (load double) → 24 instrucciones * 5 ciclos = 120 ciclos;
MultD → Tienen 4 ciclos pero hay que contar la latencia de mult, que es 5 ciclos, luego son 3(IF,ID, WB) + 5 de ejecutar la operación = 8 ciclos /instrucción * 24 instrucciones = 192 ciclos.
SD (store double) → 24 instrucciones * 4 ciclos = 96 ciclos.
Subi (substract inmediate) → se hacen 6 instrucciones que duran 4 ciclos (son restas de enteros), luego 6*4=24 ciclos.
Beqz (El salto) 6 instrucciones * 3 ciclos = 18 ciclos.
De las dos instrucciones del principio, la carga es de 5 ciclos, y la suma de 4, luego 9 ciclos.
trap vale 2 ciclos.

Sumando en total salen 120+192+96+24+18+9+2=461 ciclos.


A: Ejercicio 1-> 408 ciclos
B: Ejercicio 4: 461 ciclos

 
 
Luego B, ejercicio 4, no segmentado, es un 33% más lenta que A, ejercicio 1, segmentado.
5. Modificar el programa del apartado 3 (pract2v3.s) de forma que incluya 8 iteraciones en el bucle. Determinar la ganancia de velocidad que se obtiene con respecto a las versiones anteriores.

El programa modificado que planteamos es:

Cargamos el programa Herramientas -> Editar y para introducir las opciones de configuración iniciales Configuración -> Arquitectura he introducimos los datos de latencia (para que salgan los resultados que esperamos 2, 5, 19; debemos poner 1, 4, 18) y desactivamos el segmentado; saltos: Configuración -> Saltos -> Predicción de no tomar, y finalmente, Configuración -> Adelanto de resultados. Para simular el programa le damos a la flechita verde.


Nos fijamos en la ventana Estadísticas los ciclos, después activamos el adelanto de resultados Configuración -> Adelanto de resultados, simulamos de nuevo el programa y nos volvemos a fijar en los ciclos.
Luego B, ejercicio 5 es un 9% más rápida que A, ejercicio 3.
 

6. Partiendo de la versión del apartado 3, reorganizar las instrucciones (pract2v4.s) para reducir el efecto de las dependencias entre ellas. Simular la versión realizada y determinar la ganancia de velocidad obtenida.

El programa modificado que planteamos es:
Cargamos el programa Herramientas -> Editar y para introducir las opciones de configuración iniciales Configuración -> Arquitectura he introducimos los datos de latencia (para que salgan los resultados que esperamos 2, 5, 19; debemos poner 1, 4, 18) y desactivamos el segmentado; saltos: Configuración -> Saltos -> Predicción de no tomar, y finalmente, Configuración -> Adelanto de resultados. Para simular el programa le damos ala flechita verde.


Nos fijamos en la ventana Estadísticas los ciclos, después activamos el adelanto de resultados Configuración -> Adelanto de resultados, simulamos de nuevo el programa y nos volvemos a fijar en los ciclos.
 
Luego B, ejercicio 6 es un 56% más rápida que A, ejercicio 3.

Adjunto pdf original para consulta offline.

 Práctica 8

martes, 8 de enero de 2013

PRÁCTICA 7 - WinDLXV vol. I


En esta práctica haremos uso del programa WinDLXV, que simula la segmentación dentro de un PC.

Desarrollo de la práctica:

En el apartado de Arquitectura del programa,  modifico la latencia y desactivo las casillas de segmentación de las unidades funcionales señaladas en la práctica. Además, en la pestaña de configuración, desactivo la función de adelantamiento de resultados.

Con estos pasos, ya hemos cambiado las condiciones de partida y ya estamos listos para realizar los ejemplos de la práctica.

Ejemplo 1 : Dependencias de datos tipo RAW

Este tipo de dependencia provoca la creación de burbujas que detienen el flujo de instrucciones tantos ciclos como sea necesario a la espera del dato que necesite la instrucción.

En la pestaña de Herramientas, le damos a Editar y escribimos el programa de este ejemplo:

;*********** WINDLXV *************
;*********** Ejemplo 1 *************
;-----------------------------------------------------------------------------
; Ejemplo para ilustrar dependencias de datos tipo RAW 
;-----------------------------------------------------------------------------
                 .text
main:
                 add           r1,r2,r3         ;almacena un nuevo valor en r1
                 sub           r4,r1,r5          ;usa r1
                 and          r6,r1,r7          ;usa r1
                 or             r8,r1,r9          ;usa r1
                 xor           r10,r1,r11      ;usa r1
                 nop
                 nop
                 nop
                 nop
                add         r1,r2,r3          ;almacena un nuevo valor en r1
                sub         r4,r1,r5          ;usa r1 y almacena un nuevo valor en r4
                and         r6,r4,r7          ;usa r4 y almacena un nuevo valor en r6
                or            r8,r6,r9          ;usa r6 y almacena un nuevo valor en r8
                xor          r10,r8,r11      ;usa r8 y almacena un nuevo valor en r10
Finish:    trap        6

La latencia de emisión son los ciclos que hay entre una instrucción y la siguiente. En este caso, hay 2 ciclos entre una operación aritmético-lógica y la siguiente.

Fijándonos en la ventana de estadísticas aparecen los resultados pedidos:

a) Número total de ciclos de ejecución: 29 ciclos
    Ciclos de reloj por instrucción (CPI): 1933 ciclos

b) En 10 ciclos se han producido detenciones al decodificar las instrucciones (fase ID).

c) Al activar el adelantamiento de resultado se producen los siguiente resultados:
    Número total de ciclos en ejecución: 19 ciclos
    Ciclos de reloj por instrucción (CPI): 1.267 ciclos
    No se producen detenciones
    El aumento de rendimiento se nota en la disminución de ciclos en ejecución y de reloj

Ejemplo 2 : dependencia de datos tipo RAW

Cargo el programa del ejemplo 2:

;*********** WINDLXV*************
;*********** Ejemplo 2 *************
;-----------------------------------------------------------------------------
; Ejemplo para ilustrar dependencias de datos tipo RAW
;-----------------------------------------------------------------------------
              .text
main:
              add         r1,r2,r3
              lw           r4, 0(r1)                    ;carga en r4 usando r1
              sub         r5,r4,r3                     ;usa r4
              sw          14(r2),r5                   ;almacena r5 usando r2
              nop
              nop
              nop 
              nop
              lw           r1, 2(r2)
              sub         r4,r1,r5
              and        r6,r1,r5
              or           r8,r1,r5
Finish:    trap       6
                                                                          
En las ventanas de “Registros” y “Datos” modifico los valores de los registros y de las posiciones de memoria pedidas.

R1: 0x1f
R4: 0x5
R5: 0x1a
R6: 0x1a
R8: 0x1f
Posición de memoria del contenido de R5: 0x1010

En este caso, la latencia de emisión de las instrucciones aritmético-lógicas es de 1 ciclo, mientras que en las instrucciones de carga es de 3 ciclos.

a) Número total de ciclos de ejecución: 25 ciclos
     Ciclos por instrucción (CPI): 1.923 ciclos

b) En 8 ciclos se han producido detenciones al decodificar las instrucciones (fase ID)

c) Con adelantamiento de resultado:
           Número total de ciclos de ejecución: 19 ciclos
           Ciclos por instrucción (CPI):  1.462 ciclos
           En 2 ciclos se han producido detenciones al ejecutar las instrucciones (fase EX)

      d) Con adelantamiento de resultados, la latencia de emisión para las instrucciones aritmético-lógicas es de 1 ciclo, mientras que para las instrucciones de carga es de 2 ciclos.

Ejemplo 3 : Dependencias de tipo estructural

;*********** WINDLXV *************
;*********** Ejemplo 3 *************
;-----------------------------------------------------------------------------
; Ejemplo para ilustrar dependencias de tipo estructural
;-----------------------------------------------------------------------------
              .text
main:
              addf          f1,f2,f3
              multf        f2,f4,f5
              addf          f3,f3,f4
              multf        f6,f6,f6
              addf          f1,f3,f5
              addf          f2,f3,f4
Finish:     trap          
              
 a) Número total de ciclos de ejecución: 18 ciclos
     Ciclos por instrucción (CPI): 3 ciclos

b) No hay detenciones

c) Con unidades funcionales de punto flotante segmentadas:
15 ciclos de ejecución
2.5 ciclos de reloj por instrucción (CPI)
El rendimiento es mayor ya que ha disminuido el número de ciclos de ejecución y el número de ciclos de reloj por instrucción.

Ejemplo 4 : Reordenación de datos

Para este ejemplo, modifico la latencia en las unidades funcionales señaladas en Arquitectura.

;*********** WINDLXV *************
;*********** Ejemplo 4 *************
;------------------------------------------------------------------------------------------------------
; Ejemplo para ilustrar la reordenación de instrucciones – PROGRAMA ORIGINAL
;------------------------------------------------------------------------------------------------------
               .data
ONE:      .word 1
               .text
main:
                lf                              f1,ONE                 ;convierte divf en move al almacenar
                cvti2f                      f7,f1                      ; 1 en f7 en formato de punto flotante
                nop
                divf                         f1,f8,f7                  ;mueve Y=(f8) a f1
                divf                         f2,f9,f7                  ;mueve Z=(f9) a f2
                addf                        f3,f1,f2
                divf                         f10,f3,f7                ;mueve f3 a X=(f10)
                divf                         f4,f11,f7                ;mueve B=(f11) a f4
                divf                         f5,f12,f7                ;mueve C=(f12) a f5
                multf                      f6,f4,f5
                divf                         f13,f6,f7                ;mueve f6 a A=(f13)
Finish:      trap                        6
                

;*********** WINDLXV *************
;*********** Ejemplo 4 *************
;------------------------------------------------------------------------------------------------------------
; Ejemplo para ilustrar la reordenación de instrucciones – PROGRAMA REORDENADO
;------------------------------------------------------------------------------------------------------------
               .data
ONE:      .word                       1
               .text
main:
               lf                               f1,ONE                   ;convierte divf en move al almacenar
               cvti2f                       f7,f1                        ; 1 en f7 en formato de punto flotante
               nop
               divf                          f1,f8,f7                    ;mueve Y=(f8) a f1
               divf                          f2,f9,f7                    ;mueve Z=(f9) a f2
               divf                          f4,f11,f7                  ;mueve B=(f11) a f4
               divf                          f5,f12,f7                  ;mueve C=(f12) a f5
               addf                         f3,f1,f2
               multf                       f6,f4,f5
               divf                          f10,f3,f7                  ;mueve f3 a X=(f10)
               divf                          f13,f6,f7                  ;mueve f6 a A=(f13)
Finish:     trap                         6
               
a) Número total de ciclos de ejecución: 86 ciclos
    Ciclos por instrucción (CPI): 7.167 ciclos

b) Número de ciclos perdidos por dependencia RAW: 35 ciclos

c) Se produce un aumento del rendimiento al reordenar las instrucciones ya que se reduce el número de ciclos de ejecución(de 86 a 73 ciclos), el número de ciclos por instrucción (de 7.167 a 6.083 ciclos) y el número de detenciones (de 35 a 17).

Mejoras/Errores:

La latencia que se indica en el apartado de “Arquitectura” es una unidad menor que la latencia que se visualiza en la ventana de “Estadísticas”.
He tenido muchas dudas con el programa que con el manual, que aunque es extenso, no las pude resolver.

Adjunto Pdf original para su consulta offline.