You are on page 1of 14

Trabajo Pr actico 1: Conjunto de Instrucciones MIPS

Joaquin Stankus, Padr on: 93.143 joaquin stan@hotmail.com Nicolas Menzano Diaz, Padr on: 93.154 nicolasdiaz55@yahoo.com.ar
Grupo Nro. - 2do. Cuatrimestre de 2012 66.20 Organizaci on de Computadoras Facultad de Ingenier a, Universidad de Buenos Aires

31 de octubre de 2012
Resumen El trabajo pr actico consiste en implementar el algoritmo de ordenamiento Stoogesort en c odigo assembly de MIPS32.

Indice

1.

Introducci on

Haciendo uso del programa GXemul [1], el cual simula una m aquina MIPS que corre una versi on del sistema operativo NetBSD, debemos implementar un programa similar al realizado en el Trabajo Pr actico 0, el cual ordena l neas de archivos. En este caso, debemos implementarlo con el algoritmo de ordenamiento Stoogesort [2], en assembly de MIPS32. Cabe destacar que esta vez el programa ordenar a archivos de texto.

1.1.

Objetivo

El objetivo de este trabajo es familiarizarse con la programaci on en assembler MIPS y con el concepto de ABI (Application Binary Interface). Intentaremos ver si es posible que el Stoogesort sea tan lento por la forma en que el compilador GCC lo compila o por la forma en que esta implementado el algoritmo en s . Recordemos que en el Trabajo Practico 0, se compil o el algoritmo sin optimizaciones, de modo que veremos si implementandolo directamente en assembler, es posible encontrar alguna mejora.

1.2.

Stoogesort
log (3)

Como podemos recordar del Trabajo Pr actico 0, Stoogesort es un algoritmo recursivo con una complejidad de O(n log(1,5) ), el cual ordena los elementos de la siguiente forma: Si el valor del nal es menor que el valor del primero, se intercambian. Si hay tres o mas elementos en la sublista actual, entonces: Aplicar el algoritmo en los 2/3 iniciales de la lista. Aplciar el algoritmo en los 2/3 nales de la lista. Aplicar el algoritmo en los 2/3 iniciales de la lista. En otro caso, terminar.

2.

El Programa

A diferencia del trabajo pr actico anterior, esta vez el programa solo ejecutar a el algoritmo de ordenamiento Stoogesort, por lo que se eliminaron las opciones para correr el Quicksort.

2.1.

Compilado

Para compilar el programa, desde una consola de netBSD y estando sobre el directorio del c odigo fuente, escribir en una consola lo siguiente: gcc -O0 -otp1 -Wall -std=c99 consola.c manejoarchivos.c swap.S compare.S stoogesort.S Esto dejar a un ejecutable, llamado tp1, en el directorio donde se encuentra el c odigo fuente.

2.2.

Modo de uso

El programa puede leer tanto datos desde stdin como de archivos pasados por par ametro. La salida del programa es por stdout y la de errores por stderr. Uso: ./tp1 [opcion] o ./tp1 [archivos...] Lista de opciones posibles: -h, --help muestra la ayuda del programa y sale. -V, --version muestra la version del programa y sale. Notas: No se sobreescribir an los archivos originales al ordenarlos, siempre se imprimir an por pantalla o a un archivo nuevo. Todo argumento que no sea de los listados anteriormente, se considerar a como un archivo a ordenar. Tener en cuenta que se ordenar an todos los archivos de entrada como si fueran uno. Si no se especica un archivo a ordenar, se tomar a stdin como entrada, pudiendo ser ingresado el texto por consola y presionando Control+D para ordenar, o un archivo pasado desde consola. Ej1: ./tp1 (ingresa por teclado el texto) Ej2: cat Archivo1.txt | ./tp1 (el Archivo1.txt es ordenado con Stoogesort) Por defecto la salida ser a impresa por consola, a no ser que se especique un archivo de salida, de la siguiente forma: ./tp1 entrada1.txt entrada2.txt >salida.txt Puede imprimir tambi en los errores en caso de que los hubiera, utilizando 2> al especicar un archivo de salida.

3.

Desarrollo

Como se mencion o en la introducci on, nuestro objetivo es ver si programando el Stoogesort nosotros mismos en lenguaje assembly, es posible realizarle alguna mejora para que se ejecute m as r apido. Compararemos los tiempos de ejecuci on del programa implementado integramente en C, con los tiempos de ejecuci on del programa implementado en C a excepci on del Stoogesort, hecho en assembly de MIPS. Para dicha tarea, utilizaremos nuevamente el comando time [3] de Unix, y compararemos los valores que nos arroje.

3.1.

Corriendo el comando time

Al ejecutar el comando time para el programa implementado en C, estos fueron los valores obtenidos (probado en netBSD): Archivo de 200 lineas (random) time ./tp1 200-lineas.txt real 0m4.508s user 0m3.703s sys 0m0.063s Archivo de 200 lineas (ordenado) time ./tp1 200-lineas-ordenado.txt real 0m4.000s user 0m2.617s sys 0m0.125s Archivo de 200 lineas (inverso) time ./tp1 200-lineas-inverso.txt real 0m3.676s user 0m2.715s sys 0m0.082s Archivo de 300 lineas (random) time ./tp1 300-lineas.txt real 0m8.695s user 0m7.059s sys 0m0.078s Archivo de 300 lineas (ordenado) time ./tp1 300-lineas-ordenado.txt real 0m10.133s user 0m8.855s sys 0m0.055s Archivo de 300 lineas (inverso) time ./tp1 300-lineas-inverso.txt real 0m9.551s user 0m8.266s sys 0m0.082s

Archivo de 400 lineas (random) time ./tp1 400-lineas.txt real 0m24.648s user 0m22.945s sys 0m0.117s Archivo de 400 lineas (ordenado) time ./tp1 400-lineas-ordenado.txt real 0m29.852s user 0m27.839s sys 0m0.109s Archivo de 400 lineas (inverso) time ./tp1 400-lineas-inverso.txt real 0m28.797s user 0m26.547s sys 0m0.094s Mientras tanto, para el Stoogesort implementado en assembly, se obtuvo: Archivo de 200 lineas (random) time ./tp1 200-lineas.txt real 0m3.449s user 0m2.578s sys 0m0.063s Archivo de 200 lineas (ordenado) time ./tp1 200-lineas-ordenado.txt real 0m4.832s user 0m3.379s sys 0m0.074s Archivo de 200 lineas (inverso) time ./tp1 200-lineas-inverso.txt real 0m4.156s user 0m3.184s sys 0m0.043s Archivo de 300 lineas (random) time ./tp1 300-lineas.txt real 0m10.281s user 0m9.000s sys 0m0.051s Archivo de 300 lineas (ordenado) time ./tp1 300-lineas-ordenado.txt real 0m13.578s user 0m11.613s sys 0m0.102s Archivo de 300 lineas (inverso) time ./tp1 300-lineas-inverso.txt real 0m12.125s user 0m10.656s sys 0m0.074s 6

Archivo de 400 lineas (random) time ./tp1 400-lineas.txt real 0m31.449s user 0m29.379s sys 0m0.078s Archivo de 400 lineas (ordenado) time ./tp1 400-lineas-ordenado.txt real 0m38.055s user 0m35.773s sys 0m0.105s Archivo de 400 lineas (inverso) time ./tp1 400-lineas-inverso.txt real 0m36.398s user 0m34.281s sys 0m0.090s

3.2.

Resultados

Procedemos a gracar los resultados para comparar (tomando en cuenta el tiempo de user):

Podemos observar que el Stoogesort implementado en MIPS result o m as lento que el implementado integramente en C. Por m as que se compile con -O0, el compilador sabe traducir las instrucciones de C mejor que nosotros, y muy probablemente sepa optimizar accesos a memoria, y ah sale la diferencia.

4.

Conclusiones

En conclusi on, podemos observar que por m as que hayamos intentado implementar el algoritmo Stoogesort en assembly, no pudimos hacerlo m as eciente. Se comprob o, de forma auxiliar, compilar el c odigo original en C con el argumento de GCC -O3, que realiza m as optimizaciones. A un con eso, no se pudo apreciar gran mejor a del desempe no del algoritmo a la hora de ordenar. En denitiva, el problema no es la compilaci on o la forma de implementar el algoritmo (intentando de manejar de forma optima los registros, accesos a memoria, etc), sino mas bien el algoritmo en s . Como vimos en la introducci on, es un algoritmo
log (3)

a optar por un algoritmo cuya complejidad sea mucho de complejidad O(n log(1,5) ), cosa que no se puede mejorar. Lo ideal ser menor, como por ejemplo el Quicksort.

5.
5.1.

C odigo Assembly
Diagramas de Stack
A continuaci on se incluyen los diagramas de Stack para las funciones de Assembly programadas: $fp $gp Cuadro 1: Stack de la funci on Swap

$fp $gp Cuadro 2: Stack de la funci on Compare

$ra $fp $gp $s3 $s2 $s1 $s0 $a2 $a1 $a0 Cuadro 3: Stack de la funci on Stoogesort

10

5.2.

C odigo

A continuaci on se incluye los archivos fuentes para las funciones implementadas en Assembly:
// swap.S #include <mips/regdef.h> .globl swap swap: .ent swap .frame sp,8,ra .set noreorder .cpload t9 .set reorder subu sp, sp, 8 .cprestore 0 sw a1, 12($fp) sw a0, 8($fp) sw $fp, 4(sp) sw gp, 0(sp) move $fp, sp move t3, a0 move t4, a1 lw t0, 0(t3) lw t1, 0(t4) sw t0, 0(a1) sw t1, 0(a0) move sp, $fp lw gp, 0(sp) lw $fp, 4(sp) addiu sp, sp, 8 jr ra .end swap

# armo el stack

# # # # # # # #

fin armado el stack t3 tiene puntero char** a x t4 tiene puntero char** a y t0 tiene puntero char* a x t1 tiene puntero char* a y guardo el nuevo valor en a1 guardo el nuevo valor en a0 deshago el stack

# stack pointer a donde apuntaba antes # return

// compare.S #include <mips/regdef.h> .globl compare compare: .ent compare .frame sp,8,ra .set noreorder .cpload t9 .set reorder subu sp, sp, 8 .cprestore 0 sw a1, 12(sp) sw a0, 8(sp) sw $fp, 4(sp) sw gp, 0(sp) move $fp, sp loopPrincipal: lb t0, 0(a0) lb t1, 0(a1) bne t0, t1, resta beqz t0, iguales addiu a0, a0, 1 addiu a1, a1, 1 b loopPrincipal resta: sub v0, t0, t1 b final iguales: move v0, zero b final final: move sp, $fp lw $fp, 4(sp) lw gp, 0(sp) addiu sp, sp, 8 jr ra .end compare

# armo el stack

# cargo byte apuntado por a0 # cargo byte apuntado por a1

# avanza al siguiente char de cadena 1 # avanza al siguiente char de cadena 2

# stack pointer a donde apuntaba antes # return

11

// stoogesort.S #include <mips/regdef.h> .globl stoogesort stoogesort: .ent stoogesort .extern swap .extern compare .frame sp,48,ra .set noreorder .cpload t9 .set reorder subu sp, sp, 48 .cprestore 32 sw a2, 56(sp) sw a1, 52(sp) sw a0, 48(sp) sw ra, 40(sp) sw $fp, 36(sp) sw gp, 32(sp) sw s3, 28(sp) sw s2, 24(sp) sw s1, 20(sp) sw s0, 16(sp) move $fp, sp move s0, a0 move s1, a1 move s2, a2 bge a1, a2, Salir sll t0, a1, 2 sll t1, a2, 2 addu t2, a0, t1 addu t3, a0, t0 lw a0, 0(t2) lw a1, 0(t3) jal compare bgez v0, continuar sll t0, s1, 2 sll t1, s2, 2 addu a1, s0, t0 addu a0, s0, t1 jal swap continuar: subu t0, s2, s1 addiu t0, t0, 1 li t1, 3 bge t0, t1, Llamadas b Salir Llamadas: div t2, t0, t1 move s3,t2 sub t3, s2, s3 move a0, s0 move a1, s1 move a2, t3 jal stoogesort addu t3, s1, s3 move a0, s0 move a1, t3 move a2, s2 jal stoogesort sub t3, s2, s3 move a0, s0 move a1, s1 move a2, t3 jal stoogesort

#Armamos el stack #ABA #ABA #ABA #SRA #SRA #SRA #SRA #SRA #SRA #SRA Caller Caller Caller Callee Callee Callee Callee Callee Callee Callee

#Guardamos a0 para preservarlo (puntero al arreglo) #Guardamos a1 para preservarlo (inicio) #Guardamos a2 para preservarlo (fin) #Si inicio es mayor o igual a fin, no hay nada que hacer #inicio*4 (debe indexarse un int) #fin*4 (debe indexarse un int) #a0 + fin*4 = &arreglo[fin] #a0 + inicio*4 = &arreglo[inicio] #arreglo[fin] #arreglo[inicio] #compare(arreglo[fin],arreglo[inicio]) #Si es mayor o igual a 0, no hace swap #inicio*4 (se utiliza s1 que es saved) #fin*4 (se utiliza s2 que es saved) #a0 + inicio*4 = &arreglo[inicio] #a0 + fin*4 = &arreglo[fin] #swap(&arreglo[inicio],&arreglo[fin]) #inicio - fin #inicio - fin + 1 #3 #if (inicio - fin + 1 >= 3), llamadas recursivas #Nada mas para hacer si no se cumple la condicion #(inicio - fin + 1)/3 #Guardamos este factor porque se utiliza en las tres llamadas #fin-t #a0 = puntero a arreglo #a1 = inicio #a2 = fin - t #stoogesort(arreglo,inicio,fin-t) #inicio+t #a0 = puntero a arreglo #a1 = inicio + t #a2 = fin #stoogesort(arreglo,inicio + t,fin) #fin-t #a0 = puntero a arreglo #a1 = inicio #a2 = fin - t #stoogesort(arreglo,inicio,fin-t)

12

Salir:

move lw lw lw lw lw lw lw addiu jr .end stoogesort

sp, $fp ra, 40(sp) $fp, 36(sp) gp, 32(sp) s3, 28(sp) s2, 24(sp) s1, 20(sp) s0, 16(sp) sp, sp, 48 ra

#SRA Callee #SRA Callee #SRA Callee #SRA Callee #SRA Callee #SRA Callee #SRA Callee #Volvemos el stack a su posicion original #Return a la direccion en el registro ra (recuperado del stack)

13

6.

Referencias
[1] - GXemul - http://gavare.se/gxemul/ [2] - Stoogesort - http://en.wikipedia.org/wiki/Stooge sort [3] - time man page - http://unixhelp.ed.ac.uk/CGI/man-cgi?time

14