esquemas iterativos en paralelo con openmp

133
CENTRO UNIVERSITARIO DE LA COSTA SUR UNIVERSIDAD DE GUADALAJARA DIVISI ´ ON DE DESARROLLO REGIONAL DEPARTAMENTO DE INGENIER ´ IAS INGENIER ´ IA EN TELEINFORM ´ ATICA PARA OBTENER EL T ´ ITULO DE INGENIERO EN TELEINFORM ´ ATICA BAJO LA MODALIDAD DE TITULACI ´ ON TESIS CON EL T ´ ITULO “Esquemas Iterativos en Paralelo con OpenMP” PRESENTA Sotero Ordo˜ nes Nogales DIRECTOR Dr. Jos´ e Antonio Mu˜ noz G´ omez ASESORES Dr. Luis Isidro Aguirre Salas Dr. Omar Aguilar Loreto Autl´ an de la Grana, Jalisco. Enero 2013

Upload: sotero-ordones-nogales

Post on 08-Aug-2015

216 views

Category:

Documents


0 download

DESCRIPTION

El presente trabajo de tesis aborda la creación de algoritmos paralelos para la solución numérica de sistemas de ecuaciones lineales mediante esquemas iterativos de tipo Jacobi y Gauss-Seidel; con especial énfasis en el rendimiento y la escalabilidad. Este documento se centra en dos aspectos principales. En un primer momento, estudiamos la implementación de técnicas avanzadas de programación para maximizar el rendimiento en ejecuciones seriadas. Una de las técnicas permite utilizar módulos de procesamiento vectorial del procesador con la finalidad de realizar varias operaciones a la vez; es decir, conseguir paralelismo a nivel de datos (conocido como SIMD). También se utilizan características del compilador GCC para optimizar el código y catapultar el rendimiento serial de estas primeras funciones. En un segundo momento, se realiza un estudio exhaustivo de cada uno de los métodos que permitan escribir funciones que realmente puedan ser ejecutadas en más de un núcleo utilizando el API llamada OpenMP apoyado con los resultados de las técnicas utilizadas (Bandera de compilación, Loop unrolling, SIMD). En general con el estudio realizado observamos una escalabilidad lineal de dos a cuatro procesadores. Por otro lado cuando empleamos ocho procesadores se observa un aumento de 5.4x.

TRANSCRIPT

Page 1: Esquemas iterativos en paralelo con OpenMP

CENTRO UNIVERSITARIO DE LA COSTA SURUNIVERSIDAD DE GUADALAJARA

DIVISION DE DESARROLLO REGIONALDEPARTAMENTO DE INGENIERIAS

INGENIERIA EN TELEINFORMATICA

PARA OBTENER EL TITULO DE INGENIERO EN TELEINFORMATICA

BAJO LA MODALIDAD DE TITULACION

TESIS

CON EL TITULO

“Esquemas Iterativos en Paralelo con OpenMP”

PRESENTA

Sotero Ordones Nogales

DIRECTOR

Dr. Jose Antonio Munoz Gomez

ASESORES

Dr. Luis Isidro Aguirre Salas Dr. Omar Aguilar Loreto

Autlan de la Grana, Jalisco. Enero 2013

Page 2: Esquemas iterativos en paralelo con OpenMP
Page 3: Esquemas iterativos en paralelo con OpenMP

UNIVERSIDAD DE GUADALAJARA CENTRO UNIVERSITARIO DE LA COSTA SUR SECRETARÍA ACADÉMICA – COORDINACIÓN DE INGENIERÍA EN TELEINFORMÁTICA

Avenida Independencia Nacional # 151, Autlán de Navarro, Jalisco; C.P. 48900, Tels. (317) 382-50-10 Y 382-32- 00

http://www.cucsur.udg.mx

C. SOTERO ORDOÑES NOGALES Egresado de la Carrera de Ingeniería en Teleinformática P R E S E N T E

A través de la presente, se le informa que fue APROBADA su modalidad de titulación de TESIS, para titularse de la carrera de Ingeniero en Teleinformática.

Así mismo, se le informa que estará asignado como Director al DR. JOSE

ANTONIO MUÑOZ GÓMEZ y DR. OMAR AGUILAR LORETO y DR. LUIS ISIDRO AGUIRRE SALAS, como asesores.

Se anexa una guía con los temas que debe considerar para realizar dicho

documento y se le informa a su vez que tiene 8 meses a partir de la fecha del presente para entrega del trabajo recepcional con el visto bueno del Director. Debe presentar siete ejemplares impresos con una copia de este oficio en primer término. Además, debe agregar portada y un formato específicos, solicitarlos antes de su entrega.

ATENTAMENTE “PIENSA Y TRABAJA”

AUTLÁN DE NAVARRO, JAL. 04 DE DICIEMBRE DE 2012.

___________________________________________ M.T.A. CLAUDIA DIANE VACA GAVIÑO

COORDINADOR DE LA CARRERA DE INGENIERÍA Y DE TSU EN TELEINFORMÁTICA

C.C.P ARCHIVO

Page 4: Esquemas iterativos en paralelo con OpenMP
Page 5: Esquemas iterativos en paralelo con OpenMP
Page 6: Esquemas iterativos en paralelo con OpenMP
Page 7: Esquemas iterativos en paralelo con OpenMP

Dedicatorias y Agradecimientos

He llegado al final de una pequena travesıa en el viaje de la vida; durante este trayecto he

adquirido experiencias que han dejado estelas imborrables. Me permito mencionar a las dos personas

que se convirtieron en la estrella polar de este pobre marinero:

A Nora Marisol Chavez Guerrero,

...mi inspiracion y motivacion.

A mi padre, Luis Ordonez Dıaz

que siempre estara en mi recuerdo.

Hay personas que nos hablan y ni las escuchamos...

hay personas que nos hieren y no dejan ni cicatriz...

pero hay personas que simplemente aparecen en nues-

tra vida y nos marcan para siempre.

Cecılia Meireles

Page 8: Esquemas iterativos en paralelo con OpenMP

Un marinero no es nadie sin la ayuda de aquellos que lo han acompanado en el barco. Quiero

agradecer a esas personas con las que no solo compartı este viaje, sino colaboraron en la toma del

rumbo, me refiero a la tripulacion:

Mi familia y Dios

Por estar allı siempre apoyandome, toda la paciencia y esfuerzo que han realizado para ver cumplido

este sueno. Especialmente a mi senora madre a quien no me alcanzara toda una vida, ni cada una

de las palabras del mundo para agradecerte por todo lo que ha hecho por mı. A mis hermanos Juan,

Isabel, Angelina y Julio que sin la ayuda esto no serıa posible.

Dr Antonio

Gracias por ese apoyo incondicional no solo durante la realizacion del presente documento; sino

tambien en el transcurso de mi formacion profesional y personal dentro de esta institucion. Por la

paciencia y dedicacion para aclarar los temas oscuros. Por permitirme utilizar las computadoras

para la evaluacion de los resultados y la elaboracion de la presente tesis.

Los doctores Luis Isidro y Omar

Gracias mas que ser mis maestros ser mis amigos. Sus valiosas aportaciones y observaciones a la

presente tesis. Agradezco todas sus ensenazas que no solo se limitaron a lecciones academicas sino

tambien de vida. Me es imposible citar textualmente las frases que me dijeron; pero la esencia la

conservo.

Para llevar a puerto esta pequena embarcacion colaboraron muchas personas que por ahora me

es imposible nombrar a cada una de ellas; todos esos momentos que hicieron divertida la travesıa.

Como olvidar esta tan acertada frase de uno de ellos:

...la universidad es como una espada, cuanto mas la afilemos y practique-

mos...estaremos mejor preparados para enfrentar, al coyote que esta al

asecho en el camino de la vida...

Luis Isidro Aguirre Salas

Page 9: Esquemas iterativos en paralelo con OpenMP

Indice general

Indice de figuras XI

Indice de tablas XIII

Resumen XV

1. Introduccion 1

2. Marco Teorico 7

2.1. Metodos numericos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2. Modelacion matematica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.3. Los numeros en la computadora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.4. Tipos de error en metodos numericos . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.5. El lenguaje de programacion C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2.6. Programacion en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

2.7. OpenMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.8. Escalabilidad paralela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.8.1. Ley de Amdahl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

2.8.2. Incremento de velocidad (speed-up) . . . . . . . . . . . . . . . . . . . . . . . 27

2.8.3. Desempeno computacional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3. Producto matriz-vector Ax 31

3.1. Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.2. Loop unrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3.3. Calculo del residual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

3.4. Codificacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3.5. Incremento del desempeno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3.6. Procesamiento vectorial (SIMD) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

3.7. Codificacion en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

3.8. Evaluacion de algoritmos en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

ix

Page 10: Esquemas iterativos en paralelo con OpenMP

x Indice general

4. Metodo Iterativo de Jacobi 694.1. Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774.2. Codificacion del metodo de Jacobi en C . . . . . . . . . . . . . . . . . . . . . . . . . 81

4.2.1. Simplificando codigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814.2.2. Optimizacion de codigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

4.3. Metodo de Jacobi en paralelo con OpenMP . . . . . . . . . . . . . . . . . . . . . . . 874.4. Evaluacion de algoritmo en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

5. Metodo de Gauss-Seidel 935.1. Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935.2. Programacion en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965.3. Codificacion en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975.4. Gauss-Seidel versus Jacobi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102

6. Conclusiones y trabajo a futuro 109

Bibliografıa 113

Page 11: Esquemas iterativos en paralelo con OpenMP

Indice de figuras

2.1. Distribucion de numeros enteros con formato predefinido. . . . . . . . . . . . . . . . 10

2.2. Distribucion de numeros reales con formato predefinido. . . . . . . . . . . . . . . . . 12

2.3. Modelo para representacion de numeros en punto flotante IEEE 754. . . . . . . . . . 13

2.4. Calculo de epsilon de la computadora. . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.5. Rango de numero IEEE-754 precision simple. . . . . . . . . . . . . . . . . . . . . . . 15

2.6. Arquitectura de hardware CPU versus GPU. . . . . . . . . . . . . . . . . . . . . . . 21

2.7. Tipos de memoria en sistemas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.8. Modelo de OpenMP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

2.9. Modelo de ejecucion de programas paralelos. . . . . . . . . . . . . . . . . . . . . . . 26

2.10. Speed-up con Ley de Amdahl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.1. Calculo del residual en C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

3.2. Implementacion canonica de Ax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3.3. Tecnica Loop Unrroll con factor 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

3.4. Tecnica Loop Unroll con factor 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

3.5. Tecnica Loop Unroll con factor 2, dos ciclos for. . . . . . . . . . . . . . . . . . . . . 42

3.6. Tecnica Loop Unroll con factor 2, dos variables. . . . . . . . . . . . . . . . . . . . . . 42

3.7. Tecnica Loop Unroll con factor 2, dos ciclos for y dos variables. . . . . . . . . . . . . 43

3.8. Tecnica Loop Unroll con factor 2, cuatros ciclos for cuatro variables. . . . . . . . . . 43

3.9. Tecnica Loop Unroll con factor 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3.10. Tecnica Loop Unroll con factor 6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3.11. Tecnica Loop Unroll con factor 8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3.12. Tecnica Loop Unroll con factor 10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3.13. Tecnica Loop Unroll con factor 12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

3.14. Speed-up para la multiplicacion de dos vectores. . . . . . . . . . . . . . . . . . . . . 48

3.15. Funcion general de la multiplicacion Ax con Unroll. . . . . . . . . . . . . . . . . . . 50

3.16. Speed-up de Ax utilizando la tecnica de Unroll. . . . . . . . . . . . . . . . . . . . . . 51

3.17. Rendimiento computacional de Ax al utilizar la tecnica de Unroll. . . . . . . . . . . 52

3.18. Modelo SIMD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

3.19. Funcion en MMX que multiplica dos vectores x y y. . . . . . . . . . . . . . . . . . . 55

3.20. Desempeno de Ax al utilizar MMX con bandera de compilacion -O2. . . . . . . . . . 59

3.21. Implementacion canonica en paralelo de Ax. . . . . . . . . . . . . . . . . . . . . . . . 60

xi

Page 12: Esquemas iterativos en paralelo con OpenMP

xii Indice de figuras

3.22. Rendimiento de la version canonica de Ax en paralelo con bandera de compilacion -O2. 623.23. Implementacion general de Ax en paralelo. . . . . . . . . . . . . . . . . . . . . . . . 623.24. Desempeno de la version canonica de Ax con banderas de compilacion. . . . . . . . . 633.25. Escalabilidad paralela de Ax en su la version Unroll-10 con bandera -O2. . . . . . . 643.26. Escalabilidad paralela de Ax en su la version MMX con bandera -O2. . . . . . . . . 653.27. Comparativa del rendimiento computacional de las versiones canonica, Unroll-10 y

MMX con bandera de compilacion -O2. . . . . . . . . . . . . . . . . . . . . . . . . . 66

4.1. Primera implementacion del metodo de Jacobi en lenguaje C. . . . . . . . . . . . . . 824.2. Codigo en lenguaje C del esquema de Jacobi. . . . . . . . . . . . . . . . . . . . . . . 834.3. Porcentaje del tiempo de ejecucion del metodo de Jacobi con y sin sentencia if. . . . 844.4. Codigo general de Jacobi optimizado. . . . . . . . . . . . . . . . . . . . . . . . . . . . 864.5. Tiempos de ejecucion de Jacobi en serie, versiones [Canonica, Unroll4, MMX] para

n = 5000. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874.6. Codigo de version canonica en paralelo de Jacobi. . . . . . . . . . . . . . . . . . . . . 884.7. Speed-up del metodo de Jacobi en paralelo en su version canonica. . . . . . . . . . . 894.8. Speed-up del metodo de Jacobi en paralelo en su version MMX. . . . . . . . . . . . . 90

5.1. Metodo de Gauss-Seidel en lenguaje C, version canonica. . . . . . . . . . . . . . . . . 975.2. Metodo de Gauss-Seidel con OpenMP. . . . . . . . . . . . . . . . . . . . . . . . . . . 985.3. Descomposicion del vector solucion x para dos procesadores. . . . . . . . . . . . . . . 995.4. Escalabilidad paralela del metodo Gauss-Seidel version canonica. . . . . . . . . . . . 1015.5. Metodo de Jacobi con diferencias finitas. . . . . . . . . . . . . . . . . . . . . . . . . . 1045.6. Metodo de Gauss-Seidel con diferencias finitas. . . . . . . . . . . . . . . . . . . . . . 1045.7. Aproximacion numerica a u(x, y) = senx cos y con Gauss-Seidel. . . . . . . . . . . . . 106

Page 13: Esquemas iterativos en paralelo con OpenMP

Indice de tablas

2.1. Unidades de medida de FLOPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.1. Producto de dos vectores: resultados de prueba de exactitud, observamos las vecesque es mas exacta, mostrada en porcentaje ( %), cada funcion durante las iteracionespara cada valor de n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

3.2. Producto de dos vectores: resultados de prueba de velocidad, observamos la tasa deexactitud de cada funcion con respecto al numero de iteraciones (10,000). . . . . . . 45

3.3. Producto de dos vectores: comparacion de rendimiento de las funciones canonica,MMX y Unroll-4; observamos el rendimiento que nos brinda la funcion en MMXrespecto a la forma tradicional y en comparacion con la funcion con Unroll de 4. . . 58

4.1. Metodo iterativo de Jacobi: primera evaluacion de rendimiento, observamos el por-centaje de la reduccion del tiempo en ejecucion cuando se remueve la condicion (if). 85

5.1. Metodo de Gauss-Seidel en paralelo; iteraciones para converger. . . . . . . . . . . . . 1005.2. Convergencia de Gauss-Seidel vs Jacobi. . . . . . . . . . . . . . . . . . . . . . . . . . 105

xiii

Page 14: Esquemas iterativos en paralelo con OpenMP
Page 15: Esquemas iterativos en paralelo con OpenMP

Resumen

El presente trabajo de tesis aborda la creacion de algoritmos paralelos para la solucion numeri-

ca de sistemas de ecuaciones lineales mediante esquemas iterativos de tipo Jacobi y Gauss-Seidel;

con especial enfasis en el rendimiento y la escalabilidad. Este documento se centra en dos aspec-

tos principales. En un primer momento, estudiamos la implementacion de tecnicas avanzadas de

programacion para maximizar el rendimiento en ejecuciones seriadas. Una de las tecnicas permite

utilizar modulos de procesamiento vectorial del procesador con la finalidad de realizar varias ope-

raciones a la vez; es decir, conseguir paralelismo a nivel de datos (conocido como SIMD). Tambien

se utilizan caracterısticas del compilador GCC para optimizar el codigo y catapultar el rendimiento

serial de estas primeras funciones. En un segundo momento, se realiza un estudio exhaustivo de

cada uno de los metodos que permitan escribir funciones que realmente puedan ser ejecutadas en

mas de un nucleo utilizando el API llamada OpenMP apoyado con los resultados de las tecnicas

utilizadas (Bandera de compilacion, Loop unrolling, SIMD). En general con el estudio realizado

observamos una escalabilidad lineal de dos a cuatro procesadores. Por otro lado cuando empleamos

ocho procesadores se observa un aumento de 5.4x.

xv

Page 16: Esquemas iterativos en paralelo con OpenMP
Page 17: Esquemas iterativos en paralelo con OpenMP

Capıtulo 1Introduccion

Una de las herramientas mas valiosas para la resolucion de problemas practicos de Ingenierıa son

las computadoras digitales mediante la utilizacion de metodos numericos. En un numero significativo

de esos problemas solo se puede obtener una solucion aproximada, a esto se debe la importancia del

estudio de la rama de las matematicas llamada analisis numerico. Esta rama involucra el estudio

de metodos numericos. El desarrollo de estos esquemas es notablemente influenciado y determinado

por las computadoras, las cuales permiten realizar los calculos de manera veloz, confiable y sobre

todo flexible.

En la actualidad la computadora es una herramienta indispensable para las actividades coti-

dianas, escolares, de oficina y cientıficas. Con necesidades cada vez mas complejas, es por ello que

se busca que las aplicaciones puedan realizar los calculos lo mas rapido posible aprovechando los

recursos del equipo con la mayor eficiencia posible.

En el pasado para cubrir con las necesidades del mercado se incrementaba la velocidad del

procesador, aumentando el numero de transistores al circuito integrado. Como lo previo Gordon

Moore, en la actualidad, ya no es posible disminuir el tamano de los transistores. Para compensarlo

se han construido procesadores que tienen mas de un nucleo de procesamiento (2, 4, 8, 12). Las

computadoras de uso general que estan en el mercado al momento de la realizacion del presente

trabajo cuentan con procesadores paralelos, es decir tienen mas de un nucleo de procesamiento.

Esta cualidad indica que el computo en paralelo esta a disposicion de todos.

Cuando la arquitectura del hardware de las computadoras paso a ser paralelo se creo la necesidad

de desarrollar aplicaciones que aprovechen estas caracterısticas. La incorporacion de nucleos de

1

Page 18: Esquemas iterativos en paralelo con OpenMP

2 Capıtulo 1. Introduccion

procesamiento tienen el fin de que las aplicaciones se ejecuten mas rapido. Para ejemplificar el

problema supongase lo siguiente: se quiere extraer el agua de un tanque que tiene 1, 000m3 para

ello se utiliza una bomba que extrae 250m3 del lıquido por cada hora de trabajo. Esta maquina

terminara su tarea en 4 horas. Si en un momento se aumenta 7 bombas mas para hacer un total

de 8, la tarea sera concluida en apenas 30 minutos, con ello se redujo el tiempo del proceso. Esto

refleja la importancia del computo en paralelo. Con lo ya mencionado el computo en paralelo es la

solucion a problemas contemporaneos.

Cabe mencionar que en la actualidad la mayorıa de las aplicaciones son seriales, es decir se

ejecutan solo en uno de los nucleos; entonces estos programas no estan aprovechando al maximo los

recursos con los que cuenta el equipo. Para contrarrestarlo se fomenta el deseo de escribir codigos

que puedan ejecutarse en paralelo.

Una pregunta que surge con lo mencionado; ¿En que nos beneficia la programacion en paralelo?

La respuesta es por demas sencilla. En el mundo de la industria manufacturera se realizan procesos

de control de calidad, en los cuales se recurre a la simulacion de eventos mediante computadoras.

Estas medidas son cada dıa mas frecuentes. Un ejemplo mas que evidente ocurren en la industria

automotriz en la simulacion de sus prototipos frente a las colisiones. Hacer estas pruebas en fısico

representa un costo economico muy representativo; es por ello que se recurre a la simulacion del

evento con resultados fidedignos. Para obtener estos resultados tan realistas se deben tomar en

cuenta muchas variantes que influyen en los resultados del proceso, todo esto aumenta la complejidad

de operaciones en modelo del suceso. El costo computacional de un modelo depende del grado

de complejidad operacional. Con ello es concluyente que estas simulaciones deben ser resueltas

con programacion en paralelo, para reducir los tiempos de simulaciones y ası reducir el ciclo de

lanzamiento de los nuevos modelos; lo cual es primordial para la generacion de utilidades de la

industria automotriz.

Motivacion

La principal motivacion del presente proyecto consiste en explotar al maximo lo recursos que

ofrecen las computadoras; mediante tecnologıas para la programacion en paralelo.

En los labores de la ingenierıa y en la ciencia en general se formulan problemas mediante modelos

matematicos y son tratados numericamente, ello conduce frecuente a resolverlos por sistemas de

Page 19: Esquemas iterativos en paralelo con OpenMP

Capıtulo 1. Introduccion 3

ecuaciones lineales. Como es bien sabido esta tarea es muy demandante en tiempo de calculo. En

virtud de ello y con base a la tendencia del analisis numerico es inherente que sean resueltos con

aplicaciones computacionales paralelas.

Para la resolucion de sistemas de ecuaciones lineales existen dos tipos de metodos; directos e

iterativos. Los metodos directos son utilizados para sistemas hasta de pocos miles de nodos debido

a su orden de complejidad; ocasionando que sea imposible el resolverlo por cuestiones de tiempo.

Por otra parte los metodos iterativos se utilizan para sistemas con una mayor cantidad de nodos en

virtud de su orden de complejidad que es menor a la de los directos. Dentro de los metodos iterativos

se encuentran el de Jacobi y Gauss-Seidel que son los dos pilares fundamentales. En la presente tesis

se estudia el diseno de dos algoritmos paralelos que implementen los esquemas de Jacobi y Gauss-

Seidel. En la literatura existen algoritmos iterativos paralelos reportados, sin embargo no existe

codigo fuente por ello en el presente documento se da enfasis al desarrollo de estos algoritmos desde

un punto de vista practico con la finalidad de proporcionar ese codigo fuente.

En la literatura hemos encontrado distintos modelos matematicos y esquemas en paralelo con

OpenMP para la resolucion de sistemas lineales de ecuaciones [21, 26, 35, 36]. Sin embargo, se

enfocan principalmente a sistemas ralos o esparcidos y tipo QR o de Cholesky. Esto se debe princi-

palmente a que las discretizacion de ecuaciones diferenciales parciales (EDP) esta basada principal-

mente en los metodos de elemento finito, volumen finito y diferencia finita los cuales generan este

tipo de matrices.

En el desarrollo profesional de metodos numericos se busca la innovacion para poner a disposicion

el nuevo software. Existen una gran variedad de librerıas publicas para la optimizacion de codigo,

ejemplos son BLAS (Basic Linear Algebra Subprograms) y LAPACK (Linear Algebra Package)

que permiten la optimizacion para programas secuenciales. Dentro de las arquitectura multicore

encontramos en el top las librerıas especıficas Intel R© Math Kernel Library, CUBLAS y CULA de

CUDA R©; estan altamente optimizadas para sus respectivas arquitecturas de hardware. En general,

el uso de estos paquetes de optimizacion no son utilizadas en el desarrollo del software comercial,

excepto para la construccion de programas muy especializados o en proyectos que se encargan de

aglomerar todas estas optimizaciones como por ejemplo PLASMA (Parallel Linear Algebra Software

for Multiprocessor Architectures).

Proyectos como FLAME (Formal Linear Algebra Methods Environment) y PLASMA reflejan

Page 20: Esquemas iterativos en paralelo con OpenMP

4 Capıtulo 1. Introduccion

una fuerte tendencia de encapsular y abstraer el codigo lo que facilita el trabajo del programador. En

el caso de FLAME se abstrae el hardware dando mayor portabilidad a estas aplicaciones; haciendo

transparente el hardware, lo que permite ejecutar una implementacion en cualquier arquitectura.

Ademas permite utilizar todos los recursos disponibles CPU y GPU.

Al abstraer el codigo se aumenta la dificultad para la optimizacion mas especıfica de las apli-

caciones. Ademas la falta de codigo fuente que pueda ser analizado y/o modificado; limita la parte

academica. Estas librerıas se asemejan a las “cajas negras” porque no sabemos que hay dentro y

por tanto no aprendemos de ellas.

Lo anterior dicho, motiva que el presente trabajo se dirija al estudio e implementacion de los

dos pilares de los metodos iterativos, con herramientas publicas; con fines academicos. Esto se debe

a que el estudio de los metodos iterativos de Jacobi y Gauss-Seidel tiene fines didacticos y conforma

la base de estudio para las tecnicas modernas de metodos numericos. En la actualidad el software

especializado y la investigacion de frontera emplean metodos proyectados sobre subespacios de tipo

Krylov[1, 2, 16, 22, 38], ejemplos de software especializado son las librerıas de Portable Extensible

Toolkit for Scientific computation (PETSc) con implementaciones paralelas [4, 34, 42]. El estudio

de ello esta fuera del alcance de la presente memoria.

Objetivo general

La presente tesis tiene como objetivo el desarrollo de esquemas iterativos en paralelo con

OpenMP para la solucion numerica de sistemas de ecuaciones lineales. Para ello emplearemos una

computadora con arquitectura de tipo multi-nucleo con memoria compartida y utilizamos el lenguaje

de programacion C.

Objetivos particulares

A continuacion se listan los objetivos especıficos que seran tratados durante la realizacion del

presente documento:

1. Disenar e implementar el metodo de Jacobi y Gauss-Seidel en paralelo para resolver sistemas

de ecuaciones lineales.

2. Incrementar el rendimiento computacional mediante tecnicas avanzadas de programacion.

Page 21: Esquemas iterativos en paralelo con OpenMP

Capıtulo 1. Introduccion 5

3. Medir el desempeno de los algoritmos disenados para cuantificar los beneficios del paradigma

de programacion.

4. Medir la escalabilidad de los algoritmos disenados en computadoras multi-nucleo.

5. Crear un biblioteca de funciones que permitan resolver numericamente sistemas de ecuaciones

lineales en paralelo para computadoras SMP.

Al termino de la presente tesis se habran cumplido con los objetivos planteados; los cuales

pondran en evidencia los beneficios mediante el incremento del rendimiento por paralelizar metodos

numericos. Con los resultados obtenidos se busca motivar la incipiente tendencia de generalizar la

programacion en paralelo.

La estructura del presente trabajo de tesis esta organizada en seis capıtulos que se describen a

continuacion.

En el primer capıtulo, el presente, se describen los objetivos que permitiran llevar a buen termino

el proceso de elaboracion de la presente memoria. Tambien se mencionan las razones que dan

importancia a este estudio.

Enseguida, en el tema 2 se plantea un marco teorico que le permita al lector familiarizarse

desde un punto de vista general, con los conceptos que se tratan durante el restos de los capıtulos.

Aunado a ello se realiza una breve descripcion de las tecnicas y herramientas tecnologicas que seran

utilizadas. Se indican temas de vital importancia para la evaluacion de algoritmos en paralelo como

lo son Speed-up, Ley de Amdahl y Escalabilidad paralela, ası como la representacion de los numeros

reales en la computadora. Tambien se da un breve introduccion que intuye a la comprension del

error en los metodos numericos.

En el capıtulo 3 tratamos uno de los problemas mas basico pero de importancia muy relevante,

el Producto matriz-vector. Se pone un especial cuidado en el estudio de este tema por representar

un proceso muy demandante de tiempo de calculo. Se emplean modernas tecnicas de programacion

como Loop unrolling y procesamiento vectorial con Intel MMX R© para explotar nuevas caracterısti-

cas de los microprocesadores; para determinar cual representa la mejor opcion en paralelo. Cabe

senalar que en este bloque se estudia el Calculo del residual una tecnica utilizada como condicion

de paro en los esquemas iterativos.

Posteriormente en el capıtulo 4 se estudia el Metodo iterativo de Jacobi, en primer lugar se tratan

algunos de los metodos directos para la solucion de sistemas lineales de ecuaciones mas conocidos,

Page 22: Esquemas iterativos en paralelo con OpenMP

6 Capıtulo 1. Introduccion

Regla de Krammer, Eliminacion de Gauss-Jordan y la Factorizacion LU para determinar los pros

y contras de ambas categorıas (metodos directos e iterativos). Despues se realiza una descripcion

del esquema y consecuentemente la programacion. Con el unico fin de aumentar el rendimiento se

realiza una serie de optimizaciones basadas en los resultados del tema anterior. Al final de este

capıtulo se realiza una evaluacion exhaustiva que arroja resultados muy concretos con respecto a

las modificaciones realizadas en cada uno de los subtemas.

En el capıtulo 5 tratamos el Metodo Iterativo de Gauss-Seidel (G-S), en primer lugar se da una

descripcion del metodo con vistas hacia la programacion del mismo. En segundo lugar se implementa

OpenMP prestando especial antencion en la dependencia de operaciones a las que esta sujeto G-S.

En un tercer momento se realiza una comparacion con diferencias finitas para medir convergencia

de Jacobi y G-S, lo cual permita enmarcar las diferencias teoricas de ambos.

Finalmente en el capıtulo 6 mostramos las conclusiones generales y el trabajo a futuro.

Page 23: Esquemas iterativos en paralelo con OpenMP

Capıtulo 2Marco Teorico

2.1. Metodos numericos

En palabras de Chaillou [9] son las tecnicas mediante las cuales es posible formular problemas

de manera que puedan resolverse utilizando operaciones aritmeticas.

Es importante el estudio de los metodos o esquemas numericos porque representan una herra-

mienta importante para el analisis y diseno de algoritmos que permiten la resolucion de problemas

de la ciencia. Existe una extensa gama de esquemas numericos para la resolucion de gran parte de

los problemas. Sin embargo, con el mismo metodo no se puede resolver todos problemas; por ello es

indispensable el analisis de un grupo de candidatos con el fin de determinar cual de ellos es el mas

indicado para el problema que se este estudiando.

Como menciona Penades [33] con la aparicion de los multiprocesadores se presenta un nuevo reto,

adecuar los antiguos algoritmos para las nuevas tecnologıas; entre las que destaca la computacion

matricial. Pero esta nueva tendencia tambien sugiere y motiva la busqueda de metodos nuevos que

se adecuen mejor a la vanguardia tecnologica con el fin de aumentar el rendimiento computacional

para la resolucion de ciertos problemas.

2.2. Modelacion matematica

Una definicion muy simple es la proporcionada por Chaillou en [9] la cual dice: un modelo

matematico es una formulacion o ecuacion que expresa las caracterısticas fundamentales de un

7

Page 24: Esquemas iterativos en paralelo con OpenMP

8 Capıtulo 2. Marco Teorico

sistema o proceso fısico en terminos matematicos. Esto nos indica que un modelo corresponde a

una explicacion de un proceso de un forma simple, lo cual conduce a resultados predecibles.

Los modelos matematicos sirven para obtener cierta informacion de un problema que se este estu-

diando; si bien en cierto que frecuentemente contienen errores que ponen en evidencia componentes

esenciales de una realidad compleja [9]. Existe un clasificacion de tipos de modelos matematicos en

funcion a su area de estudio; estos temas no son tratados con la profundidad necesaria debido que

no es la finalidad del presente trabajo.

2.3. Los numeros en la computadora

En el mundo real existen varios sistemas numericos entre los que destacan los sistemas arabico,

binario, octal, hexadecimal. El mas utilizado por todo ser humano es el arabico o mejor conocido

como decimal. Por otro lado el sistema numerico de las computadoras es el binario para describir los

estados encendido (1) apagado (0); ası un dıgito binario o bit es la unidad de informacion mas basica

en la computadora. Debido a que los humanos utilizamos el sistema decimal y las computadoras

el binario se hizo necesario realizar conversiones de numeros entre ellos. Fue Gottfried Leibniz

(1646–1716) quien desde siglos pasados lo habıa resuelto. Leibniz argumento que cualquier numero

entero puede ser representado por una serie de unos y ceros.

En documentos como [29, 37] se emplea el formato mantisa/exponente para representar numeros

binarios tomando la idea de la notacion cientıfica. Como se muestra en (2.1)

1010 = 10.010 × 100 = 1.010 × 101 = 0.110 × 102

10102 = 1010.02 × 20 = 101.02 × 21 = 10.102 × 22(2.1)

El manejo de los numeros en la computadora es mediante la notacion cientıfica del sistema

binario.1 Sin embargo, los formatos que se utilizan permiten representar los numeros como en (2.1)

sin escribir de forma explıcita el punto decimal. El formato signo/mantisa/exponente se expresa

1El sistema numerico de la computadora se debe a la arquitectura de la misma. Recordando que existen compu-tadoras binarias, octales y hexadecimales. Las computadoras comerciales son binarias.

Page 25: Esquemas iterativos en paralelo con OpenMP

2.3. Los numeros en la computadora 9

como una palabra con las siguientes caracterısticas para un valor x

x =

signo︷︸︸︷s e1e2e3 . . . ek︸ ︷︷ ︸

exponente

mantisa︷ ︸︸ ︷m1m2m3m4 . . .mn (2.2)

Sabiendo que cuando el bit de s este encendido se trata de un numero negativo. Tomando como

referencia (2.2) la longitud de la palabra que equivale a (1 + k + n) donde los valores de k y n

son definidos por el disenador y 1 representa el bit s del signo; para definir los valores de k y n

es imprescindible pensar en la exactitud con lo que se representaran los numero reales, ası como

analizar el costo computacional que representa. Para ejemplificar tomaremos un formato de 8 bits

como sigue

x =

signo︷︸︸︷b1 b2 b3 b4︸ ︷︷ ︸

exponente

mantisa︷ ︸︸ ︷b5 b6 b7 b8 (2.3)

Partiendo de (2.3) representemos 1010 = 10102 con cuatro bits. Con el formato en cuestion

puede ser representado como sigue

x =

sig︷︸︸︷0 0 0 1︸︷︷︸

exp

man︷ ︸︸ ︷1 0 1 0 = 10102 × 21 = 1010

Ahora tomando un valor mayor por ejemplo 6410 = 10000002, lo cual en notacion cientıfica se

expresa como 1000× 23 y se representa como sigue

x =

sig︷︸︸︷0 0 1 1︸︷︷︸

exp

man︷ ︸︸ ︷1 0 0 0 = 10002 × 23 = 6410

Para representar un numero negativo por ejemplo −1810 se realiza lo siguiente

x =

sig︷︸︸︷1 0 1 0︸︷︷︸

exp

man︷ ︸︸ ︷1 0 0 1 = −1× 10012 × 22 = −1810

Como se puede observar el valor mas grande y el menor que se pueden representar son

xmax = 0 111 1111 = 1× 11112 × 27 = 192010

xmin = 1 111 1111 = −1× 11112 × 27 = −192010

Page 26: Esquemas iterativos en paralelo con OpenMP

10 Capıtulo 2. Marco Teorico

Para exponer el formato de (2.3) ante una situacion cotidiana en el calculo intensivo tomemos

el numero 2710 = 110112 como sabemos tenemos solo cuatro bits de mantisa y este nuevo numero

tiene 5 bits, lo cual tomamos los 4 bits mas significativos y tenemos lo siguiente

x =

1︷︸︸︷0 0 1 0︸︷︷︸

2

13︷ ︸︸ ︷1 1 0 1 = 1× 11012 × 22 = 2610

Ello no es equivalente con el numero que se trata de representar y el siguiente serıa

x =

1︷︸︸︷0 0 1 0︸︷︷︸

2

14︷ ︸︸ ︷1 1 1 0 = 1× 11102 × 22 = 2810

Con ello es mas que evidente que no se puede representar el numero 27 utilizando el formato de

(2.3). Pero esto no significa que sea el unico. En la figura 2.1 se ilustra los numeros que se pueden

representar con este formato. Las lıneas verticales (|) indican la posicion en la linea recta de cada

uno de los numeros, por lo que no existen numeros en los espacios entre las lıneas. Como se puede

observan la mayor densidad de numeros esta en los aledanos de cero y conforme nos alejamos la

densidad disminuye.

−2000 −1500 −1000 −500 0 500 1000 1500 2000

Figura 2.1: Distribucion de numeros enteros con formato predefinido.

Bien, con el formato de (2.3) se han representado numeros enteros pero con un aspecto impor-

tante, existen numeros que pueden ser representados de mas de una forma lo cual no es bueno.2

Con lo anterior se han representado numeros enteros de una forma no ortodoxa pero nos brinda

un primer acercamiento para representar numeros reales. Tomando la idea del formato (2.3) y con

base a Hidalgo [19, Apendice E] se realiza una modificacion simple que se expresa en (2.4)

x =

signo︷︸︸︷b1 b2 b3 b4︸ ︷︷ ︸

exponente

bimp b5 b6 b7 b8︸ ︷︷ ︸mantisa

(2.4)

donde la mantisa trata la parte fraccionaria del numero [ver (2.1)] y bimp es un bit implıcito que

2Nota: con este formato se han representado numeros enteros unica y exclusivamente para exponer el formatomantiza/exponente y no representa el verdadero formato para la representacion de enteros en la computadora.

Page 27: Esquemas iterativos en paralelo con OpenMP

2.3. Los numeros en la computadora 11

actua ası

si 0 < exp< 7, entonces bimp = 1.

si exp = 0 y mantisa 6= 0, entonces bimp = 0.

Tambien se establece la necesidad de representar los exponentes con signo por ello se indica lo

siguiente

si 0 < exp< 7, entonces exp = exp - 3.

si exp = 0 y mantisa 6= 0, entonces exp = -2.

Con base a ello se establece que para un valor x se obtiene como sigue

x = (−1)s · 2exp−3 · 1.mantisa para 0 < exp < 7 y

x = (−1)s · 2−2 · 0.mantisa para exp = 0

donde exp es el valor del exponente, s el signo y [(0 : 1).mantisa] es el bit implıcito (bimp) y el valor

de las mantisa (b5b6b7b8).

La idea anterior hace que el numero 010110012 con el formato (2.4) se convierte en decimal de

la siguiente forma

x =

s=0︷︸︸︷0︸︷︷︸

signo

exp=5︷︸︸︷1 0 1︸ ︷︷ ︸

exponente

bimp.mantisa=1.5625︷ ︸︸ ︷bimp 1 0 0 1︸ ︷︷ ︸

mantisa

= (−1)0 · 25−3 · 1.5625 = 6.2510

Ahora se convierten x1 = 111010102 y x2 = 000001102 a decimal como sigue

x1 = 11101010 = (−1)1 · 26−3 · 1.625 = −1310

x2 = 00000110 = (−1)0 · 2−2 · 0.375 = 0.0937510

Como se puede observar el cambiar el formato de representacion de los numeros hace que los

valores al convertirlos a decimal sea distinto. En la figura 2.2 se ilustra la distribucion de los numeros

representables con este formato, donde se puede observar que la densidad de la retıcula cercas del

cero es muy alta. Conforme nos alejamos de cero la cantidad de numeros representables disminuye.

Page 28: Esquemas iterativos en paralelo con OpenMP

12 Capıtulo 2. Marco Teorico

−16−15.0 −10 −5 0 5 10 15 16

Figura 2.2: Distribucion de numeros reales con formato predefinido.

Con los dos ejemplos planteados se tiene una idea mas concreta de la representacion de los

numeros mediante una serie de bits. En ambos casos se utilizo 8 bits como longitud de palabra. Sin

embargo el resultado es distinto pero con similitudes. La mayor densidad de numeros representables

estan cercas del cero y en los extremos existe una menor densidad. En el primer ejemplo se repre-

sentaron numeros enteros con un rango (-1920,1920) mientras que en el segundo se representaron

numeros reales en un rango de (-15.5,15.5). Es evidente la imposibilidad de representar la totalidad

de los numeros con una longitud de palabra finita.

La representacion de los numeros reales (numeros con fraccion de entero) en la computadora

fue en su momento un tema hermetico en cada una de las empresas manufactureras de las mismas.

El hermetismo era a tal grado que las empresas tenıan su propio protocolo, lo que limitaba la por-

tabilidad. Como menciona Severance et al.[37] esos formatos para representar numeros en punto

flotante se enfocaron primordialmente en la exactitud y no tanto en un balance entre exactitud y

velocidad. Con base a Null et al.[29] la solucion para ello llego en 1985 por parte del Instituto de

Ingenieros Electricos y Electronicos (IEEE por sus singlas en ingles) que produjeron un estandar

para representar numero en punto flotante para simple y doble precision, el estandar se titulo “IEEE

754-1985 Standard for Binary Floating-Point Arithmetic”. El nuevo estandar tuvo sus inicios du-

rante el diseno del coprocesador para punto flotante Intel i8087 [37]. Pasaron mas de 10 anos para

que los grandes fabricantes adoptaran el IEEE 754 de forma generalizada en la contruccion de

computadoras.

En la figura 2.3 se ilustra como se representan dos tipos de numeros definidos en el estandar de

IEEE. Como se puede observa el formato es signo/exponente/mantisa al igual que en el segundo

ejemplo. (A) es un formato que en el lenguaje de programacion C se le conoce como float donde

se tienen 23 bits de mantisa y 8 de exponente. (B) corresponde la primitiva double en el lenguaje

de programacion C que corresponde a 52 bits de mantisa y 11 bits; es mas comunmente conocido

como doble precision cientıfica.

Segun Severance et al.[37] en precision simple el menor numero normalizado es 1.2E-38 y

Page 29: Esquemas iterativos en paralelo con OpenMP

2.3. Los numeros en la computadora 13

Figura 2.3: Modelo para representacion de numeros en punto flotante IEEE 754.

2.2E-308 con doble precision. Mientras que el numero mas grande para simple y doble es 3.4 E+38

y 1.8 E+308 respectivamente. Ello nos brinda un marco de trabajo mas amplio y con errores mas

pequenos.

Con base en Null y Severace [29, 37] este estandar incorpora NaNs (Not a Number, no es

numero) cuando el exponente sea igual a 255 y la mantisa no sea cero (exp = 255 y mantisa 6= 0),

los NaNs son utilizados como indicadores de error. Tambien incluye dos infinitos (−∞ y +∞) que

se presentan cuando el exponente es 255 y la mantisa es 0, positivo cuando el signo es 0 y negativo

cuando es 1. Al igual que en el caso de infinito, se tienen dos ceros uno positivo y otro negativo.

En el presente documento se utilizan numero de precision simple como el formato (A) de la figura

2.3 mientras no se indique lo contrario. Como se ha especificado ese formato tiene una longitud de

32 bits para la representacion de los numeros por lo cual se pueden representar la siguiente cantidad

de numeros (n)

n = 232 = 4 294 967 296

De acuerdo con la definiciones anteriores para el caso donde el exponente es igual a 255 todos

los numeros son considerados NaNs, excepto cuando la mantisa es 0; este caso se presenta dos veces

para −∞ y +∞ respectivamente. Con base a ello podemos obtener la cantidad de NaNs que se

representan

NaNs = 2× 223 − 2 = 16 777 214

Para obtener el total de numero representables con precision simple sustraemos lo NaNs del

Page 30: Esquemas iterativos en paralelo con OpenMP

14 Capıtulo 2. Marco Teorico

total n

Total de reales representables = 4 294 967 296− 16 777 214 = 4 278 190 082

De antemano sabemos que existe una diferencia entre el cero y el primer numero que puede ser

representado, haciendo el numero mas pequeno posible tendremos el menor numero distinto de cero

que puede ser representable como sigue

x =

signo︷︸︸︷0

exponente︷ ︸︸ ︷000 0000 0

mantisa︷ ︸︸ ︷000 0000 0000 0000 0000 00012 = (−1)0 × 2−126 × 2−23 = 2−149

x ' 1.4× 10−45

Como menciona Nakamura [28] al numero representable inmediatamente despues de la unidad se

le conoce como el epsilon de la computadora el cual nos permite calcular el numero real representable

inmediatamente posterior; esto se obtiene al multiplicar el epsilon por el real y sumarlo a ese real.

Para calcular el epsilon se puede utilizar el fragmento de codigo de la figura 2.4. En ese codigo solo

hace falta indicar el tipo de variable que es “epsilon” (simple o doble). El ultimo valor impreso

corresponde al epsilon de la computadora. Para una ejecucion con precision simple (float) se tiene

epsilon' 1.1921 × 10−7, en el otro caso (double) epsilon ' 2.2204 × 10−16. Cabe senalar que el

denominador para calcular el epsilon es dos porque la computadora empleada es binaria.

Calculo del epsilon

epsilon = 1;

while(1+epsilon>1)

printf("%f\n",epsilon);

epsilon = epsilon/2;

Figura 2.4: Calculo de epsilon de la computadora.

Para corroborar que efectivamente el epsilon de la computadora sirve para calcular la distancia

entre un numero real representable y su inmediatamente consecuente tomaremos el siguiente ejemplo

x1 =

signo︷︸︸︷0

exponente︷ ︸︸ ︷000 0000 1

mantisa︷ ︸︸ ︷100 0000 0000 0000 0000 00002 = (−1)0 × 21−127 × 1.5

x1 = (−1)0 × 2−126 × 1.5 ' 1.7632415262× 10−38

Page 31: Esquemas iterativos en paralelo con OpenMP

2.3. Los numeros en la computadora 15

Ahora multiplicamos x1 por el epsilon para obtener la diferencia (y) tomando mas cifras signi-

ficativas para disminuir el error

x1 ' 1.7632415262× 10−38 y epsion = 1.1921× 10−7

y = x1 × epsilon

y ' 1.7632415262× 10−38 × 1.1921× 10−7

y ' 2.1019602234× 10−45

xα2 = x1 + y = 1.7632415262× 10−38 + 2.1019602234× 10−45

xα2 = 1.7632417364× 10−38

Posteriormente se calcula el valor para x2 tomando el siguiente numero de la serie como sigue

x2 =

signo︷︸︸︷0

exponente︷ ︸︸ ︷000 0000 1

mantisa︷ ︸︸ ︷100 0000 0000 0000 0000 00012 = (−1)0 × 21−127 × 1.5 + 2−23

x2 ' 1.7632416664× 10−38

Con estos resultados podemos decir que xα2 = x2, donde el error se debe en gran medida a la

cantidad de cifras significativas tomadas en cuenta. Con base a los temas anteriores es concluyente

que la distancia entre un numero representable y su inmediatamente posterior crece conforme se

aleje de cero.

Figura 2.5: Rango de numero IEEE-754 precision simple.

En la figura 2.5 se muestra el rango en el cual podemos representar numeros con el estandar

IEEE-754. Siempre pensando que la mayor densidad de numeros estan aledanos al cero. Visualizar

el rango nos permite mapear los numeros para no caer en valores underflow u overflow e inclusive

elegir el tipo de precision con la finalidad de tener una mayor exactitud.

La incapacidad para poder representar la totalidad de los numeros conlleva a tener resultados

Page 32: Esquemas iterativos en paralelo con OpenMP

16 Capıtulo 2. Marco Teorico

numericos aproximados. Ella es como una enfermedad con la que se nace; sino es tratada puede ser

letal.

2.4. Tipos de error en metodos numericos

En analisis numerico un tema de vital importancia es el estudio del error en un resultado

numerico. Esto se debe principalmente a que los datos de entrada no son exactos; tambien influye que

los metodos numericos introducen errores de varios tipos; por ello los resultados son aproximados.

Como menciona Chaillou [9] en muchos casos profesionales los errores son costosos y en algunos

letales. A continuacion se presentan los principales errores introducidos por los esquemas numericos.

Error de redondeo: este tipo de error se presenta debido a la cantidad de cifras significativas

que se asignan para las operaciones. En terminos de computacion este error es muy comun y

depende de la exactitud de la primitiva utilizada (precision simple, doble precision, etc.), para

la representacion de los numeros reales en la maquina. Para tener una idea mas clara tomemos

en cuenta un numero real x con k cifras en punto flotante, lo cual se representa como

x = 0.d1d2 . . . dk × Bn donde B es la base del sistema

dado que unicamente se tienen t cifras significativas, siendo t < k, el numero real sera repre-

sentado como sigue

x = 0.d1d2 . . . dt × Bn

con ello se han perdido k − t cifras del valor real de x con lo cual x es una aproximacion de

x. A continuacion se muestra un ejemplo

x = 1.2345678 con t = 4 se tiene x = 1.2345

Este error es inherente a la computacion como consecuencia de la imposibilidad de representar

totalmente los numeros reales. Para disminuir este error se aumenta el tamano de la mantisa

de bits (aumentar k), ası se tendran mas cifras para la representacion de los numeros; pero

ello repercutira en un aumento en el costo de calculo.

Error por truncamiento: este tipo de error aparece como consecuencia de las reglas de cifras

Page 33: Esquemas iterativos en paralelo con OpenMP

2.4. Tipos de error en metodos numericos 17

significativas que se establezcan, donde a partir de t cifras el valor se redondea al extremo

proximo. Por ejemplo tomando tres cifras significativas (en punto flotante) de x para obtener

x como sigue

x1 = 23.333333 se redondea a x1 = 23.333

x2 = 23.333690 se redondea a x2 = 23.334

En problemas aplicados a metodos numericos el error de truncamiento surge al “truncar” una

serie de operaciones. Citando textualmente a Nakamura [28] el error de truncamiento se debe

a las aproximaciones utilizadas en la formula matematica del modelo. Un claro ejemplo de ello

es la Serie de Taylor para mostrarlo veamos la expresion de esta serie

f(x+ h) = f(x) + hf′(x) +

h2

2!f

′′(x) +

h3

3!f

′′′(x) + · · ·+ hm

m!f (m)(x) + · · · (2.5)

En la practica se trunca (2.5) debido a que es imposible utilizar un numero infinito de terminos.

A continuacion se representa una serie truncada de Taylor hasta despues del termino de orden

m

f(x+ h) = f(x) + hf′(x) +

h2

2!f

′′(x) +

h3

3!f

′′′(x) + · · ·+ hm

m!f (m)(x) +O(hm+1) (2.6)

donde O(hm+1) representa el error por el truncamiento.

La Serie de Taylor representa un punto de partida para la obtencion de metodos numericos.

En el polinomio de Taylor (2.6) el error de truncamiento se reducira conforme m → ∞.

Como menciona Nakamura [28] calcular el valor exacto del error de un polinomio de Taylor es

practicamente imposible es por ello que se representa con una aproximacion que corresponde

O(hm+1). En general el error de truncamiento nace al representar una serie infinita con otra

serie finita de operaciones.

Error absoluto: este error corresponde a la diferencia absoluta entre un resultado exacto y

otro aproximado. Esto se representa como

EA = |x− x| (2.7)

Page 34: Esquemas iterativos en paralelo con OpenMP

18 Capıtulo 2. Marco Teorico

donde x es el resultado exacto y x es el aproximado.

Error relativo: consiste en normalizar el error respecto al resultado exacto. Lo cual se expresa

como

ER =|x− x||x|

(2.8)

donde x es el resultado exacto y x es el aproximado. Si multiplicamos el error relativo por

cien se obtiene el error porcentual del resultado aproximado.

2.5. El lenguaje de programacion C

El lenguaje C es de alto nivel pero mantiene caracterısticas de bajo nivel. De alto nivel porque

es estructurado, facil de aprender pero mas que nada racional[15]. Y de bajo nivel porque permite

trabajar con el lenguaje maquinas los bits, registros de la CPU y registros de memoria. Algunas de

las caracterısticas son la siguientes tomadas del libro de Basurto et al.[6]:

Potencia y flexibilidad: C es un lenguaje no tan alejado del lenguaje maquina lo cual

puede traducirse en un mejor desempeno computacional. Otro punto a favor del lenguaje es

la flexibilidad para la creacion de aplicaciones que van desde modestas aplicaciones de consola

a robustos sistemas operativos graficos como UNIX y sus derivados.

Popularidad: como la mayorıa de los grandes proyectos, el lenguaje C debe su popularidad

a la variedad de recursos como compiladores, herramientas y librerıas.

Portabilidad: gracias al estandar ANSI C un programa escrito en C puede ser compilado y

ejecutado en diferentes arquitecturas con pocos o nulos cambios.

Sencillez: el lenguaje C es muy facil de aprender por contar con un numero muy reducido de

palabras reservadas.

Estructura y modularidad: C es el primer lenguaje de programacion bien estructurado

que permite la agrupacion de codigo en funciones; que posteriormente puede ser reutilizado.

El conjunto de cualidades anteriormente descritas coadyuvan para que este lenguaje cuente

con el soporte de varias interfaces que permitan la programacion en paralelo y juntos sean una

herramienta importante para el computo cientıfico.

Page 35: Esquemas iterativos en paralelo con OpenMP

2.6. Programacion en paralelo 19

En el presente documento se utiliza lenguaje C en su totalidad. Esto se debe a las caracterısticas

que son sencillez y racional para la creacion de codigo; ası como la flexibilidad en el manejo de

vectores y matrices mediante los apuntadores. La compatibilidad de C con la API OpenMP es el

motivo principal por el cual se utiliza este lenguaje de programacion. Cabe senalar que FORTRAN

es otro lenguaje compatible con esta API; no se utilizo en este trabajo porque se tenıa un mejor

dominio del lenguaje C.

2.6. Programacion en paralelo

Como menciona Pacheco [31] de 1986 a 2002 el incremento del rendimiento en los micropro-

cesadores fue de 50 % por ano; el aumento de la velocidad de los procesadores estuvo sujeta a la

densidad de transistores del circuito integrado, cada ano se aumentaba en ese mismo porcentaje.

Como menciona Petersen et al.[34] esto se debe a una ley formulada por Gordon Moore (uno de

los fundadores de Intel) en 1965 conocida como ley de Moore: el incremento de la velocidad de los

procesadores debera ser duplicada cada dos anos. Por problemas de diseno ya es imposible continuar

con esa tendencia, por lo cual en el lapso de 2002 a 2005 el aumento de la velocidad se redujo a

20 % anual.

Para 2005 la industria de microprocesadores acordo incrementar el rendimiento con un cambio

en el diseno; se eligio el camino del paralelismo. Esto consiste en dejar de construir procesadores

monolıticos mas rapidos; para centrarse en la construccion de circuitos integrados que contengan

varios procesadores completos. Con base a Petersen et al.[34] actualmente las computadoras con

multiprocesadores y el desarrollo de algoritmos suman un mayor aumento en el rendimiento que el

establecido en la ley de Moore; esto habla del poder que le dota al computo esta tendencia. Con las

medidas tomadas por los industriales se puede cumplir con las nuevas demandas de rendimiento en

las diferentes areas que lo requieran.

Las nuevas tendencias en la contruccion de hardware paralelo representa un nuevo reto para

los programadores, la realizacion de software capaz de explotar las nuevas caracterısticas de estos

recursos electronicos. En la actualidad la mayorıa del software en el mercado es serial; ello indica

que esas aplicaciones unicamente explotan una fraccion de los recursos de la computadora.

Durante la realizacion de este trabajo se ha observado una fuerte tendencia en la programacion

de aplicaciones paralelas, estos programas son divididos en multiples instancias tantas como nucleos

Page 36: Esquemas iterativos en paralelo con OpenMP

20 Capıtulo 2. Marco Teorico

contenga el sistema. Ello con la finalidad de presentar resultados en el menor tiempo posible.

Durante la traduccion de aplicaciones seriales a paralelas nos encontramos con problemas de

adaptacion de algoritmos y/o modelos; como menciona Pacheco [31] un algoritmo serial eficiente

puede convertirse en uno paralelo ineficiente. Por ello la tarea de los programadores para traducir

programas secuenciales en paralelos es difıcil.

La programacion en paralelo esta influenciada directamente por la tendencia del desarrollo de

hardware denotada por la construccion de sistemas fısicos. Para la programacion en el lenguaje

estructurado C existen tres alternativas principales; Message-Passing Interface (MPI, Interfaz de

Paso de Mensajes), POSIX threads (Pthreads) y OpenMP. El primero de ellos esta orientado a

la programacion paralela para memoria distribuida. Los otros dos son utilizados en sistemas con

memoria compartida, como diferencia Pthreads al igual que MPI son librerıas y definiciones que

se usan dentro de programas mientras que OpenMP esta constituido por una librerıa y algunas

modificaciones al compilador. Como menciona Petersen et al.[34] OpenMP es mas facil de programar

e implementar que Pthreads.

En tiempo mas reciente ha surgido un tipo de computo distinto que consiste en utilizar la

tarjeta grafica (GPU) para resolver operaciones aritmeticas. Un ejemplo de ello es la interfaz de

programacion CUDA propiedad de la empresa Nvidia, esto revoluciona la fabricacion de hardware

en la cual se incluyen miles de procesadores. Cada uno de ellos tiene mucho menores prestaciones

de procesamiento que un CPU; sin embargo, juntos le permiten al GPU desarrollar un incremento

sustancial de rendimiento comparable e inclusive mejor que la CPU. Al igual que las tres tecnologıas

antes mencionadas CUDA trabaja con memoria compartida y distribuida. Una de sus opciones

programables es mediante el lenguaje C++. Con base al manual de Nvidia CUDA [30] el modelo de

programacion de CUDA esta enfocado al paralelismo masivo, el diseno del hardware permite lanzar

miles de hilos de ejecucion a la vez. En la figura 2.6 extraıda de [30, fig.1-3 pag.3] se ilustra las

diferencias en la construccion de los dispositivos. En el caso de la CPU se cuenta con pocas unidades

de procesamiento pero con mayores capacidades y requiere mucho control y mucha memoria cache.

Por otra parte en la GPU se tiene una mayor cantidad de unidades de procesamiento con poco

control y poco cache; esto es lo que permite la ejecucion de miles de hilos a la vez. La principal

desventaja de CUDA es el marco de ejecucion que solo se limita a dispositivos compatibles de la

marca Nvidia, lo cual limita la popularidad en el uso de esta API. Cabe senalar que un proyecto

Page 37: Esquemas iterativos en paralelo con OpenMP

2.7. OpenMP 21

encabezado por la marca norteamericana Apple llamado OpenCL permite la portabilidad de codigo

que utilice la GPU; mediante la compilacion en tiempo de ejecucion.

Figura 2.6: Arquitectura de hardware CPU versus GPU.

En la figura 2.7 se ilustran las arquitecturas de memoria compartida y distribuida respectiva-

mente; en (A) todos los cores-nucleos del sistema acceden a una misma memoria principal, con

ello todas las unidades de procesamiento pueden acceder a localidades de memoria donde otra uni-

dad esta trabajando. Cabe senalar que la memoria principal es de tipo UMA (Memoria de Acceso

Uniforme) que permite una comunicacion intensiva entre los procesos que son ejecutados en los

diferentes nucleos. En (B) se muestra un sistema con memoria distribuida, los cuales estan carac-

terizados porque cada una de las unidades-nodos de procesamiento tienen su propia memoria tipo

UMA, pero tambien pueden acceder a la memoria de cualquier otro nodo. Es preciso indicar que

es muy costo acceder a la memoria de un nodo desde otro en terminos de tiempo. A esto se debe

la barrera tecnida para no crear secciones de aplicacion que mantenga una comunicacion intensa

siempre y cuando las secciones sean ejecutadas en nodos diferentes. En este tipo de aplicaciones es

muy importante el papel que jugara el sistema de interconexion de nodos puesto que es un enorme

cuello de botella para el acceso a la memoria distribuida, generalmente se utiliza la fibra optica.

Hasta este punto se han mencionado algunas de las principales tendencias y caracterısticas de la

programacion en paralelo. Ademas se indican los motivos por los cuales este paradigma representa

el futuro de la computacion de alto desempeno.

2.7. OpenMP

Como menciona Chapman et al. [11], OpenMP es una Interfaz de Programacion de Aplicaciones

(API) cuyas caracterısticas, se basan en esfuerzos anteriores para facilitar la programacion paralela

Page 38: Esquemas iterativos en paralelo con OpenMP

22 Capıtulo 2. Marco Teorico

Figura 2.7: Tipos de memoria en sistemas.

de memoria compartida. Las siglas MP denotan “multiprocessing” (multiproceso) lo cual es un

sinonimo de programacion paralela de memoria compartida.

OpenMP es un acuerdo alcanzado entre los miembros de la Architecture Review Board (ARB)

para dar un enfoque portatil, facil de usar y eficaz a la programacion paralela de memoria compar-

tida. Al contrario de lo que se puedrıa pensar OpenMP no es un lenguaje de programacion nuevo;

por el contrario es la notacion que se puede agregar a un programa secuencial en Fortran, C o C++,

a las cuales se le denomina directivas o pragmas que son instrucciones pre-procesador.

Una implementacion adecuada de OpenMP en un programa permitira a las aplicaciones benefi-

ciarse de la memoria compartida de las arquitecturas paralelas. En ocasiones con pocas modificacio-

nes al codigo se convierte una aplicacion serial en una paralela; en la practica muchas aplicaciones

tiene un cierto grado de paralelismo que debe ser explotado. Como menciona Chandra et al.[10],

todos los proveedores de computadoras de memoria compartida de alto desempeno soportan la fun-

cionalidad de OpenMP, pero la portabilidad de aplicaciones ha sido casi imposible de alcanzar.

Desde un punto de vista general, una aplicacion serial se convierte en paralelo simplemente

incluyendo una directiva de OpenMP. Estas directivas van desde constructores de hilos hasta la

sincronizacion de los mismos para el acceso a los datos compartidos. Pero un punto muy importante

es que en la directiva se indica el tipo de reparto de las cargas de trabajo.

OpenMP utiliza el modelo fork-join, el cual consiste en que la ejecucion de un programa inicia

con un hilo llamado maestro. Cuando el proceso llega a una directiva se crea una region paralela con

las especificaciones de la misma. La zona paralela se ejecuta sobre un mismo espacio de direcciones

lo cual permite compartir las variables declaradas, pero tambien declarar informacion privada [10,

Page 39: Esquemas iterativos en paralelo con OpenMP

2.7. OpenMP 23

Figura 2.8: Modelo de OpenMP.

11, 31, 34]. Al finalizar la fraccion paralela los hilos esclavos se destruyen y continua la ejecucion

del hilo maestro.

En la figura 2.8 se ilustra la ejecucion de un programa con una region paralela. Cuando el hilo

maestro llega al inicio (etapa fork) de esta zona se crean los hilos esclavos y se declaran la variables

locales de la zona. Posteriormente se realiza el reparto de cargas de trabajo, para que todos los

subprocesos ejecuten el mismo codigo. Despues de finalizar la ejecucion se destruyen las variables

locales de la region paralela y todos los hilos acepto el maestro; es la etapa join. Al finalizar la region

paralela, el proceso continua una ejecucion serial; si mas adelante existiese otra region paralela el

proceso se repite con las condiciones de la nueva directiva.

Soporte de compiladores

La norma industrial OpenMP es soportando por una gran variedad de compiladores; la mayorıa

de ellos con fines comerciales. Algunos ejemplos de ellos son: el compilador Oracle C/C++/Fortran

de Sun Microsystems Inc, el gigante de los procesadores Intel ofrece su compilador para Windows y

Linux con el nombre de Intel C/C++/Fortran, por su parte Microsoft’ brinda el soporte en Visual

C++ en su version comercial entre otros.3 Tambien existe el compilador GNU GCC que brinda

soporte para el API de forma gratuita el cual es propiedad de la comunidad de codigo abierto de

GNU Project. Por tratarse de un estandar nos garantiza que el codigo no debe ser re-escrito cuando

cambiemos el compilador.

El compilador GCC implementa OpenMP en la version 4.2.1 o posteriores. En su version 4.3.2

3La lista completa de compiladores que soporta OpenMP puede ser consultada en el sitio oficialhttp://www.openmp.org.

Page 40: Esquemas iterativos en paralelo con OpenMP

24 Capıtulo 2. Marco Teorico

(Agosto de 2008) comenzo a implementar OpenMP v3.0.4. Las nuevas versiones de GCC las encon-

tramos pre-cargadas en la mayorıa de las distribuciones Linux (recientes) por ello se convierte en el

mas accesible. Por estas cuestiones los resultados que se muestren en la presente tesis corresponde

a codigo compilado con GCC v4.2.1.

Como se menciona en el manual oficial de GNU GCC v4.2.4 [40] el compilador lleva este nombre

por “GNU Compiler Collection” donde se engloba la posibilidad de compilar codigo en lenguajes

C, C++, Objective-C, Objective-C++, Java, Fortran y Ada. GCC cuenta con un gran numero

de optimizacion para aumentar el rendimiento de las aplicaciones conocidas como banderas de

compilacion, las especificaciones tecnicas de estas banderas no son tratadas en el presente trabajo.

Para la evaluacion de algoritmos paralelos se utilizan varios parametros entre los cuales destacan

el La ley de Amdahl, speed-up y el rendimiento computacional. En los temas siguientes se dara una

breve explicacion para llenar el contexto.

2.8. Escalabilidad paralela

La Escalabilidad paralela (Parallel Scalability) es el comportamiento de una aplicacion cuando

un creciente numero de hilos (threads o subprocesos) se utilizan para resolver un problema de tamano

constante. Idealmente, aumentar el numero de hilos de 1 a P dara un aceleramiento paralelo (speed-

up) de p [11]. Como menciona Pacheco [31] se dice que un programa es escalable si al aumentar el

numero de hilos la eficiencia persiste. Para definir este punto, en primer lugar se toma la ecuacion

de la eficiencia E

E =T1

p · Tp=S

p(2.9)

donde T1 es el tiempo de ejecucion con un nucleo, p es el numero de procesadores, Tp representa

el tiempo de ejecucion para p-hilos y S es el speed-up (2.13). En base a lo anterior supongamos que

aumentamos k veces el numero de procesadores con lo cual se tiene

Ekp =T1

kp · Tkp=Skpkp

(2.10)

Con base a (2.9) y (2.10) podemos determinar si un programa es escalable si E = Ekp. Tomando

como idea principal que un programa no puede ser paralizado de forma completa. Idealmente,

4Esta informacion con base la documentacion del sitio web oficial http://gcc.gnu.org/gcc-4.3/

Page 41: Esquemas iterativos en paralelo con OpenMP

2.8. Escalabilidad paralela 25

pensamos que la reduccion en tiempo de ejecucion es proporcional al aumento de hilos-procesadores,

en la practica no es comun que se presente la proporcionalidad, el principal obstaculo es el acceso a

memoria ya que esta se encuentra compartida para todos los hilos, y por ende, se da una competencia

para el uso de la misma. Aunado a ello estas lo costos derivados por la sincronizacion y en general por

el manejo de las regiones paralelas. Existen ocasiones donde aumentar el numero de hilos se torna

contraproducente, se dice que la aplicacion tiene un lımite de hilos, y a partir de aquı, aumentara el

tiempo de ejecucion conforme aumentemos la cantidad de hilos.

Para la evaluacion de la escalabilidad de la aplicacion se utilizan dos metodos: el primero Ley

de Amdahl el cual no pone en un contexto real de la escalabilidad teorica que se puede obtener.

En segundo tenemos el speed-up el cual mide las veces que es mas rapido un algoritmo paralelo con

respecto al serial. Mientras tanto el desempeno computacional mide la cantidad de operaciones por

segundo de un programa. En los siguientes temas se desarrolla cada uno de ellos.

2.8.1. Ley de Amdahl

Como menciona Pacheco [31] fue desarrollada por Gene Amdahl en la decada de 1960. Esta ley

indica que un programa serial solo se puede paralelizar una fraccion; ello limitara muy significati-

vamente el speed-up; independientemente del numero de unidades de procesamiento.

La ley plantea la carencia de poder paralelizar un algoritmo serial de forma completa. Solo

podemos hacer paralelo una fraccion del codigo. Mientras mas grande sea la fraccion paralela, el

speed-up sera mayor para un numero creciente de procesadores; sin embargo, no siempre sera posi-

tivo aumentar la cantidad de hilos.

En la figura 2.9 se ilustra la ejecucion de un fragmento de programa con una seccion en paralelo.

En ella se describe lo siguiente: en un principio el hilo maestro inicia la ejecucion y crea la region

paralela. En la region paralela los hilos esclavos ejecutan el proceso, al finalizar se destruyen los

hilos. Finalmente el hilo maestro continua con la ejecucion.

La ley de Amdahl nos permite calcular el speed-up maximo Sp como

Sp =1

(1− F ) + Fp

(2.11)

donde F es la fraccion de tiempo secuencial y p el numero de procesadores, entonces (1 − F )

representa la fraccion serial del programa.

Page 42: Esquemas iterativos en paralelo con OpenMP

26 Capıtulo 2. Marco Teorico

Figura 2.9: Modelo de ejecucion de programas paralelos.

Tomando un programa que se ejecuta como el de la figura 2.9 donde la region paralela es

F = 80 % del total de calculo. Con base a (2.11) se calcula el speed-up maximo (Sp) para 2

procesadores (n = 2) como sigue

Sp =1

(1− 0.8) + 0.82

=1

0.2 + 0.4= 1.66x

Ahora supongamos que otro codigo es altamente paralelizable F = 95 %, a continuacion se

calcula el nuevo Sp para este nuevo codigo

Sp =1

(1− 0.95) + 0.952

=1

0.05 + 0.475= 1.90x

Si calculamos el speed-up maximo para 4, 5, 8, 16, 32 procesadores para los dos ejemplos

anteriores se obtiene la grafica de la figura 2.10.

En la figura 2.10 se ilustra el speed-up de dos programas con 95 % y 80 % de paralelismo y son

comparados con el speed-up ideal. Para un numero reducido de procesadores ambos estan cercanos

al teorico; pero conforme el numero de procesadores aumentan el speed-up de los dos programas

empeora muy drasticamente. El speed-up que se puede esperar de un programa 95 % paralelo para

Page 43: Esquemas iterativos en paralelo con OpenMP

2.8. Escalabilidad paralela 27

5 10 15 20 25 30

5

10

15

20

25

30

Numero de procesadores

speed−

up

Ideal

95%

80%

Figura 2.10: Speed-up con Ley de Amdahl.

mas de 16 procesadores es muy pobre. Para otro 80 % paralelo practicamente su lımite son 16

procesadores.

Con el paso del tiempo la Ley de Amdahl se volvio obsoleta y fue Gustafson quien la revalido a

finales de la decada de 1980[20]. La version moderna de la ecuacion de esta ley en (2.12)

Smax =1

(1− F ) + FS

(2.12)

donde lo unico que cambia es S que representa un speed-up. Cabe senalar que conforme S se

aproxime a infinito (S →∞) se redondea el denominador de (2.12) quedando 1/(1− F ).

2.8.2. Incremento de velocidad (speed-up)

El incremento de velocidad (speed-up), es la proporcion del tiempo de reloj para la ejecucion

del programa en un hilo y el tiempo de reloj para la ejecucion del mismo programa en varios hilos.

Teoricamente, debe ejecutar un programa en P -hilos, P veces tan rapido como se ejecute en un

hilo[11]. En la literatura existente cuando se refiere a este tema se utiliza el termino speed-up, este

documento no sera la excepcion.

Page 44: Esquemas iterativos en paralelo con OpenMP

28 Capıtulo 2. Marco Teorico

Con base a lo ya mencionado se define a speed-up como sigue

S =T1

Tp(2.13)

donde S representa el speed-up, T1 el tiempo de ejecucion para un procesador y Tp el tiempo que

tarda la misma aplicacion en P -procesadores. La medida del speed-up es adimensional. Por ejemplo,

si una fraccion de codigo seriado (T1) dura 10 segundos, despues cuando ese codigo se ejecuta en

forma paralela con dos procesadores (T2) dura 5.5 segundos. El speed-up que se tiene es el siguiente

S =10

5.5= 1.8x

Ahora si aumentamos el numero de procesadores a cuatro y tiene un tiempo de ejecucion (T4)

de 3 segundos, el speed-up entonces sera

S =10

3= 3.3x

Con los ejemplos anteriores se representa el proceso para determinar la aceleracion de ejecuciones

paralelas. En ninguno de los casos anteriores se llega al speed-up teorico 2 y 4 respectivamente. En

temas siguientes se indica el motivo por el cual no se llega a ello.

Cuando se programa en paralelo siempre se busca alcanzar la proporcionalidad entre el aumento

de la velocidad respecto al numero de hilos, no siempre se alcanza dicha meta debido a los proble-

mas de acceso a memoria, los cuales depende del diseno de cada computadora. Es por ello que es

conveniente cuidar la implementacion del codigo a fin de obtener una mayor velocidad cuando se

cambie el numero de hilos.

2.8.3. Desempeno computacional

El desempeno o rendimiento computacional (en la literatura tambien se le conoce como perfor-

mance) se mide por las operaciones en punto flotante por segundo. Como menciona Null et al.[29]

la metrica para el rendimiento es el FLOPS (floating-point operations per second, operaciones en

punto flotante por segundo). Para calcular el desempeno se divide el numero de operaciones n entre

Page 45: Esquemas iterativos en paralelo con OpenMP

2.8. Escalabilidad paralela 29

el tiempo empleado t.

FLOPS =n

t(2.14)

Con las nuevas prestaciones que ofrecen las computadoras la cantidad de FLOPS es algo difıcil

de manejar. Por ello se utilizan unidades de medida de FLOPS que se indican en la tabla 2.1.

Tabla 2.1: Unidades de medida de FLOPS

Nombre de la unidad Valor

KiloFlop 103

MegaFlop 106

GigaFlop 109

TeraFlop 1012

PetaFlop 1015

ExaFlop 1018

ZetaFlop 1021

YottaFlop 1024

Para obtener directamente una de las unidades de la tabla 2.1 de (2.14) basta con hacer lo

siguiente

K FLOPS =n

t× 10e(2.15)

donde e corresponde al exponente de la unidad, por ejemplo e = 9 si calculamos GigaFlops. Ello se

muestra a continuacion

GigaFlops =n

t× 109

FLOPS es una unidad generalizada para mostrar resultados de rendimiento. En la presente

tesis se muestran todos los resultados de rendimiento utilizando esta unidad de medida. Para los

fines de la presente tesis unicamente se utilizan para evaluar los algoritmos paralelos el desempeno

computacional y el speed-up.

Con los temas que se han tratado durante el presente capıtulo se establece un fundamento

teorico lo cual se puede resumir. Los metodos numericos estas influenciados por las computadoras,

lo cual requiere de analisis y modelacion matematica que permitan adaptar el esquema al tipo de

problema en cuestion. Las nuevas generaciones de computadoras multinucleo permiten la ejecucion

de aplicaciones paralelas; ello conlleva que se disenen nuevos algoritmos que puedan explotar estas

nuevas caracterıticas. Estos nuevos algoritmos deben ser eficientes para ellos son evaluados a fin de

Page 46: Esquemas iterativos en paralelo con OpenMP

30 Capıtulo 2. Marco Teorico

determinar su desempeno computacional ası como su speed-up. A diferencia de los numero reales

idealmente conocidos, en las computadoras la cantidad de numeros es limitada y su distribucion

en la lınea recta no es uniforme. Debido al metodo numerico elegido y a la representacion de los

numeros en la computadora nace el error numerico en los problemas de analisis numerico, ademas

de las propias contemplaciones hacia el resultado por parte quien implementa el metodo.

Page 47: Esquemas iterativos en paralelo con OpenMP

Capıtulo 3Producto matriz-vector Ax

La multiplicacion de una matriz y un vector, es una operacion simple que resuelve un problema

basico, pero importante [11]. La cual se presenta de forma frecuente en esquemas iterativos como lo

son el metodo de Jacobi y el de Gauss-Seidel, por mencionar algunos. Estos metodos son tratados

en capıtulos siguientes.

Durante este capıtulo se describen formas distintas para resolver A·x utilizando la computadora;

senalando los pro y contras de cada una de ellas. Para ello se exhibe el rendimiento en speed-up y

Mflops1 con el fin de mostrar numericamente cual de ellos es el mejor procedimiento para codificarla.

En la primera seccion se definen conceptos basicos para comprender el problema. Como se realiza

el producto entre una matriz y un vector, cuales son la normas que deben cumplirse para que se

pueda realizar.

En el segundo apartado se da una breve introduccion a un tecnica de optimizacion de ciclos

conocida como Loop unrolling, la cual es utilizada para optimizar el producto de una matriz por

un vector.

Se estudia el calculo del residual en la seccion tres, lo cual resulta ser un tema interesante, es

utilizado como condicion de paro en metodos iterativos. El residual es la diferencia que existe entre

la solucion exacta y una aproximada.

La implementacion canonica se realiza en la cuarta parte del capıtulo.

En las secciones cinco y seis se realizan distintos procedimientos de optimizacion, para mejorar

1flops (floating-point operations per second, operaciones en punto flotante por segundo) es una unidad de medidapara el desempeno de una aplicacion. Mflops denota que es un millon de flops (106).

31

Page 48: Esquemas iterativos en paralelo con OpenMP

32 Capıtulo 3. Producto matriz-vector Ax

el desempeno de la aplicacion. En primer lugar, es utilizada la tecnica de Loop unrolling para

optimizar el bucle. En segunda instancia, se optimiza a nivel de datos con la Tecnologıa SIMD de

Intel R©. Al final de esta quinta seccion se combinan ambas (Loop unrolling y SIMD) para exponer

el resultado que se presenta al combinarlas.

En la actualidad la gran mayorıa de las computadoras disponibles en el mercado, tienen mas de

un procesador. En computo es importante explotar todos los recursos de manera eficiente. Lo que

nos lleva a realizar aplicaciones que aprovechen el multinucleo, es decir, puedan ser ejecutadas en

varios procesadores de forma simultanea, esta tarea se lleva a cabo en el septimo apartado.

Por ultimo se muestran los resultados obtenidos tras las optimizaciones realizadas. Ello con la

finalidad de establecer la mejor opcion para implementarla en los metodos iterativos de los capıtulos

siguientes.

3.1. Concepto

El producto de una matriz y un vector es un operacion simple que resuelve un problema basico

pero importante [11]. En esta seccion se presenta la multiplicacion de una matriz por un vector

desde un punto de vista matematico.

Antes de adentrarse es preciso definir lo que son las matrices y los vectores. Un vector no es

mas que un conjunto ordenado de numeros uniformemente espaciados, en el area de informatica se

le conoce como arreglo unidimensional. Existen vectores de tipo columna y renglon dependiendo de

la orientacion del mismo. A continuacion se representa un vector de orden n.

X = [x1, x2, . . . , xn]T (3.1)

En la ecuacion (3.1) se describe un vector renglon, tomando ese ejemplo para convertirlo a uno

de tipo columna solo resolvemos la transpuesta del mismo. A continuacion se ilustra lo mencionado.

X =

x1

x2

...

xn

(3.2)

Page 49: Esquemas iterativos en paralelo con OpenMP

3.1. Concepto 33

Una matriz es un arreglo rectangular de numeros con m filas y n columnas, o dicho de otra forma

una matriz es un arreglo bidimensional [28]. A continuacion se muestra la representacion general de

cualquier matriz.

A =

a1,1 a1,2 · · · a1,n

a2,1 a2,2 · · · a2,n

......

......

am,1 am,2 · · · am,n

(3.3)

En (3.3) se describe la forma general para representar una matriz de m-renglones y n-columnas,

decimos que es una matriz de m × n. En este documento unicamente se abordaran matrices cuyo

numero de renglones es equivalente al de columnas. A este tipo de arreglo bidimensional se le conoce

como matriz cuadrada, a consecuencia cuando se mencione una matriz se supondra que es cuadrada;

mientras no se indique lo contrario.

Para llevar a cabo la multiplicacion de una matriz por un vector se requiere cumplir con dos

condiciones. La primera es que el vector tenga la forma de (3.2), es decir, sea un vector de tipo

columna o vertical. Tomando a (3.3) y (3.2), el orden del vector (numero de renglones) debe ser

exactamente igual al numero de columnas de la matriz; esta es la segunda condicion. Por ende no

puede realizarse la siguiente operacion.

c = xA (3.4)

Cuando se cumplen las condiciones se puede realizar la operacion. Como resultado de multiplicar

la matriz A por el vector x se obtiene el vector c. La operacion se describe a continuacion,

Ax = c (3.5)

Si se desglosa (3.5), encontramos el siguiente procedimiento con base en (3.2) y (3.3). Donde se

expone que cada renglon de la matriz se multiplica por el vector.

a1,1 a1,2 · · · a1,n

a2,1 a2,2 · · · a2,n

......

......

am,1 am,2 · · · am,n

x1

x2

...

xn

=

a1,1x1 + a1,2x2 + · · ·+ a1,nxn

a2,1x2 + a1,2x2 + · · ·+ a2,nxn...

am,1xn + am,2x2 + · · ·+ am,nxn

(3.6)

Page 50: Esquemas iterativos en paralelo con OpenMP

34 Capıtulo 3. Producto matriz-vector Ax

A continuacion se muestra una forma compacta de (3.6). En este documento sera utilizada esta

formula (3.7) cuando se haga referencia a la ecuacion de la mutiplicacion de una matriz por un

vector, mientras la matriz no sea rectangular.

ci =n∑j=1

aijxj i = 1, 2, . . . , n (3.7)

Como se observa en (3.6) y (3.7) resolver la operacion en cuestion resulta trivial. Sin embargo,

el proceso es demandante en tiempo de calculo. La demanda de calculo aumenta conforme la matriz

A se vuelve mas densa, es decir, el orden de la misma crece. Con base a (3.7) se realiza el algoritmo

que corresponde con el tema tratado lo cual permitira crear la funcion para la misma ecuacion.

Algoritmo 3.1 Multiplicacion matriz-vector

Esta definido por los siguientes seis pasos:

1. Hacer i = 0

2. Si (i < m)

Verdadero: hacer ci = 0,j = 0, posteriormente pasar al paso 3.

Falso: ir al paso 6

3. Hacer ci = ci +Aij · xj

4. Hacer j = j + 1

5. Si (j < n)

Verdadero: regresar al paso 3.

Falso: hacer i = i+ 1, posteriormente regresar al paso 2.

6. Parar.

En esta seccion se definieron las bases para resolver la operacion c = Ax. Lo cual es indispensable

para escribir funciones en codigo C que resuelvan la operacion en cuestion. Esta actividad se llevara a

cabo en secciones posteriores de este capıtulo.

3.2. Loop unrolling

En esta seccion se define una tecnica de optimizacion de ciclos principalmente de tipo for. La

tecnica llamada Loop Unroll o Loop unrolling (desdoble de ciclo). Esta tecnica sirve para optimizar

Page 51: Esquemas iterativos en paralelo con OpenMP

3.2. Loop unrolling 35

el codigo de programas para reducir el tiempo de ejecucion de la aplicacion, los cual incrementa el

desempeno computacional de la misma.

Como menciona Page [32] esta tecnica tiene como objetivo eliminar la sobrecarga asociada con

la operacion de un ciclo determinado. Cuando el numero de iteraciones es conocido se pueden listar

todos lo valores posibles para la variable de induccion2. Para ejemplificar, se tiene el siguiente ciclo:

for(i = 0; i < n; i++)

c[i] += a[i] * b[i];

Para ejemplificar tomemos n = 4 lo cual permite desdoblar el ciclo de forma completa quedando

como sigue

c[0] = a[0]× b[0]

c[1] = a[1]× b[1]

c[2] = a[2]× b[2]

c[3] = a[3]× b[3]

En este caso en particular la variable de induccion esta definida en el rango 0 ≤ i < n, al escribir

un codigo con las nuevas modificaciones se obtiene una aplicacion que realiza la misma tarea que

el ciclo original (para este caso en particular), pero ahora no hay gastos asociados al ciclo. En

consecuencia el rendimiento aumenta.

Cuando el valor de n es pequeno el ciclo puede ser desdoblado en su totalidad. Sin embargo,

conforme n crece llevar a cabo un desdoble completo del bucle; sera una tarea practicamente impo-

sible de realizar. Aunado a ello, el codigo resultante es tosco. Una forma ingeniosa para resolverlo

es hacer un desdoble por bloques, cada uno tan grande como se desee. Esto con el fin de reducir

el numero de iteraciones ademas de exponer las operaciones que se pueden realizar en paralelo. A

continuacion se desarrolla un codigo general aplicable a cualquier Unroll.

r = n % k;

for(i = 0; i < n-r; i+=k)

c[i] += x[i]*y[i] + x[i+1]*y[i+1] + ... + x[i+k-1]*y[i+k-1];

for(i = n-r; i < n; i++)

c[i] += x[i]*y[i];

En el codigo anterior k representa el factor de unroll que se aplica; n el orden de los vectores y

r es el residual por si n no es divisible por k.

2La variable de induccion es aquella que controla el funcionamiento del ciclo, en la mayorıa de los casos se representacon i.

Page 52: Esquemas iterativos en paralelo con OpenMP

36 Capıtulo 3. Producto matriz-vector Ax

Como menciona Page [32] al desarrollar un desdoble parcial queda claro que el numero de

operaciones dentro del cuerpo del ciclo se puede llevar a cabo de forma paralela.

La tecnica de Loop Unroll permite reducir la carga en el ciclo utilizando la lınea de cache del

procesador utilizando los valores que recientemente han sido cargados a la memoria caliente3. Ello

hace que sea muy utilizada gracias a la fidelidad que presenta en una implementacion. Aun cuando

la implementacion es por demas sencilla, la eleccion de una regla para que esta tecnica funcione

siempre no es una tarea sencilla. Este problema esta ligado directamente a las caracterısticas del

procesador, los procesadores no-moviles ejecutan mejor las sobre-cargas en los ciclos que los que no

lo son.

3.3. Calculo del residual

En esta seccion se aborda el tema del calculo del residual, como un metodo para medir la

convergencia de los esquemas iterativos que se estudian en capıtulos posteriores. Este procedimiento

mide el error entre la k-esima iteracion con respecto a la solucion exacta del sistema lineal de

ecuaciones. Uno de los principales usos del calculo del residual es durante la medicion de error en

los metodos iterativos de proyeccion sobre subespacios de tipo Krylov[24]. Se realizara una funcion

que realice este procedimiento, la cual sera utilizada en los siguientes capıtulos.

El calculo del residual (r) se obtiene de sustraer el producto de A y x∗ a b como se muestra a

continuacion

r = b−Ax∗ (3.8)

donde, x∗ = una aproximacion a la solucion exacta de x, b, r, x∗ ∈ RN y, A ∈ RN×N

Para ello los vectores (b, r, x∗) tienen la forma del vector z la cual se expresa a continuacion,

z = (z1, z2, . . . , zn)T

Si x∗ = x⇒ r = 0 Ahora si x ≈ x∗ ⇒ r 6= ~0

Tomando en cuenta que la solucion exacta x es la suma de la aproximacion mas el error (x =

x∗ + e), con lo que deducimos que

x = x∗ − e3La memoria caliente corresponde a un tipo de almacenamiento conocido como NUMA(Non-uniform memory

access, memorıa de acceso no uniforme) o memoria caliente es como se le conoce a la memoria cache del procesadordebido a que es una memoria de gran velocidad.

Page 53: Esquemas iterativos en paralelo con OpenMP

3.3. Calculo del residual 37

Al sustituir x∗ en (3.8) tenemos

r = b−A(x∗ − e)

con ello se intuye que el residual es equivalente al error entre la solucion exacta y una aproximada

r ≈ e

Observe que el residual r es un vector de orden n, es decir, r ∈ Rn de la forma

r = (r1, r2, r3, . . . , rn)T

A continuacion el calculo del residual se traduce a codigo C, en la figura (3.1) se ilustra esta

tarea ya realizada.

Implementacion Calculo del Residual

double calcularResidual(float **A, float *dx, float *b, int n)

double *residual,normResidual;

int i,j;

double rowDot;

residual = make_dvector(n);

for(i = 0; i < n; i++)

rowDot = 0.0;

for(j = 0; j < n; j++)

rowDot += A[i][j] * dx[j];

residual[i] = b[i] - rowDot;

normResidual = normInf(residual,n);

free_svector(residual);

return normResidual;

Figura 3.1: Calculo del residual en C.

En la funcion descrita con anterioridad, se utilizan tres metodos que se explican a continua-

cion. Cuando se llama a la funcion make dvector(n) se reserva la memoria para un vector, en este

caso residual. La segunda funcion normInf(residual,n) calcula la norma infinita de un vector con

Page 54: Esquemas iterativos en paralelo con OpenMP

38 Capıtulo 3. Producto matriz-vector Ax

orden n. En el ultimo caso free dvector(residual) se libera la memoria previamente reservada con

make dvector(n).

En temas posteriores, cuando se indique el calculo del residual (dentro de lıneas de codigo), se

hara alucion a esta funcion cuando no se indique lo contrario.

El residual es un metodo que mide la diferencia entre una solucion exacta y una aproximada.

Se utiliza para determinar la convergencia en esquemas iterativos como son los metodos de Jacobi

y Gauss-Seidel. Para reducir el error derivado de la gran cantidad de operaciones en los metodos

directos se utilizan tecnicas iterativas de correccion del error del residual.

La funcion que fue implementada puede ser optimizada con temas tratados en secciones poste-

riores de este capıtulo, a fin de incrementar el desempeno computacional de la misma. Cabe senalar

que esta funcion no sera optimizada llegando a esos temas porque no es la finalidad del presente

documento.

3.4. Codificacion

En esta seccion se realiza una primera implementacion en codigo C, para la ecuacion que corres-

ponde a la multiplicacion de una matriz por un vector, es decir, la ecuacion (3.7). En esta primera

funcion secuencial no se utilizo ninguna de la optimizaciones. En temas posteriores se realizaran

mejoras que impacten positivamente en el rendimiento.

Como se ha mencionado con anterioridad, el producto de una matriz por un vector es una

operacion muy sencilla. Traducirla a un lenguaje para computadora es tambien una tarea muy

simple. La fraccion de codigo de la figura 3.2 es un primer resultado tras realizar la tarea en

cuestion.Implementacion Canonica de Ax

for(i = 0; i < n; i++)

c[i] = 0.0;

for(j = 0; j < n; j++)

c[i] = A[i][j] * x[j];

Figura 3.2: Implementacion canonica de Ax.

Page 55: Esquemas iterativos en paralelo con OpenMP

3.5. Incremento del desempeno 39

Como puede observarse el codigo de la figura 3.2 esta disenado para matrices cuadradas. El

codigo es por demas sencillo y no existe nada extrano. Es preciso definir que en temas siguientes

cuando se mencione una implementacion canonica del producto de una matriz po un vector, nos

referiremos a esta fraccion de programa alojado dentro de una funcion. En pocas palabras, esta

primera implementacion corresponde a una version compacta de una funcion canonica que resuelve

la multiplicacion de una matriz por un vector.

La implementacion canonica permite tener un primer acercamiento en la realizacion de una

aplicacion; la cual pueda ser ejecutada en forma paralela.

En esta seccion se realizo una primera implementacion, la canonica. Esta funcion no cumple

con los objetivos planteados; es decir, no presenta un buen desempleno computacional. Ademas

no es posible ejecutar esa aplicacion en varios procesadores de manera simultanea. Tomando esto

dos puntos, y los que puedan surgir, definimos que la implementacion canonica no es una opcion,

en terminos de computo de alto desempeno. En las siguientes secciones se tratan cada uno de los

puntos ya mencionados, a fin de cumplir con cada uno de ellos.

3.5. Incremento del desempeno

Muchos programas pasan gran parte de su tiempo de ejecucion en bucles; en este caso es mediante

ciclos que se accede a los elementos de la matriz; con una reorganizacion adecuada de los bucles se

puede explotar el cache de procesador donde se guardan mas de un elemento que se va a utilizar en

la siguiente operacion. Los elementos que se encuentran en la lınea de cache en muchos casos pueden

ser procesados a la vez mediante una pila de operaciones. Esto puede mejorar el rendimiento de un

programa4. En esta seccion se optimiza la version canonica de la mutiplicacion Ax con la tecnica

de Loop unrolling.

Para mejorar el rendimiento de la aplicacion es preciso realizar un analisis detallado de la forma

matematica, se realiza una descomposicion a fin de buscar diferentes formas de programar el pro-

blema para definir las caracterısticas y determinar cual se adapta mejor a nuestros requerimientos.

Para ello es preciso desglosar y estudiar un gran numero de posibles soluciones, ası como analizarlas;

para determinar aquella que permita maximizar el desempeno sin incrementar significativamente el

4Las modificaciones en codigo pueden ser aplicadas si y solo si no cambian el correcto funcionamiento de laaplicacion.

Page 56: Esquemas iterativos en paralelo con OpenMP

40 Capıtulo 3. Producto matriz-vector Ax

error numerico para la solucion buscada. Recordemos la ecuacion,

ci =n∑j=1

aijxj i = 1, 2, . . . , n (3.9)

En mas de una ocasion cuando se realiza una tarea se encuentra que existen varios caminos para

realizarla; cada uno de esos caminos con distancias y obstaculos distintos. Nos encontramos justo en

uno de esos casos, para elegir el camino primero estudiaremos cada uno de ellos. Existen practicas

utilizadas para la optimizacion ciclos con un numero significativo de iteraciones, generalmente en

bucles for’s. Las tecnicas tienen el proposito de disminuir el tiempo de ejecucion del bucle; consisten

en disminuir la cantidad de iteraciones haciendo un incremento mayor a la unidad en la variable

que controla el ciclo. Una de esas practicas es la llamada Unroll Loops.

Como menciona Chapman et al.[11] el Unroll a un bucle es una practica poderosa para reducir

efectivamente los gastos de ejecucion. Puede ayudar a mejorar la utilizacion de la lınea de cache con

la reutilizacion de datos. Como es sabido el compilador no es capaz de determinar las dependencias

de operaciones ni tampoco lo que respecta al acceso en los elementos dentro de ciclos; por lo que el

desarrollador suele hacer un mejor trabajo en la optimizacion de bucles.

Antes de resolver el producto c = Ax, se plantea lo siguiente,

ci = aix (3.10)

donde c y x son vectores verticales de orden de n-elementos, y ai es el i-esimo vector horizontal de

la matriz A.

Partiendo de (3.10) encontramos diferentes formas de resolverlo, a continuacion se listan las

variantes a tomar en cuenta, para esto todas utilizan la tecnica de unroll.

1. s =n∑j=1

xjyj + xj+1yj+1 ∆ j = 2

2. s =n∑j=1

xiyj + xj+1yj+1 + xj+2yj+2 + xj+3yj+3 ∆ j = 4

3. s =n/2∑j=1

xjyj + xj+1yj+1 +n∑

j=n/2

xjyj + xj+1yj+1 ∆ j = 2

4. s =n/4∑j=1

xjyj + xj+1yj+1 +n/2∑j=n/4

xjyj + xj+1yj+1 +3n/4∑j=n/2

xjyj + xj+1yj+1

Page 57: Esquemas iterativos en paralelo con OpenMP

3.5. Incremento del desempeno 41

+n∑

j=3n/4

xjyj + xj+1yj+1 ∆ j = 2

5. s =n∑j=1

xiyj + xj+1yj+1 + xj+2yj+2 + xj+3yj+3 + xj+4yj+4 ∆ j = 5

6. s =n∑j=1

xiyj + xj+1yj+1 + xj+2yj+2 + xj+3yj+3 + xj+4yj+4 +xj+5yj+5 ∆ j = 6

7. s =n∑j=1

xiyj + xj+1yj+1 + xj+2yj+2 + xj+3yj+3 + xj+4yj+4 + xj+5yj+5 + xj+6yj+6

+xj+7yj+7 ∆ j = 8

8. s =n∑j=1

xiyj + xj+1yj+1 + xj+2yj+2 + xj+3yj+3 + xj+4yj+4 + xj+5yj+5 + xj+6yj+6

+xj+7yj+7 + xj+8yj+8 + xj+9yj+9 + xj+10yj+10 + xj+11yj+11 ∆ j = 12

Para comprender y tener una idea de como utilizar el unroll, en primera instancia se estudiaran

y compararan las primeras cinco variantes (1-5), en segunda instancia se analiza el resto. En algunos

de los casos anteriores podemos realizar dos implementaciones lo cual se expresara en su momento.

A continuacion se hara la codificacion de cada una de las opciones para conocer sus caracterısticas.

En la primera implementacion (figura 3.3) corresponde a ese mismo orden de la lista de opciones

enlistadas anteriormente. Como se puede observar el numero de iteraciones se reduce a la mitad, lo

cual teoricamente hace pensar que el tiempo de ejecucion va a reducirse a la mitad de tiempo. Para

este caso en particular corresponde a un Unroll-2 donde se guardara el resultado obtenido a una

variable. Esta al igual del resto de las fracciones de codigo que corresponda con la lista de opciones,

representa la solucion de la multiplicacion de dos vectores.

Codigo Opcion 1

for(i = 0; i < n; i+=2)

suma += (x[i]* y[i]) + (x[i+1] * y[i+1]);

Figura 3.3: Tecnica Loop Unrroll con factor 2.

A continuacion hacemos la codificacion de la segunda opcion (figura 3.4), que corresponde a un

Unroll-4. En esta ocasion la cantidad de iteraciones se reduce a una cuarta parte. Al igual que en

el caso anterior el resultado es guardado dentro de una variable.

Page 58: Esquemas iterativos en paralelo con OpenMP

42 Capıtulo 3. Producto matriz-vector Ax

Codigo Opcion 2

for(j = 0; j < n; j+=4)

suma += x[j]*y[j] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3];

Figura 3.4: Tecnica Loop Unroll con factor 4.

El siguiente codigo (figura 3.5) representa una forma distinta de programar la primera opcion

de la figura 3.3, en esta ocasion, primero haciendo las operaciones con los ındices pares del vector

y posteriormente con los impares.

Codigo Opcion 1a

for(j = 0; j < n; j+=2) suma += x[j]*y[j];

for(j = 1; j < n; j+=2) suma += x[j]*y[j];

Figura 3.5: Tecnica Loop Unroll con factor 2, dos ciclos for.

Como vemos en el codigo de la figura 3.6, se puede codificar de distintas formas un mismo

problema. En las implementaciones anteriores solo utilizamos una variable para almacenar el resul-

tado, de la operacion en cuestion, en las proximas codificaciones se hara uso de dos o mas variables

para acumular el resultado mientras se realizan las operaciones. La siguiente fraccion de programa

corresponde al mismo codigo anterior pero ahora haciendo uso de dos variables.

Codigo Opcion 3

for(j = 0; j < n; j +=2) s1 += (x[j]*y[j]);

for(j = 1; j < n; j +=2) s2 += (x[j]*y[j]);

suma = s1 + s2;

Figura 3.6: Tecnica Loop Unroll con factor 2, dos variables.

La cuarta opcion (figura 3.7) representa una forma mas sofisticada para llevar a cabo la solucion

del problema ya que partimos la operacion principal en dos sub-operaciones, las cuales a su vez

presentan un incremento en j de dos (∆j = 2) lo cual reduce el numero de iteraciones a la mitad

e implementa dos variables, temporales, para llevar a cabo las operaciones. Ello ante los ojos del

unroll, corresponde al Unroll-2 dividido en dos mitades.

Page 59: Esquemas iterativos en paralelo con OpenMP

3.5. Incremento del desempeno 43

Codigo Opcion 4

for(j = 0; j < n/2; j += 2) s1 += x[j]*y[j] + x[j+1]*y[j+1];

for(j = n/2; j < n; j += 2) s2 += x[j]*y[j] + x[j+1]*y[j+1];

suma = s1 + s2;

Figura 3.7: Tecnica Loop Unroll con factor 2, dos ciclos for y dos variables.

La siguiente implementacion (figura 3.8), de la quinta opcion, sigue la nomenclatura a la anterior

y solamente difiere en la cantidad de partes, que para este caso son cuatro, y por ende el numero

de variables temporales aumenta a igual numero, a continuacion se muestra lo que con anterioridad

se ha mencionado.

Codigo Opcion 5

for(j = 0; j < n/4; j+=2) s1 += x[j]*y[j] + x[j+1]*y[j+1];

for(j = n/4; j > n/2; j+=2) s2 += x[j]*y[j] + x[j+1]*y[j+1];

for(j = n/2; j > 3*n/4; j+=2) s3 += x[j]*y[j] + x[j+1]*y[j+1];

for(j = 3*n/4; j > n; j+=2) s4 += x[j]*y[j] + x[j+1]*y[j+1];

suma = s1 + s2 + s3 + s4;

Figura 3.8: Tecnica Loop Unroll con factor 2, cuatros ciclos for cuatro variables.

Todas la implementaciones anteriores tienen el fin de encontrar las ventajas y desventajas que

resulta despues de desglosar el problema de distintas formas. Para cada una de las codificaciones

los resultados arrojados son distintos, aunque en teorıa el resultado es una constante; en la practica

el resultado difiere en cada una de las aplicaciones.

Para hacer mas evidente los resultados es necesario que los vectores x y y sean de tipo float y

llenados con numero reales con signo, intercalados de preferencia.

En muchos lugares escuchamos que los nuevos disenos se deben adaptar a la necesidades, es

por ello que en todo momento nos referimos como opciones a todas las implementaciones; en esta

ocasion unicamente se someteran a pruebas de exactitud y de velocidad de ejecucion.

En la tabla 3.1 podemos observar los resultados de exactitud de las funciones cuando se someten

con vectores de longitud n y con diez mil iteraciones para cada valor de n. Los resultados son

muy congruentes; para valores reducidos de n es mas provechoso realizarlo con la version canonica,

Page 60: Esquemas iterativos en paralelo con OpenMP

44 Capıtulo 3. Producto matriz-vector Ax

en caso contrario cuando n es grande dividir el ciclo en varias partes sera mejor; en terminos de

exactitud.

Tabla 3.1: Producto de dos vectores: resultados de prueba de exactitud, observamos las veces quees mas exacta, mostrada en porcentaje ( %), cada funcion durante las iteraciones para cada valorde n.

Resultados de Prueba de Exactitud

Funcion y Exactitud ( %)N Canonica 1 1a 2 3 4 5

16 49.90 26.26 10.63 1.27 7.10 3.50 1.3432 39.38 29.04 11.50 1.86 10.74 5.59 1.8964 29.20 28.17 12.00 2.99 15.35 8.52 3.77

128 22.01 23.80 12.70 4.45 18.06 12.84 6.14256 17.42 28.17 10.73 6.01 19.26 16.10 9.76512 13.44 20.72 10.01 7.46 18.62 19.22 13.52

1024 11.26 17.73 8.63 9.60 18.36 19.28 17.832048 9.68 15.04 9.08 10.18 17.30 20.76 19.534096 9.07 13.47 8.26 11.50 17.16 19.33 22.308192 8.30 12.38 7.95 12.45 16.40 20.56 22.78

16384 8.50 11.56 7.79 12.91 15.50 19.93 24.2232768 7.67 10.55 7.98 13.57 15.06 19.62 25.55

Con base a lo que observamos en la tabla 3.1 decimos que si queremos cuidar la exactitud de la

operacion, necesitamos desdoblar las operaciones en k-partes utilizando una variable distinta para

cada parte, donde k dependera del orden de los vectores (x, y). Ello por motivo que en valores de

n pequeno es contraproducente, pero donde n tenga un valor suficientemente grande, la exactitud

mejorara conforme se implementen mas desdobles.

Con base a estos resultados podemos inferir que es de vital importancia definir el grado de

exactitud que buscamos; lo cual se obtiene al aumentar la cantidad de desdobles. Por consecuencia

conforme aumentemos la cantidad de partes, el codigo fuente crecera y se convertira en tosco y

dificultara el entendimiento del mismo.

Una buena pregunta que surge con los resultados obtenidos es la siguiente: ¿Por que los resulta-

dos son distintos para cada funcion?, la respuesta es muy simple, por problemas de redondeo, como

menciona Chapra et al.[12], estas diferencias son originadas porque las computadoras utilizan un

determinado numero de cifras significativas para los calculos. Es por ello que algunas operaciones

Page 61: Esquemas iterativos en paralelo con OpenMP

3.5. Incremento del desempeno 45

Tabla 3.2: Producto de dos vectores: resultados de prueba de velocidad, observamos la tasa deexactitud de cada funcion con respecto al numero de iteraciones (10,000).

Resultados de Prueba de Velocidad

Funcion y Veces mas Veloz ( %)N Cannica 1 1a 2 3 4 5

16 84.94 15.06 0 0 0 0 032 76.55 23.45 0 0 0 0 064 60.35 39.60 0.04 0 0.01 0 0

128 26.51 36.80 19.62 0 16.05 1.01 0.01256 36.30 41.90 9.08 12.70 0.02 0 0512 16.97 31.94 2.81 34.12 0 12.84 1.32

1024 0 11.26 0 79.95 0 3.08 5.712048 0 0.82 0 87.74 0 6.52 4.924096 0.01 0.04 0 99.78 0 0.05 0.128192 0 0.08 0.01 99.72 0 0.03 0.16

16384 0 0.18 0 99.45 0 0.21 0.1632768 0 0.04 0 99.70 0 0.05 0.21

donde se tienen una gran cantidad de cifras, sobre todo decimales, la computadora nos da el re-

sultado aproximado de la solucion real. Este problema es debido a que el sistema numerico en las

computadoras no puede representar la totalidad de los numeros reales.

Un punto a tomar en cuenta para elegir la exactitud son los fines para los que queremos la

aplicacion, y tomando en cuenta el tiempo que se va a tardar en realizar las operaciones. Un ejemplo

de ello nos lo encontramos en el corte de mosaico donde no es indispensable tener maquinaria con

precision en el orden de las micras.

Como en computo lo que importa es el tiempo de ejecucion es preciso someter a las funciones a

una prueba de velocidad de ejecucion. En la tabla 3.2 podemos observar los resultados de la prueba

de velocidad, donde nos muestra el porcentaje donde fue mas rapida cada funcion, en un total de

diez mil iteraciones.

En la tabla 3.2 se muestra un resultado muy claro, la implementacion 2 que corresponte a un

Unroll-4, es la mas rapida para valores de n grandes; pero no es la mas exacta. Es aquı donde

nace la gran disyuntiva, velocidad versus exactitud. Cabe senalar que para valores de n pequenos

la version canonica es mas rapida esto se debe a costo computacional por operaciones de alineacion

Page 62: Esquemas iterativos en paralelo con OpenMP

46 Capıtulo 3. Producto matriz-vector Ax

Unroll-5

r = n % 5;

for(j = 0; j < n-r; j+=5)

suma += x[j ]*y[j ] + x[j+1]*y[j+1] + x[j+2]*y[j+2]\

+ x[j+3]*y[j+3] + x[j+4]*y[j+4];

for(j = n-r; j < n; j++)

suma += x[j] * y[j];

Figura 3.9: Tecnica Loop Unroll con factor 5.

para la pila de operaciones. Tambien con estos resultados es concluyente que al dividir un for con

n iteraciones en k-for’s con n/k iteraciones es mas costoso debido al aumento de operaciones por el

manejo del ciclo. En la columna seis que corresponde a una version canonica dividida en dos partes,

la primera para numeros pares y la segunda para impares. Estos resultados demuestran el costo por

la carga de datos a la zona caliente y las repercusiones que tienen un mal manejo del proceso; por

no utilizar valores guardados en la cache.

El presente documento esta enfocado al estudio del rendimiento de las aplicaciones, es por ello

que la balanza se inclina hacia la velocidad. Con los resultados que se obtuvieron, se tiene una idea

general del funcionamiento de unroll.

Ya estudiamos las primeras cuatro variantes, donde se obtienen las conclusiones ya expuestas.

Mas adelante se toman en cuenta el resto de las variantes de la lista, para ası realizar lo importante;

una aplicacion con rendimiento aceptable. En el resto de las opciones se encuentran los Unroll

de 5, 6, 8, 10 y 12. Es importante mencionar, que existen muchas otras formas de codificar este

problema; sin embargo no se realizaran modificaciones debido a que se busca un mejor desempeno

computacional. En las figuras 3.9-3.13 se encuentran desarrolladas las funciones mencionadas.

Page 63: Esquemas iterativos en paralelo con OpenMP

3.5. Incremento del desempeno 47

Unroll-6

r = n % 6;

for(j = 0; j < n-r; j+=6)

suma += x[j ]*y[j ] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3]\

+ x[j+4]*y[j+4] + x[j+5]*y[j+5];

for(j = n-r; j < n; j++) suma += x[j] * y[j];

Figura 3.10: Tecnica Loop Unroll con factor 6.

Unroll-8

r = n % 8;

for(j = 0; j < n-r; j+=8)

suma += x[j ]*y[j ] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3]\

+ x[j+4]*y[j+4] + x[j+5]*y[j+5] + x[j+6]*y[j+6] + x[j+7]*y[j+7];

for(j = n-r; j < n; j++) suma += x[j] * y[j];

Figura 3.11: Tecnica Loop Unroll con factor 8.

Unroll-10

r = n % 10;

for(j = 0; j < n-r; j+=10)

suma += x[j ]*y[j ] + x[j+1 ]*y[j+1 ] + x[j+2 ]*y[j+2 ]\

+ x[j+3]*y[j+3] + x[j+4 ]*y[j+4 ] + x[j+5 ]*y[j+5 ]\

+ x[j+6]*y[j+6] + x[j+7 ]*y[j+7 ] + x[j+8 ]*y[j+8 ]\

+ x[j+9]*y[j+9];

for(j = n-r; j < n; j++) suma += x[j]*y[j];

Figura 3.12: Tecnica Loop Unroll con factor 10.

Page 64: Esquemas iterativos en paralelo con OpenMP

48 Capıtulo 3. Producto matriz-vector Ax

Unroll-12

r = n % 12;

for(j = 0; j < n-r; j+=12)

suma += x[j ]*y[j ] + x[j+1 ]*y[j+1 ] + x[j+2 ]*y[j+2 ]\

+ x[j+3]*y[j+3] + x[j+4 ]*y[j+4 ] + x[j+5 ]*y[j+5 ]\

+ x[j+6]*y[j+6] + x[j+7 ]*y[j+7 ] + x[j+8 ]*y[j+8 ]\

+ x[j+9]*y[j+9] + x[j+10]*y[j+10] + x[j+11]*y[j+11];

for(j = n-r; j < n; j++) suma += x[j]*y[j];

Figura 3.13: Tecnica Loop Unroll con factor 12.

Se evaluaran las cuatro implementaciones anteriores con el fin de medir la velocidad de cada una

de ellas, tambien se auna a ellas el Unroll de 4, para comparar el rendimiento. Para ello se utilizo una

computadora Apple MacBook con el sistema Operativo Mac OS X (v. 10.6.8), un procesador Intel

Core 2 Duo (2.4 GHz), 2 GB de memoria RAM DDR3 (1067 MHz). En la figura 3.14 se muestran

los resultados obtenidos, se observa el speed-up obtenido por cada una de las funciones con respecto

a la canonica. Cabe hacer mencion que para estos resultados no se utilizo ninguna de las banderas

de compilacion disponibles.

102

103

104

1.1

1.2

1.3

1.4

1.5

1.6

1.7

1.8

1.9

2

2.1

Valor de N

Sp

ee

d−

Up

Unroll−4

Unroll−5

Unroll−6

Unroll−8

Unroll−10

Unroll−12

Figura 3.14: Speed-up para la multiplicacion de dos vectores.

Page 65: Esquemas iterativos en paralelo con OpenMP

3.5. Incremento del desempeno 49

En la figura 3.14 se observa que el desempeno computacional aumenta en un promedio general

de 1.7x para la multiplicacion de dos vectores. El mejor desempeno para valores de n menores a

1000 corresponde a la funcion con Unroll de ocho con un pico de 2x. Sin embargo, para los valores

mayores a 1000 el mejor comportamiento esta dividido en dos, el Unroll de ocho y diez; este ultimo

es ligeramente mas rapido que los demas. En esta grafica se demuestra que aumentar el desdoble no

garantiza que el incremento en el desempeno aumentara; el speed-up desempenado por Unroll-12

no es en ningun momento la funcion mas rapida y mientras el orden de los vectores aumenta la

tendencia del rendimiento de esta funcion se asemeja al Unroll-4. Cabe senalar que existen tres

funciones que presentan un rendimiento que tiene a normalizarse conforme el valor de n aumenta,

estas funciones son las que corresponde a un Unroll de 4, 5, 6. Es muy importante que el aumento

del rendimiento sea uniforme en programas seriales; esto permite tener un incremento mas uniforme

al programarlo en paralelo.

Con las cinco funciones anteriormente descritas se realiza el producto matriz-vector (Ax), se

pone mayor interes en estas funciones [Unroll (4, 5, 6, 8, 10, 12)] debido a que son las que mejor

comportamiento han tenido. Tambien encaminado a tener un panorama mas amplio conforme se

adentre al tema en cuestion.

Retomando el problema tenemos que

c = Ax (3.11)

donde c, x ∈ RN y la matriz A ∈ RN×N

Partiendo de la ecuacion (3.11), se expresa con una vista para fines de programacion

ci =n∑j=1

Aijxj i = 1, 2, . . . , n (3.12)

En (3.12) observamos que para resolver (3.11) se realizan n-operaciones del tipo x · y (producto

de dos vectores). Lo cual se define como se muestra a continuacion.

ci =

n∑i=1

Aix (3.13)

Con base a lo que se ha mencionado, se puede proceder a realizar el programa que resuelva el

problema. Con base a los resultados de la parte anterior se realiza una funcion para cada una de

Page 66: Esquemas iterativos en paralelo con OpenMP

50 Capıtulo 3. Producto matriz-vector Ax

las opciones [Unroll(4, 5, 6, 8, 10, 12)]. Las funciones descritas tienen la forma siguiente:

float dot version(float *x, float *y, int n)

Explicando la sintaxis de las funciones, dot version es el nombre de la version de la funcion;

por ejemplo dot 4 corresponde a la funcion con un Unroll de cuatro. El resto de los nombres de las

funciones tienen la misma tendencia. Con ello podemos escribir la forma general de las funciones,

lo cual es descrito en la figura 3.15, donde la palabra version sera sustituido por el factor de unroll

de la funcion que se trate.5

Ax con la tecnica de Unroll

void matrix_vector_dot(float **A, float *x, float *c, int n)

int i;

for(i = 0; i < n, i++)

c[i] = dot_vesion(A[i],x,n);

Figura 3.15: Funcion general de la multiplicacion Ax con Unroll.

Es preciso ilustrar el rendimiento que se obtiene despues de las modificaciones y definiciones que

se han realizado durante esta seccion. En la figura 3.16 se plasma el speed-up que desempena cada

una de las funciones Unroll[4, 5, 6, 8, 10, 12]. En ella se observan principalmente dos situaciones

denotadas por el orden de la matriz. La primera describe al rendimiento como una lınea brusca, esto

se presenta cuando el orden es pequeno (100:1000). En el caso contrario, cuando la matriz es densa,

el rendimiento tiende a ser simetrico conforme la matriz crezca. Cuando se optimizan programas se

busca que el speed-up sea estable. Con base a ello se deduce que el factor de Unroll es determinante,

para matrices de orden pequeno el desdoble debe ser menor; en caso contrario el factor debe ser

mayor. Ademas se percibe en la grafica que a mayor factor de Unroll el rendimiento aumenta para

casi todos los casos; en esta evaluacion el desdoble de 12 tiene un rendimiento menor al de 10, lo

cual es concluyente para afirmar que si se realiza el experimento con un factor de 14 tendra menor

rendimiento que el de 12.

Durante el transcurso de esta seccion se ha hecho referencia al desempeno computacional de

las aplicaciones. En la figura 3.16 se ilustra el speed-up de cada aplicacion con respecto a otra

5El factor de unroll denota la cantidad de iteraciones que son ejecutadas en un paso dentro del bucle.

Page 67: Esquemas iterativos en paralelo con OpenMP

3.5. Incremento del desempeno 51

102

103

104

1.5

1.55

1.6

1.65

1.7

1.75

1.8

1.85

Valor de N

Sp

ee

d−

up

Unroll 4

Unroll 5

Unroll 6

Unroll 8

Unroll 10

Unroll 12

Figura 3.16: Speed-up de Ax utilizando la tecnica de Unroll.

canonica. En la mayorıa, si es que no en todos, los documentos que tratan temas relacionados a la

optimizacion de codigo para Programacion en Alto Desempeno (HPC, por sus singlas en ingles de

High Performance Computing) miden el rendimiento en operaciones en coma flotante por segundo

(flops). Las computadoras con que contamos hoy en dıa pueden realizar mas de una operacion en

cada ciclo. Ademas se toma en cuenta que un procesador actual (por ejemplo el procesador Intel

i7 de segunda generacion, uno de los mas actuales durante la realizacion de este trabajo) tienen

frecuencias de 2.6 GHz lo cual significa 2.6×109 ciclos por segundo. Por esas caracterıscas la cantidad

de operaciones esta en el orden de los millones.

En virtud de lo mencionado, en la figura 3.17 se plasma el desempeno computacional de las

funciones tratadas. Para realizar esta evaluacion se utilizo una computadora con las siguientes

caracterısticas tecnicas Apple MacBook con el sistema Operativo Mac OS X (v10.6.8), un procesador

Intel Core 2 Duo (2.4 GHz), 2 GB de memoria RAM DDR3 (1067 MHz), cabe mencionar que no

se utilizo ninguna de las banderas de compilacion disponibles para la compilacion. En la grafica se

observa la ganancia en MFLOPS por utilizar la tecnica de Unroll.

En la figura 3.17 se muestra que la aplicacion con el factor de Unroll mayor (factor de 12) no

es la mejor, para este experimento en particular. La funcion que tiene un mayor rendimiento fue la

de Unroll-10, pero no existe una brecha muy marcada con respecto al rendimiento del resto de la

Page 68: Esquemas iterativos en paralelo con OpenMP

52 Capıtulo 3. Producto matriz-vector Ax

102

103

104

300

350

400

450

500

550

600

650

700

750

Valor de N

Re

nd

imie

nto

(M

FL

OP

S)

Canonica

Unroll 4

Unroll 5

Unroll 6

Unroll 8

Unroll 10

Unroll 12

Figura 3.17: Rendimiento computacional de Ax al utilizar la tecnica de Unroll.

funciones Unroll, todas con una pequena diferencia. Para los temas siguientes cuando se mencione

la funcion Unroll se hace referencia al Unroll-10, a menos que se especifique lo contrario.

Con la optimizacion que se realizo durante esta seccion se obtiene un aumento del rendimiento

cercano al 200 % con una tecnica muy sencilla. Ello es bienvenido en procesos donde el tiempo de

calculo es muy demandante, para ejemplificar, si se tiene un proceso donde se resuelve el producto

de una matriz por un vector de forma iterativa se reduce aproximadamente a la mitad el tiempo

de ejecucion de la aplicacion, si anteriormente duraba una hora con la optimizacion solo durara 30

minutos.

3.6. Procesamiento vectorial (SIMD)

Anteriormente cuando las computadoras tenıan un procesador se buscaron opciones para mejorar

el rendimiento del procesamiento, es cuando se desarrollo una forma de paralelizar los datos y

ası tener varios modulos de procesamiento en un procesador; donde hay varias entradas de datos y

una salida unica. Una de ellas fue la tecnica llamada SIMD.

Single Instruction, Multiple Data (SIMD)

Como su acronimo lo indica, SIMD (Una Instruccion Multiples Datos) es una tecnica empleada

Page 69: Esquemas iterativos en paralelo con OpenMP

3.6. Procesamiento vectorial (SIMD) 53

para conseguir paralelismo a nivel de datos, es decir, tenemos una instruccion donde se aplica una

misma operacion a un conjunto de datos. Mediante una organizacion donde intervienen Unidades de

Procesamiento (UP) y una Unidad de Control (UC), la cual supervisa y asigna las actividades que

se van a realizar en las unidades de procesamiento. El proceso se presenta de la siguiente forma, la

unidad de control envıa la misma instruccion a las unidades de procesamiento; cada UP trabaja en

un subconjunto de los datos; ası es como se ejecuta la instruccion de forma sıncrona donde actuan

todas las unidades de procesamiento.

Figura 3.18: Modelo SIMD.

En la figura 3.18 se ilustra el funcionamiento del modelo SIMD donde se observa que la UC

interviene en la carga de los datos y la ejecucion de los mismo en las UPs. Los datos son divididos

en n bloques con tantos elementos como UPs. La ejecucion de la operaciones se llevan a cabo con

la direccion de la UC la cual se encarga de cargar los datos a los registros y posteriormente indicar

la operacion a ser ejecutada en las UPs.

Como menciona Cockshott et al.[13], el modelo SIMD fue desarrollado originalmente en el con-

texto de y para maquinas paralelas a gran escala, en esos sistemas un procesador unico de control

emite una instruccion para miles de procesadores, cada uno de ellos de un bit unico de longitud

de palabra, con ello cada procesador funciona al mismo tiempo en la operacion global. Los pri-

meros procesadores SIMD exhiben paralelismo masivo de datos pero, como cada procesador tiene

su memoria privada y un bus de datos, esto hacıa que las maquinas fuesen enormes, compuestas

por multiples tarjetas de ejecucion y cada una con multiples chips de memoria y pares de chips

procesadores de datos. Hay que denotar que el modelo SIMD no esta restringido unicamente a los

Page 70: Esquemas iterativos en paralelo con OpenMP

54 Capıtulo 3. Producto matriz-vector Ax

procesadores de un bit, sino que lo podemos encontrar implementado en procesadores de 8, 16,

32 y 64 bits. Esta caracterıstica nos permite no solamente realizar aritmetica de un bit, sino que

podemos realizar aritmetica paralela con varios bits enteros y numeros de punto flotante.

En la actualidad la incorporacion de SIMD en los microprocesadores con propositos generales se

encuentra en una escala modesta. Y por razones meramente economicas el motor SIMD se incluye

en el mismo chip que el resto de la Unidad Central de Procesamiento (CPU) lo cual restringe el

grado de paralelismo, no por problemas de incorporacion sino por el ancho de la ruta entre la CPU

y la memoria de datos; mientras que el ancho de las lıneas de cache limitan el grado de paralelismo.

En base a lo que menciona Cockshott et al.[13], en la actualidad un gran numero de procesa-

dores cuentan con el conjunto de instrucciones SIMD; con el objetivo de permitir que se realicen

varias operaciones en cada ciclo de reloj; es decir, una unica intruccion realiza la misma operacion

matematica, con un subconjunto distinto de los datos para la operacion, al mismo tiempo.

Tecnologıa MMX

Esta tecnologıa es un conjunto de instrucciones SIMD desarrolladas por Intel, obtiene la deno-

minacion de MMX por MultiMedia eXtension o Multiple Math o Matrix Math eXtension. Como

menciona Mittal et al.[27], la tecnologıa MMX amplıa lo que era la Arquitectura (IA) de Intel, fue

disenada con el fin de mejorar el rendimiento de la multimedia, las comunicaciones y las nuevas

aplicaciones para la Internet, pero en general cualquier aplicacion que se ajuste al paradigma SIMD

podra disfrutar de forma importante el rendimiento de speed-up brindado por esta tecnologıa.

La adicion de la tecnologıa MMX a la familia de procesadores IA debıa ser perfecta, para que

las aplicaciones que utilizaran dicha tecnologıa se ejecutara sin ningun contratiempo en cualquier

sistema operativo amigo de la arquitectura de Intel, ası no se tendrıa que realizar modificacion

alguna en el mismo (sistema operativo). De esta manera la convivencia con la base de la aplicacion

IA existente era perfecta [27].

Lo mencionado con anterioridad se traduce en beneficios para el usuario final mediante la mejora

en el rendimiento de las aplicaciones multimedia en un factor de 1.5x a 2x, y mejora el rendimiento

de nucleos clave en un factor de 4x en el procesador principal [27].

Para este documento se utilizan los registros para tipos de datos con precision simple mejor

conocidos como float, en los cuales la tecnologıa nos permite multiplicar cuatro elementos a la vez,

es decir, x(1 : 4) · y(1 : 4).

Page 71: Esquemas iterativos en paralelo con OpenMP

3.6. Procesamiento vectorial (SIMD) 55

El siguiente paso es realizar una implementacion en codigo C de un producto punto entre los

vectores x y y. Para esto se hace uso de las instrucciones que proporciona la tecnologıa MMX. En

la figura 3.19 se muestra una primera codificacion en MMX, para ello se presupone que el orden de

x y y es un multiplo de cuatro.

Producto de Vectores con MMX

float dot_mmx(float *x, float *y, int n)

int i;

float suma = 0.0;

__m128 n1, n2, n3, n4;

n4 = _mm_setzero_ps();

for(i = 0; i < n; i += 4)

n1 = _mm_loadu_ps(x+i);

n2 = _mm_loadu_ps(y+i);

n3 = _mm_mul_ps(n1, n2);

n3 = _mm_hadd_ps(n3, n3);

n4 = _mm_add_ps(n4, n3);

n4 = _mm_hadd_ps(n4, n4);

_mm_store_ss(&suma,n4);

return suma;

Figura 3.19: Funcion en MMX que multiplica dos vectores x y y.

A continuacion se desglosan cada una de las instrucciones MMX (usadas en la figura 3.19) con

el fin de tener una idea mas concreta de como funciona el codigo anterior, las definiciones para cada

funcion fueron extraıdas de la pagina web de Microsoft Developer Network6.

1. m128: es un tipo de dado para uso exclusivo con Streaming SIMD Extensions y Streaming

SIMD Extensions 2, esta definido dentro de la biblioteca “xmmintrin.h”. No se puede acceder

directamente a los campos m128. pero pueden verse en el depurador. Este tipo de variable

se correlaciona con los registros MMX[0-7] y se alinean automaticamente en el lımite de 16

bytes.

6La direccion de internet del sitio Microsoft Developer Network es http://msdn.microsoft.com/en-us/.

Page 72: Esquemas iterativos en paralelo con OpenMP

56 Capıtulo 3. Producto matriz-vector Ax

El tipo de dato m128 es un vector de 4 elementos de tipo float, es por ello que se le considera

como un mini-vector.

2. mm setzero ps(): esta funcion retorna una variable m128 donde cada uno de los elementos

es equivalente a cero. Esta funcion tiene la forma,

__m128 _mm_setzero_ps(void);

Internamente la operacion que se realiza es la siguiente: se tiene una variable R de tipo m128,

dentro de la funcion se hace r(1 : 4) = 0.

3. mm loadu ps(x+i): con esta funcion se cargan los cuatro valores siguientes del vector a

los registros MMX(0-7). La funcion tiene la siguiente forma:

__m128 _mm_loadu_ps(float *p);

La operacion realizada se expresa como r(1 : 4) = p(1 : 4), donde r y p son vectores.

4. mm mul ps(n1, n2): esta funcion realiza la mutiplicacion n1 por n2 y el resultado lo retorna

en un vector r, para esto cada uno de los vectores debe ser de tipo m128. La forma de la

funcion se muestra a continuacion:

__m128 _mm_mul_ps(__m128 n1, __m128 n2);

La operacion realizada por esta funcion es r(1 : 4) = n1(1 : 4)× n2(1 : 4).

5. mm hadd ps(n3, n3): esta funcion realiza una suma horizontal, es decir, los elementos

adyacentes en el mismo operando se suman. Cada argumento de 128-bits es considerado como

cuatro elementos de tipo float cada uno de 32-bits. La nomenclatura de esta funcion se expresa

a continuacion:

__m128 _mm_hadd_ps(__m128 a, __m128 b);

Esta rutina realiza la siguiente operacion, se tienen los vectores a, b, r de tipo m128 e

internamente se realiza la operacion:

r = a+ b

Page 73: Esquemas iterativos en paralelo con OpenMP

3.6. Procesamiento vectorial (SIMD) 57

r =

r4 = b4 + b3

r3 = b2 + b1

r2 = a4 + a3

r1 = a2 + a1

=

a4

a3

a2

a1

+

b4

b3

b2

b1

6. mm add ps(n4, n3): esta rutina suma los cuatro valores de n4 y n3. la funcion tiene la

siguiente sintaxis.

__m128 _mm_add_ps(__m128 a, __m128 b);

La presente funcion realiza simplemente la suma de dos vectores a y b, lo cual se demuestra

en la siguiente ecuacion,

r =

r4 = a4 + b4

r3 = a3 + b3

r2 = a2 + b2

r1 = a1 + b1

=

a4

a3

a2

a1

+

b4

b3

b2

b1

7. mm store ss(&suma,n4): esta funcion guarda el valor de una variable m128 (n4) a una

variable float∗ (suma). La estructura de la funcion se define a continuacion:

void _mm_store_ss(float * p, __m128 a);

Es preciso indicar que el primer argumento es un apuntador, es decir, contiene la direccion de

memoria donde se guardara el valor que esta alojado en n4.

En la tabla 3.3 se observan los resultados que se obtienen con este paradigma de programacion.

En la primera columna se indica los valores de n utilizados. Los tiempos de ejecucion con la im-

plementacion canonica, se muestran en la segunda columna7. En el siguiente par de columnas se

especifican los tiempos de ejecucion y el rendimiento, respectivamente, arrojados por la funcion con

un factor de Unroll igual a 4. En la quinta y sexta columna se exponen el tiempo de ejecucion y el

speed-up a consecuencia de escribir programas con la tecnologıa MMX. Para obtener los resultados

7Unroll-0 o version canonica.

Page 74: Esquemas iterativos en paralelo con OpenMP

58 Capıtulo 3. Producto matriz-vector Ax

Tabla 3.3: Producto de dos vectores: comparacion de rendimiento de las funciones canonica, MMXy Unroll-4; observamos el rendimiento que nos brinda la funcion en MMX respecto a la formatradicional y en comparacion con la funcion con Unroll de 4.

Comparacion de Rendimiento de MMXcon bandera de Compilacion -O2

Valor de Tradicional Unroll-4 MMXN Tiempo(s) Tiempo(s) Speed-Up Tiempo(s) Speed-Up

16 0.00117 0.00080 1.46 0.00083 1.4132 0.00156 0.00098 1.59 0.00088 1.7764 0.00236 0.00134 1.77 0.00109 2.18

128 0.00379 0.00219 1.73 0.00172 2.21256 0.00748 0.00307 2.44 0.00239 3.13512 0.01493 0.00530 2.82 0.00464 3.22

1024 0.02853 0.00925 3.08 0.00758 3.772048 0.05883 0.01801 3.14 0.01453 3.904096 0.11247 0.03560 3.16 0.02860 3.938192 0.22394 0.07879 2.84 0.05613 3.99

16384 0.44777 0.16040 2.79 0.11342 3.9532768 0.89796 0.31393 2.86 0.22376 4.01

que se muestra se utilizo una bandera de compilacion (-O2), con el fin de activar una pila de op-

timizaciones de GNU GCC y ası mejorar el rendimiento en la aplicacion. Para mayor informacion

consultar el Manual de Usuario del compilador8.

Como se aprecia en la cuarta y sexta columna de la tabla 3.3, conforme el valor de n se incrementa

el speed-up con MMX es comparativamente superior al speed-up del Unroll utilizado hasta un

maximo de 4x para MMX.

Durante la seccion anterior se optimizo el codigo utilizando la tecnica de Unroll, la cual es

evidentemente diferente a la de procesamiento vectorial. A consecuencia de lo mencionado es preciso

crear una combinacion de ambas tecnicas para determinar la conveniencia de la fusion.

Para realizar esta evaluacion se empleo una computadora con las siguientes caracterısticas tecni-

cas Apple MacBook con el sistema Operativo Mac OS X (v10.6.8), un procesador Intel Core 2 Duo

(2.4 GHz), 2 GB de memoria RAM DDR3 (1067 MHz) de forma adicional se utilizo la bandera de

8Los manuales de GCC estan disponibles en electronico y clasificados por version del compilador en la paginahttp://gcc.gnu.org/onlinedocs.

Page 75: Esquemas iterativos en paralelo con OpenMP

3.6. Procesamiento vectorial (SIMD) 59

compilacion (-O2).

0 1000 2000 3000 4000 5000 6000 7000 8000 9000 100001200

1400

1600

1800

2000

2200

2400

2600

2800

3000

Valor de N

Rendim

iento

(M

FLO

PS

)

Canonica

MMX

MMX Unroll−2

MMX Unroll−4

Figura 3.20: Desempeno de Ax al utilizar MMX con bandera de compilacion -O2.

El resultado de ello es ilustrado en la figura 3.20 en la cual se presenta el rendimiento en

MFLOPS para las funciones, canonica MMX y MMX con Unroll [2, 3].9 En esta grafica se observa

que el rendimiento de MMX es en momentos cerca de dos veces mas rapida que la canonica, cuando

la dimension de la matriz es menor a 1000×1000. Cuando incrementamos la dimension de la matriz

el speed-up es de 1.5x en promedio, lo cual es evidentemente menor que para el caso anterior (ver la

tabla 3.3). Los resultados para MMX (con un core) son semejantes a los esperados segun Mittal et

al.[27]. Cabe mencionar que no existe beneficio por fusionar las dos tecnicas de optimizacion, esto

desde un punto de vista practico.

Con los resultados que se obtienen es concluyente que la tecnica de procesamiento vectorial es

una mejor opcion antes de fusionarla con la tecnica de Unroll Loops.

9Nota: en este caso la tecnica de Unroll fue aplicada sobre MMX, es decir, en cierto modo MMX es equitativo aUnroll-4; con ello Unroll 2, 3 para MMX corresponde a un Unroll real de 8 y 12 respectivamente.

Page 76: Esquemas iterativos en paralelo con OpenMP

60 Capıtulo 3. Producto matriz-vector Ax

3.7. Codificacion en paralelo

En esta seccion se realiza la codificacion en paralelo de c = Ax. En primera instancia se realiza

con base, unicamente, en la ecuacion (3.7) de la pagina 34 a esta version la llamaremos canonica en

paralelo.

En el diseno de algoritmos en paralelo es importante establecer las dependencias de operaciones

presentes en el problema a resolver. Esto a fin de eliminar los cuellos de botella que pudiesen presen-

tarse; pero lo mas importante, que la ejecucion en paralelo no altere los resultados negativamente.

Si prestamos atencion en la ecuacion (3.7) se observa que no existen dependencias de operaciones

cuando se calcula el i-esimo elemento del vector c (ci). Para este caso en particular no existe una

competencia entre los hilos en el acceso a los elementos; porque se obtienen a traves de los ındices.

Si cualquiera de las escalares fuese una lista enlazada este problema se presentarıa y habrıa que

sincronizar el acceso de los hilos. A continuacion se muestra la ecuacion que se ha mencionado (3.7).

ci =

n∑j=1

aijxj i = 1, 2, . . . , n

Como no existe dependencia entre las operaciones no es necesario hacer modificaciones a la

ecuacion; para que esta pueda ser paralelizada. A continuacion se realiza la primera implementacion

en paralelo de la multiplicacion de una matriz por un vector, en la figura 3.21. Para realizar esta

primera version en paralelo se agrega unicamente una directiva de OpenMP al codigo descrito en

la canonica. A esto se debe la popularidad de este paradigma de programacion.

Canonica en Paralelo

#pragma omp parallel for default(none) \

shared(x,c,A,n) private(j,i)

for(i = 0; i < n; i++)

c[i] = dot(A[i], x, n);

Figura 3.21: Implementacion canonica en paralelo de Ax.

En primer lugar se indica el significado de la directiva de OpenMP usada en figura 3.21, se define

que la estructura a paralelizar es un ciclo for. Ademas se puntualiza el tipo de acceso por parte de

los hilos que tendra cada una de las variables. El tipo compartido (shared) todos los hilos tendran

Page 77: Esquemas iterativos en paralelo con OpenMP

3.7. Codificacion en paralelo 61

acceso sincronizado a la variable. Para el caso contrario (private) cada uno de los hilos contara con

una copia de esa variable, por ejemplo en la variable n cada hilo tiene una variable nα de la cual solo

el hilo del que nα sea huesped podra acceder al valor que se aloja en ella; dicho de otra forma es una

variable local de cada hilo (mas informacion en [10, 11, 17]). Para tener una idea mas concreta del

funcionamiento paralelo del codigo descrito en la figura 3.21 es preciso definirlo. De forma particular

para la ejecucion con dos procesadores, el ciclo for principal es interpretado como dos sub-for’s, el

primero con el rango (1 : n/2) y el del otro (n/2 : n) cada sub-for es ejecutado en un procesador

distinto de forma simultanea. Ello se expresa a continuacion,

for(i = 0; i < n/2; i++) for(i = n/2; i < n; i++)

c[i] = dot(A[i],x,n); c[i] = dot(A[i],x,n);

Lo expresado con anterioridad es aplicable para k cantidad de procesadores, y la forma funda-

mental de la ejecucion persiste. En la figura 3.22 se ilustra el rendimiento computacional que tiene el

codigo que corresponde a la version canonica en paralelo. Los resultados mostrados se obtienen por

la ejecucion en una computadora Apple modelo MacPro 4.1 con dos procesadores Quad-Core Intel

Xeon a 2.26 GHz, 8 Gb de memoria RAM tipo DDR3 (1067 MHz), con un sistema operativo Mac

OS X Snow Leopard (v10.6.8), en lo consecuente cuando se muestren los resultados de ejecuciones

paralelas corresponderan a esta computadora a menos que se indique lo contrario.

En la figura 3.22 se muestra que el rendimiento para una matriz (para tamano igual o menor a

1000) se deteriora conforme se incrementa la cantidad de hilos. En el caso contrario el rendimiento

se ve mejorado sustancialmente conforme aumentan el numero de procesadores. Cabe hacer mencion

que el speed-up que se obtiene al incrementar la cantidad de hilos no es literalmente proporcional.

Para 2 y 4 hilos la proporcionalidad esta presente, desde un punto de vista practico. Sin embargo,

el aumento en el rendimiento para 8 nucleos con respecto a 4 es mucho menor. Esto se debe al

cuello de botella en el acceso a la memoria resultado de la arquitectura de la computadora.10 Con

ello es concluyente que para casos donde el tamano de la matriz es pequeno es una mejor opcion el

resolverlo con menos hilos y viceversa.

Durante las ultimas dos secciones se crearon diferentes funciones con tecnicas de optimizacion

diferentes, con el fin de mejorar el rendimiento en una ejecucion no paralela. Esto permite generar un

software en paralelo con diferentes tecnicas y un rendimiento distinto. En la figura 3.23 se describe

10La computadora tiene un arquitectura Intel Nehalem que agrega un buffer de menores prestaciones que permitecompartir informacion entre los dos procesadores. El acceso a este nivel es mas costoso en terminos de tiempo.

Page 78: Esquemas iterativos en paralelo con OpenMP

62 Capıtulo 3. Producto matriz-vector Ax

102

103

104

0

1000

2000

3000

4000

5000

6000

7000

8000

Valor de N

Rendim

iento

(M

FLO

PS

)

1−Core

2−Cores

4−Cores

8−Cores

Figura 3.22: Rendimiento de la version canonica de Ax en paralelo con bandera de compilacion -O2.

la forma general que tiene la funcion paralela que multiplica una matriz por un vector, ello con base

al codigo de la figura 3.16. Es bien observado que la subrutina relativamente no cambia, cuando se

cambia entre las diferentes tecnicas de optimizacion.

Forma general en paralelo

#pragma omp parallel for default(none) \

shared(x,c,A,n) private(j,i)

for(i = 0; i < n; i++)

c[i] = dot_version(A[i], x, n);

Figura 3.23: Implementacion general de Ax en paralelo.

Durante esta seccion se hizo paralela la version canonica y se obtuvieron resultados que muestran

los beneficios en rendimiento por esta accion. Los cuales tiene una semejanza con lo esperado,

el incremento del rendimiento en la practica no es lineal debido en gran parte al diseno de la

computadora.

Page 79: Esquemas iterativos en paralelo con OpenMP

3.8. Evaluacion de algoritmos en paralelo 63

3.8. Evaluacion de algoritmos en paralelo

En esta seccion se realiza la evaluacion de los algoritmos tratados en las secciones anteriores. Se

realizan diferentes planteamientos con fin de seleccionar la mejor opcion para resolver el problema

en cuestion.

En temas anteriores se ha utilizado el termino de bandera de compilacion pero hasta este mo-

mento no se ha definido el significado ni el proposito de su uso. Por ello es preciso definir este punto

tan importante. De forma general, la bandera de compilacion tiene la funcion de activar una serie

de optimizacion durante el compilado del codigo, esto en forma analoga a las banderas utilizadas

en cualquier programa. El uso de las banderas de compilacion tienen el unico fin de aumentar el

desempeno computacional de la aplicacion.

Figura 3.24: Desempeno de la version canonica de Ax con banderas de compilacion.

En la figura 3.24 se ilustran los beneficios que se obtienen con el uso de banderas de compilacion,

para los propositos del presente trabajo solo se utilizan dos banderas “-O2” y “-funroll-loops”. En

la grafica se plasma que al utilizar la bandera de compilacion el rendimiento de la aplicacion se va

a las nubes. Para este caso en particular la diferencia entre “-O2” y “-funroll-loops”practicamente

no existe. En la realizacion del presente documento se utiliza la bandera “-O2” que corresponde al

segundo nivel de optimizacion por parte del compilador; esto mientras no se indique lo contrario.

Las optimizaciones activadas por esta bandera son descritas en [40, pag.70].

Primeramente se realiza la evaluacion de la tecnica de Unroll Loops en paralelo. Para este

procesos se toma en cuenta unicamente el factor de Unroll de 10 ya que es el que mejor desempeno

Page 80: Esquemas iterativos en paralelo con OpenMP

64 Capıtulo 3. Producto matriz-vector Ax

102

103

104

0

0.5

1

1.5

2

2.5

3

3.5

4

4.5

Valor de N

Speed−

up

1−Core

2−Cores

4−Cores

8−Cores

Figura 3.25: Escalabilidad paralela de Ax en su la version Unroll-10 con bandera -O2.

obtuvo. En la figura 3.25 se plasma el speed-up de la version en cuestion cuando se aumenta el

numero de hilos de procesamiento. Es claro que la tecnica de Unroll tiene una menor escalabilidad

que la canonica de la figura 3.22. Para este caso en particular resulta contraproducente resolver el

problema con muchos hilos cuando el valor de n sea reducido, existen momentos en donde es mas

rapida la ejecucion con un procesador. Cabe mencionar que para los casos de ejecucion con 2 y 4

procesadores se obtiene un speed-up cercano al teorico o lineal 1.8x y 3.5x aproximadamente (para

los valores mas grandes de n). Esto induce a que la escalabilidad de la tecnica de Unroll Loops

es de considerarse ya que se asemeja a la canonica. Para el caso de 8 hilos la ganancia no es muy

significativa 4.3x con respecto a cuatro cores. Ello se debe a la arquitectura de la computadora

utilizada, para obtener los 8 hilos se hace uso del segundo procesador lo cual implica otra linea de

cache mas distante.

La evaluacion de la tecnica MMX consiste en el mismo procedimiento que el que se hizo para la

anterior. En primera instancia se evalua la escalabilidad en paralelo. En la figura 3.26 se ilustra el

speed-up de esta tecnica utilizando una bandera de compilacion -O2. En ella se observa que para

los valores 100 ≤ n ≤ 1000 es contraproducente hacerlo en paralelo. Mientras que para 1000 ≤ n ≤

10000 si existe una ganancia en el rendimiento. El speed-up que se obtiene para 2 procesadores es

Page 81: Esquemas iterativos en paralelo con OpenMP

3.8. Evaluacion de algoritmos en paralelo 65

102

103

104

0

0.5

1

1.5

2

2.5

3

3.5

Speed−

up

Valor de N

1−Core

2−Cores

4−Cores

8−Cores

Figura 3.26: Escalabilidad paralela de Ax en su la version MMX con bandera -O2.

un poco menor a 1.5x cuando teoricamente es 2x, con 4 hilos la ganancia es de 2.5x cuando debiese

ser 4x. El caso mas pobre es para 8 nucleos donde la ganancia no es muy significativa con respecto

a la de 4, la aceleracion apenas llega a 3x. Con estos resultados es concluyente que la version MMX

es menos escalable que la canonica y que Unroll Loops.

Una vez que se ha definido la escalabilidad de la funcion MMX se realiza la comparacion en

rendimiento con la tecnica Unroll Loops con un factor de unroll de 10. En la figura 3.27 se muestran

los resultados obtenidos. La diferencia mayor se presenta cuando la ejecucion es en serie. Conforme

se aumenta el numero de hilos de ejecucion esta diferencia tiende a disminuir. Con base a estos

resultados se demuestra que la funcion MMX tiene un mayor desempeno computacional para la

totalidad de los casos evaluados. Cabe mencionar que la diferencia en el rendimiento tiende a la

baja conforme se aumentan el numero de procesadores.

Para ilustrar una comparativa del rendimiento de las tres versiones tratadas en esta seccion se

plasma la grafica de la figura 3.27 donde se observa de forma muy clara que la version MMX es mas

rapida que las otras dos mas sin embargo cuando el numero de hilos comienza a crecer la diferencia

tiende a reducirse. Ello implica que en un determinado numero de hilos la funcion MMX dejara de

ser la mas rapida. Con los resultados obtenidos es concluyente que la version MMX tiene el mejor

Page 82: Esquemas iterativos en paralelo con OpenMP

66 Capıtulo 3. Producto matriz-vector Ax

Figura 3.27: Comparativa del rendimiento computacional de las versiones canonica, Unroll-10 yMMX con bandera de compilacion -O2.

rendimiento computacional. Sin embargo, no tiene la mejor escalabilidad cuando se hace en paralelo.

La version canonica tiene el mejor speed-up pero es la mas lenta, en terminos de rendimiento.

Como consecuente a los resultados de la evaluaciones realizadas se utilizara la funcion MMX en

los siguientes temas cuando sea necesario resolver el producto de una matriz por un vector.

Para finalizar este tema se concluye lo siguiente; durante la ejecucion de un programa en el cual

se cargan a la memoria cache del procesador, valores que no son utilizados sino hasta despues de la

segunda carga originan un retardo por gastos de ejecucion; aun el cache es de muy alta velocidad

ocasiona un continuo direccionamiento que se traduce en el aumento del tiempo. Realizar una sobre

carga de operaciones genera un mejor uso de la memoria caliente; pero a costo de un mayor error

de redondeo. Por otra parte la division de un ciclo en multiples beneficia en la reduccion del error

de redondeo por una “segmentacion” de la cantidad de operaciones; pero esto genera un incremento

en el tiempo de ejecucion por los gastos de manejo de ciclos y la administracion de las cargas de

memoria. La conclusion mas importante es que la tecnica MMX representa la mejor opcion para

Page 83: Esquemas iterativos en paralelo con OpenMP

3.8. Evaluacion de algoritmos en paralelo 67

resolver el producto de una matriz por un vector independientemente de una ejecucion en serie o

en paralelo. La escalabilidad paralela de MMX es la peor de las tres tratadas. La version canonica

es la que presenta la mejor escalabilidad cuando se aumenta el numero de cores para la ejecucion

paralela. La diferencia de performance entre MMX frente a la canonica y Unroll Loops tiende a

disminuir conforme se aumenta el numero de cores. Esto implica que a cierto numero de hilos de

ejecucion esa diferencia dejara de existir.

Page 84: Esquemas iterativos en paralelo con OpenMP
Page 85: Esquemas iterativos en paralelo con OpenMP

Capıtulo 4Metodo Iterativo de Jacobi

En el area de la computacion, y en la ingenierıa en general, una tarea cotidiana es la de resolver

problemas representados por un sistema lineal de ecuaciones. La resolucion de este problema de-

manda mucho calculo, es por ello que generalmente se le encomienda a una computadora. Por ello

es importante realizar programas eficientes que resuelvan estos problemas lo mas rapido posible.

Existen dos categorıas para resolver un sistema lineal, los metodos directos y los iterativos. Los

primeros determina la solucion en un numero determinado de pasos. Los iterativos son aquellos

que obtienen la solucion aproximandose a ella en un numero finito, pero no definido de pasos. La

principal diferencia entre ambos es en el resultado; el arrojado por los directos es exacto mientras

que aproximado el de los segundos (iterativos).

En palabras de Skiba [39] “los metodos directos se emplean para resolver sistemas lineales con

matrices n×n cuando el valor de “n” no es muy grande (menor que un millon)”. Cuando la matriz

de coeficientes es densa la cantidad de operaciones dependera del tamano, por otro lado cuando sea

dispersa el numero de operaciones dependera de la cantidad de elementos nulos y de la estructura

del grafo[8]. Ejemplos de metodos numericos que pertenecen a esta categorıa, los cuales se abordan

en este trabajo son la regla de Kramer, el metodo de Gauss-Jordan y la factorizacion LU.

Regla de Kramer

La regla de Kramer es el metodo directo mas simple, es de gran utilidad para comprender al

resto. De acuerdo con Skiba [39] en la practica ya no es utilizado debido al orden de complejidad

O((n+ 1)!) lo cual evidentemente es impractico. Sirve para resolver sistemas cuadrados de la forma

69

Page 86: Esquemas iterativos en paralelo con OpenMP

70 Capıtulo 4. Metodo Iterativo de Jacobi

Ax = b lo cual se representa como

a1,1x1

a2,1x1

...

an,1x1

+

+

+

a1,2x2

a2,2x2

...

an,2x2

+

+

+

. . .

. . ....

. . .

+

+

+

a1,nxn

a2,nxn...

an,nxn

=

=

=

b1

b2...

bn

(4.1)

De acuerdo con Baldor [5] la regla de Kramer dice: El valor de cada incognita es una fraccion

cuyo denominador es el determinante formado con los coeficientes de las incognitas (determinante

del sistema) y cuyo numerador es el determinante que se obtiene sustituyendo en el determinante

del sistema la columna de los coeficientes de la incognita que se halla por la columna de los terminos

independientes de las ecuaciones dadas.

En otras palabras el vector solucion del sistema se encuentra con la razon del determinante

general del sistema sobre el determinante de la matriz sustituyendo j-esimo vector columna del

sistema por el vector columna de los terminos independientes; y el determinante general de esa

matriz.

Como menciona Sydsaeter et al.[41], El sistema tiene una solucion unica si la matriz de coefi-

cientes es singular.

Este metodo es muy utilizado para resolver sistemas de 3 × 3, a continuacion se describe el

procedimiento para resolver los sistemas en cuestion.

Sea un sistema de ecuaciones de la siguiente forma

ax+ by + cz = j

dx+ ey + fz = k

gx+ hy + iz = l

El sistema se expresa de la siguiente forma matricial

a b c

d e f

g h i

x

y

z

=

j

k

l

(4.2)

Para encontrar el resultado de las variables x, y, z primero se resolvera el determinante de la

Page 87: Esquemas iterativos en paralelo con OpenMP

Preliminares: metodos directos 71

matriz de coeficientes a la cual nombraremos A, para ello aplicamos la regla de Sarrus1.

Det(A) = |A| =

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣

a b c

d e f

g h i

a b c

d e f

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣= (aei+ dhc+ gbf)− (ceg + fha+ ibd) (4.3)

Para encontrar los valores de las variables x, y, z se realiza el siguiente procedimiento, para esto

se toma en cuenta (4.3) y con base a la definicion de la regla ya expuesta,

x =Det(A1)

DetA=

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣

j b c

k e f

l h i

j b c

k e f

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣|A|

=(jei+ khc+ lbf)− (cel + fhj + ibk)

(aei+ dhc+ gbf)− (ceg + fha+ ibd)

y =Det(A2)

DetA=

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣

a j c

d k f

g l i

a j c

d k f

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣|A|

=(aki+ dlc+ gjf)− (ckg + fla+ ijd)

(aei+ dhc+ gbf)− (ceg + fha+ ibd)

z =Det(A3)

DetA=

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣

a b j

d e k

g h l

a b j

d e k

∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣|A|

=(ael + dhj + gbk)− (jeg + kha+ lbd)

(aei+ dhc+ gbf)− (ceg + fha+ ibd)

1La Regla de Sarrus, es un regla pratica muy sencilla consiste en repetir las primeras dos filas de la matriz decoeficientes al final de la misma. Despues realizar la suma del producto de las tres diagonales de izquierda a derechacon su propio signo; a las tres diagonales de derecha a izquierda se les cambia el signo.

Page 88: Esquemas iterativos en paralelo con OpenMP

72 Capıtulo 4. Metodo Iterativo de Jacobi

Con base en (4.2) y al procedimiento anterior se induce a la siguiente ecuacion para resolver los

sistemas de ecuaciones de n-ecuaciones con n-incognitas

xi =1

|A|

n∑j=1

Ajibj i = 1, 2, . . . , n (4.4)

Una forma mas simple para expresar (4.4) es la siguiente

xj =Det(Aj)

Det(A)j = 1, 2, . . . , n (4.5)

La regla de Kramer es utilizada para la solucion de sistemas lineales con pocas ecuaciones e igual

numero de variables. Presenta el fundamento teorico para comprender metodos como la eliminacion

gaussiana y la factorizacion LU .

Metodo de Gauss-Jordan

Este metodo es uno de lo preferidos para resolver sistemas de ecuaciones lineales, cabe mencionar

que es una variante del metodo de la eliminacion de Gauss (eliminacion gaussiana). De acuerdo

con Chapra et al.[12] ambos metodos difieren en que cuando se elimina una incognita se elimina no

solo de las ecuaciones subsecuentes sino de todo el sistema de ecuaciones. Esto infiere que la ultima

matriz a determinar es unitaria [18], es decir

A =

1 0 · · · 0

0 1 · · · 0...

.... . .

...

0 0 · · · 1

(4.6)

Teniendo la matriz A de la forma unitaria tiene la ventaja de que la solucion es directa. Esto

puede ser representado con la matriz extendida

A =

1 0 · · · 0 b1

0 1 · · · 0 b2...

.... . .

......

0 0 · · · 1 bn

(4.7)

Page 89: Esquemas iterativos en paralelo con OpenMP

Preliminares: metodos directos 73

es decir x(1 : n) = b(1 : n), donde x es la inconita y b es el resultado.

Con base a Nakamura [28] el algoritmo consiste en dos procesos principales: 1) la eliminacion

hacia adelante, y 2) eliminacion hacia atras.

En palabras2 del mismo autor el primer paso se realiza de la siguiente manera: La primera

ecuacion se multiplica por a2,1/a1,1 y se le resta a la segunda ecuacion para eliminar el primer

termino de la segunda; de la misma forma, el primer termino de las ecuaciones restantes, i > 2, se

elimina restando la primera ecuacion multiplicada por ai,1/a1,1, este resultado se representa como

a∗ijxj . Lo mencionado se ve a continuacion:

a1,1x1 + a2,1x2 + a3,1x3 + · · ·+ a1,nxn = b1

a∗2,2x2 + a∗2,3x3 + · · ·+ a∗2,nxn = b∗2

a∗3,2x2 + a∗3,3x3 + · · ·+ a∗3,nxn = b∗3...

a∗n,2x2 + a∗n,3x3 + · · ·+ a∗n,nxn = b∗n

(4.8)

Si aplicamos el mismo procedimiento pero ahora, para el segundo termino de las ecuaciones para

i > 2 se elimina restando la segunda ecuacion multiplicada por a∗1,2/a∗2,2 como sigue

a1,1x1 + a2,1x2 + a3,1x3 + · · ·+ a1,nxn = b1

a∗2,2x2 + a∗2,3x3 + · · ·+ a∗2,nxn = b∗2

a∗∗3,3x3 + · · ·+ a∗∗3,nxn = b∗∗3...

a∗∗n,3x3 + · · ·+ a∗∗n,nxn = b∗∗n

(4.9)

Siguiendo el paso anterior se eliminan todos los terminos para tener una matriz triangular supe-

rior. De forma general se despeja el j-esimo termino al multiplicar la j-esima ecuacion y aii,j−1/aij,j ,

esto se le resta a la j-esima ecuacion para i > j. Al finalizar este procedimiento la matriz tendra la

2La metodologıa que se presenta para la solucion del Metodo de Gauss-Jordan fue estraıdo del tema 6.2 de [28].

Page 90: Esquemas iterativos en paralelo con OpenMP

74 Capıtulo 4. Metodo Iterativo de Jacobi

siguiente forma.

a1,1x1 + a2,1x2 + a3,1x3 + · · ·+ a1,nxn = b1

a∗2,2x2 + a∗2,3x3 + · · ·+ a∗2,nxn = b∗2

a∗∗3,3x3 + · · ·+ a∗∗3,nxn = b∗∗3...

an−1n,3 x3 + · · ·+ an−1

n,n xn = bn−1n

(4.10)

Hasta este punto las eliminaciones de Gauss y Gauss-Jordan coinciden en su metodologıa. Donde

se diferencia es en el segundo paso, la eliminacion hacia atras. A continuacion se muestra la matriz

extendida que se tiene hasta este punto3

a1,1 a1,2 a1,3 . . . a1,n−1 a1,n b1

0 a∗2,2 a∗2,3 . . . a∗2,n−1 a∗2,n b∗2

0 0 a3,3 . . . a3,n−1 a3,n b∗∗3...

.... . .

. . ....

......

0 0 0 . . . an−2n−1,n−1 an−2

n−1,n bn−2n−1

0 0 0 . . . 0 an−1n,n bn−1

n

(4.11)

Antes de continuar con el paso dos es preciso mencionar; se le conoce como pivotes a los elementos

de la diagonal principal. Para realizar la eliminacion hacia atras se parde de (4.11), al finalizar este

paso se tendra una matriz identidad para los coeficientes y los valores de los terminos independientes

corresponderan al valor de la incognita que no es cero. Primero se divide el ultimo renglon entre

an−1n,n . De esta forma se obtiene 1 en ese pivote.

Para eliminar el n-esimo coeficiente del i-esimo renglon basta con multiplicar el n-esimo coefi-

ciente por el ultimo renglon (renglon n), este resultado restarlo al i-esimo renglon. Con ello se tiene

3Esta matriz fue extraıda de la pagina 187 del libro de [28].

Page 91: Esquemas iterativos en paralelo con OpenMP

Preliminares: metodos directos 75

la nueva matriz,

a1,1 a1,2 a1,3 . . . a1,n−1 0 b∗1

0 a∗2,2 a∗2,3 . . . a∗2,n−1 0 b∗2

0 0 a3,3 . . . a3,n−1 0 b∗3...

.... . .

. . ....

......

0 0 0 . . . an−2n−1,n−1 0 b∗n−1

0 0 0 . . . 0 1 bn

(4.12)

Para convertir en 1 el pivote del renglon n− 1, se divide ese renglon por su pivote. Se eliminan

los coeficientes de la columna (n− 1), para i < n− 1, restando al i-esimo renglon la multiplicacion

del n-esimo coeficiente del i-esimo renglon. Con este procedimiento se tiene la matriz de la siguiente

manera

a1,1 a1,2 a1,3 . . . 0 0 b∗∗1

0 a∗2,2 a∗2,3 . . . 0 0 b∗∗2

0 0 a3,3 . . . 0 0 b∗∗3...

.... . .

. . ....

......

0 0 0 . . . 1 0 b∗n−1

0 0 0 . . . 0 1 bn

(4.13)

Continuando con este procedimiento se tiene el siguiente resultado el cual representa la solucion

del sistema lineal de ecuaciones

1 0 0 . . . 0 0 bn−11

0 1 0 . . . 0 0 bn−22

0 0 1 . . . 0 0 bn−33

......

. . .. . .

......

...

0 0 0 . . . 1 0 b∗n−1

0 0 0 . . . 0 1 bn

(4.14)

La eliminacion de Gauss-Jordan es uno de los metodos mas simples para la solucion de sistemas

de ecuaciones lineales, este metodo representa una gran ventaja sobre la regla de Kramer porque

disminuye considerablemente el numero de operaciones necesarias. El orden de complejidad para este

Page 92: Esquemas iterativos en paralelo con OpenMP

76 Capıtulo 4. Metodo Iterativo de Jacobi

metodo es O(n3); pero esto no es suficiente para sistemas lo suficientemente densos. Como menciona

Nakamura [28] tiene la desventaja de ser poco eficiente para un unico conjunto de ecuaciones.

Descomposicion o factorizacion LU

Este metodo es mas complejo que los dos anteriores, cabe mencionar que es una variante de la

eliminacion gaussiana y su orden de complejidad concuerda con ello O(2n3/3) [25]. Como menciona

De la Fuente [14] este metodo representa una matriz cuadrada A con dos matrices, una triangular

inferior L y otra triangular superior U , para sistemas de la forma Ax = b tal que satisfaga

A = LU (4.15)

sustituyendo (4.15) en Ax = b se tiene

LUx = b (4.16)

haciendo Ux = z y sustituyendo en (4.16) queda

Lz = b (4.17)

despejando z de (4.17) se tiene lo siguiente

z = L−1b (4.18)

retomando Ux = z y sustituyendo en (4.18) hasta tener

x = U−1z (4.19)

Como menciona Nakamura [28] para encontrar la solucion de un sistemas de n incognitas se

resuelve con dos pasos para ello se toma (4.17), el primero llamado eliminacion hacia adelante, en

este paso se obtiene el valor de z con se muestra

z1 = b1

zi = bi −

[i−1∑j=1

li,jzi

]i = 2, 3, . . . , n

(4.20)

Page 93: Esquemas iterativos en paralelo con OpenMP

4.1. Concepto 77

El segundo paso, llamado eliminacion hacia atras,

xn = znun,n

xi =zi−

n∑j=i+1

ui,jxj

ui,ii = n− 1, n− 2, . . . , 1

(4.21)

Con base a Nakamura [28] con (4.20) y (4.21) se encuentra el resultado del sistema pero hasta

este momento no se ha empleado el pivoteo; es muy importante su utilizacion en la practica. Como

menciona Kolman et al.[25] este metodo es muy utilizado porque permite resolver numericamente

sistemas de ecuaciones donde lo unico cambiante son los terminos independientes. Cabe mencionar

que este metodo se utiliza en los temas siguientes.

4.1. Concepto

El Metodo de Jacobi llamado ası en honor al matematico aleman Carl Gustav Jacob Jacobi

(1804-1851). Es considerado el metodo iterativo mas simple para resolver sistemas de ecuaciones

lineales y se aplica solo a sistemas cuadrados, es decir, a aquellos que tienen tantas incognitas

como ecuaciones. Es usado para el analisis de circuitos, para soluciones numericas de ecuaciones

diferenciales y los problemas con valor en la frontera.

Es preciso definir que es un metodo iterativo; es aquel que progresivamente va calculando apro-

ximaciones a la solucion de un problema, repitiendo el mismo procedimiento en cada iteracion a fin

de obtener una mejor aproximacion que la inicial. El proceso se repite sobre esta nueva solucion

aproximada hasta que el resultado reciente cumpla con ciertas condiciones. Los esquemas iterativos

son usados cuando se desconoce un metodo para obtener la solucion en forma exacta. Tambien se

utilizan cuando el metodo para determinar la solucion exacta requiere mucho tiempo de calculo,

cuando una respuesta aproximada es adecuada, y cuando el numero de iteraciones es relativamente

reducido.

En palabras de Burden et al.[7], Un metodo iterativo para resolver un sistema de ecuaciones

lineales de la forma Ax = b, comienza con una aproximacion inicial x(0) a la solucion x se genera

una sucesion de vectores x(k)∞k=0 que convergen a x. La aproximacion inicial x(0) esta representado

por un valor arbitrario.

Page 94: Esquemas iterativos en paralelo con OpenMP

78 Capıtulo 4. Metodo Iterativo de Jacobi

El metodo o esquema de Jacobi sirve para resolver ecuaciones lineales de la forma

Ax = b (4.22)

donde A ∈RN×N , y x, b ∈RN

Para su mejor estudio se descompone la matriz A de la siguiente forma

A = L+D + U (4.23)

donde,

L = Lower(inferior), es una matriz triangular inferior de A,

D = Diagonal, es una matriz diagonal de A y

U = Upper (superior), es una matriz triangular superior de A.

Sustituimos en (4.22) lo que se ha hecho con anterioridad, ademas sustituimos a x por su

aproximacion (x∗),

(L+D + U)x∗ = b

Distribuyendo a A ∈RN×N , y x ∈ RN tenemos

Lx∗ +Dx∗ + Ux∗ = b

Al despejar Dx∗ nos queda la siguiente ecuacion

Dx∗ = −(L+ U)x∗ + b

Llamaremos a D−1 la inversa de la matriz D, debido a

D−1 ·D = I

Para ello I es una identidad de la forma1 0 · · · 0

0 1 · · · 0...

.... . .

...

0 0 · · · 1

Page 95: Esquemas iterativos en paralelo con OpenMP

4.1. Concepto 79

Haciendo uso de la identidad, antes expuesta, despejamos hasta obtener la forma matricial del

metodo de Jacobi que se expresa a continuacion

x = −D−1(L+ U)x∗ +D−1b (4.24)

Siempre que la matriz sea diagonal dominante, la ecuacion (4.24) seguro converge a la solucion.

Una matriz se dice que es diagonalmente dominante, si y solo si en cada uno de los renglones, el

valor absoluto del elemento de la diagonal principal es mayor que la suma de los valores absolutos

de los elementos restantes del mismo renglon. A veces la matriz de un sistema de ecuaciones lineales

no es diagonalmente dominante pero cuando se cambian el orden de las ecuaciones y las incognitas

el nuevo sistema puede ser matriz de coeficientes diagonalmente dominante; es decir,

0 <

n∑j=1,j 6=i

|aij | < |aii| i = 1, 2, . . . , n (4.25)

Cuando se aplica Jacobi donde la matriz no es diagonalmente dominante es suficiente para que no

exista garantıa de convergencia. Sin embargo, en algunos casos sera posible re-ordenar las incognitas

de otra manera de tal forma que la nueva matriz de coeficientes sea diagonalmente dominante. Esto

se puede detectar revisando todos los posibles ordenamientos de las incognitas y ver como es la

matriz resultante. Claro que esto conlleva un buen numero de pruebas puesto que el numero posible

de ordenamientos en n-variables es de (n− 1)! pero cuando n es reducido es sencillo.

La ecuacion (4.24) se puede representar de la siguiente forma iterativa y converge a la solucion:

xk+1 = −D−1(L+ U)xk +D−1b, ∀xk ∈R y k = 1, 2 . . . nx0, x1, x2, . . . , xn converge a la solucion

Lo cual se puede expresar como,

xk+1i =

1

aii

bi − n∑j=1j 6=i

aijxkj

(4.26)

Uno de los principales problemas de los metodos iterativos es la garantıa de que el metodo va a

converger, es decir, va a producir una sucesion de aproximacion cada vez mas efectiva a la solucion.

En el caso del metodo de Jacobi no existe una condicion exacta para la convergencia. Lo mejor es

Page 96: Esquemas iterativos en paralelo con OpenMP

80 Capıtulo 4. Metodo Iterativo de Jacobi

una condicion que garantice la convergencia pero en caso de no cumplirse, la sucesion puede o no

converger; la condicion es la siguiente: Si la matriz de coeficientes original del sistema de ecuaciones

es diagonalmente dominante (4.25), el metodo de seguro converge.

Para determinar cuando la sucesion x0, x1, x2, . . . , xn converge a la solucion se emplean crite-

rios de paro; es aquı donde se denomina aproximacion al resultado, ya que se utiliza un error (η)

para definir el grado de aproximacion del resultado. El valor definido para η no es constante sino

esta adherido al tipo de problema y dependera directamente del grado de exactitud que se desee

obtener. Hay que tener presente que conforme el rango de error disminuya (η → 0), el tiempo de

calculo aumentara. Algunos criterios de paro son la norma infinita del residual y la de la diferencia

de x en la iteracion actual respecto a la iteracion anterior como se muestra a continuacion,

‖xk+1 − xk‖∞ < η (4.27)

Llevar a cabo (4.27) resulta trivial y es por demas profundizar. La norma infinita del residual

en la k-esima iteracion se expresa como,

‖rk+1‖∞ < η (4.28)

En ambos casos, (4.27) y (4.28), el valor para η debe ser pequeno (generalmete 10−3) esto

representa el margen de error que tendra la aproximacion. Para valores de η muy pequenos (10−9,

por mencionar) la cantidad de iteraciones de procesamiento que se llevaran a cabo es un punto a

considerar, ya que con esto la resolucion del problema tardarıa mucho tiempo.

La definicion del algoritmo del esquema iterativo de Jacobi, con base a lo que se ha mencionado,

se presenta a continuacion.

Algoritmo 4.1 Algoritmo del Metodo de Jacobi

Esta definido por los siguientes seis pasos:

1. Hacer k = 0

2. Mientras (4.27) o (4.28) se tornen falsas llevar a cabo los pasos 3-5

3. Hacer

xi =

bi −n∑

j=1j 6=iaijx

∗j

aiii = 1, 2, . . . , n

Page 97: Esquemas iterativos en paralelo con OpenMP

4.2. Codificacion del metodo de Jacobi en C 81

4. para i = 1, 2, 3, . . . , n hacer x∗i = xi

5. Aumentar el valor de k en uno (k = k + 1)

6. Mostrar los valores de (x1, x2, x3, . . . , xn)

Durante esta seccion se planteo el esquema de Jacobi ello permite tener las bases para crear una

aplicacion que resuelva numericamente un sistema lineal de ecuaciones mediante este metodo. En

los siguientes temas se lleva a cabo esta tarea, en primera instancia para una ejecucion no paralela

y despues en una que sea ejecutada por multiples nucleos de forma simultanea.

4.2. Codificacion del metodo de Jacobi en C

En esta seccion se realiza una primera implementacion del esquema de Jacobi con base al al-

gorimo 4.1 desarrollado en el tema pasado. La aplicacion es realizada por etapas. El primer paso

consiste en escribir el codigo en lenguaje C. Cuando sea cumplido ese paso, se procede a optimizar

la aplicacion mediante tecnicas de programacion ası como disminuir los cuellos de botella; con ello

el rendimiento aumentara. Para finalizar se debe convertir esa aplicacion serial en una paralela, la

cual pueda ser ejecutada de forma paralela en computadoras multinucleo de memoria compartida.

En el siguiente codigo de la figura 4.1 se describe el primer paso, implementar el metodo de Jacobi

de acuerdo al algoritmo 4.1.En la figura 4.1 se describe un fragmento de codigo de una primera implementacion. Si comple-

mentamos el codigo anterior, ya tenemos un programa que resuelve sistemas de ecuaciones lineales

por el metodo de Jacobi. Cuando se implementan los algoritmos en programacion se busca que este

pueda ser ejecutada lo mas rapido que sea posible, para reducir el tiempo de procesamiento, esto es

determinante para conocer la calidad de nuestro programa y es por ello que adaptar la interpretacion

de algoritmo para que se adapte a los recursos que se tienen se vuelve prioridad.

Con lo ya mencionado nos damos cuenta que la implementacion anterior no cumple totalmente

con esos planteamientos, es decir no es una opcion para el problema, a consecuencia se realizara una

adaptacion. Ello se realiza en los temas posteriores.

4.2.1. Simplificando codigo

En esta seccion se realiza una modificacion de la ecuacion iterativa de Jacobi (4.26) para simpli-

ficar el codigo y quitar el cuello de botella provocado por la ejecucion de la condicion en el producto

Page 98: Esquemas iterativos en paralelo con OpenMP

82 Capıtulo 4. Metodo Iterativo de Jacobi

Primera Implementacion de Jacobi

for( k = 0; ; k++)

for( i = 0; i < n; i++)

suma = 0.0;

for( j = 0; j < n; j++)

if( j != i)

suma += A[i][j] * x_old[j];

x[i] = (b[i]-suma)/A[i][i];

if(norma_Infinita(x, x_old, n) < E)

break;

clonar(x_old, x, n);

Figura 4.1: Primera implementacion del metodo de Jacobi en lenguaje C.

punto que impera en la ecuacion mencionada.

Como es sabido el tiempo de procesamiento de una sentencia (if) es mayor a una operacion y

como se encuentra anidado, es decir se ejecutara n2 veces por iteracion, sera necesario removerlo,

para ello recordemos (4.26) que se muestra a continuacion,

xk+1i =

1

aii

bi − n∑j=1,j 6=i

aijxkj

Para anular la sentencia (j 6= i), debemos quitarla de∑n

j=1,j 6=i aijxkj partiendo de la siguiente

ecuacionn∑j=1

aijxkj = a1,1x

k1 + a1,2x

k2 + · · ·+ an,nx

kn i = 1, 2, . . . , n (4.29)

Con (4.29) deducimos los siguiente

n∑j=1,j 6=i

aijxkj =

n∑j=1

aijxkj − aiixki i = 1, 2, . . . , n (4.30)

Page 99: Esquemas iterativos en paralelo con OpenMP

4.2. Codificacion del metodo de Jacobi en C 83

Esquema de Jacobi en lenguaje C

for( k = 0; ; k++)

for(i = 0; i < N; i++)

suma = 0.0;

for( j = 0; j < N; j++)

suma += A[i][j] * x_old[j];

x[i] = ( (b[i] - suma) / A[i][i] ) + x_old[i];

norma = normInfinita(x, x_old, n);

if(norma < E)

break;

clonar(x_old, x, n);

Figura 4.2: Codigo en lenguaje C del esquema de Jacobi.

Sustituimos la igualdad en (4.26) y tenemos,

xk+1i =

1

aii

bi − n∑j=1

aijxkj − aiixki

i = 1, 2, . . . , n (4.31)

A continuacion simplificamos (4.31) para obtener

xk+1i =

1

aii

bi − n∑j=1

aijxkj

+1

aiiaiix

k i = 1, 2, . . . , n (4.32)

Ello puede ser expresado como se muestra a continuacion

xk+1i =

1

aii

bi − n∑j=1

aijxkj

+ xki i = 1, 2, . . . , n (4.33)

Una vez que se ha removido la condicion (j 6= i) se dice que se tiene una adaptacion en (4.33);

esta nueva adaptacion es mas rapida que la de (4.26) y es facilmente demostrable. Antes de ello es

preciso definir los cambios que sufre el primer codigo a consecuencia de los anterior. Ello se describe

en la figura 4.2.

Page 100: Esquemas iterativos en paralelo con OpenMP

84 Capıtulo 4. Metodo Iterativo de Jacobi

Figura 4.3: Porcentaje del tiempo de ejecucion del metodo de Jacobi con y sin sentencia if.

Con la codificacion de la figura 4.2 se tiene un programa que es ejecutado en un nucleo sin

contratiempos, y solamente con la necesidad de introducir las ecuaciones de acuerdo a las condiciones

que imponen el metodo; es decir es una version compacta de un programa que resuelve sistemas de

ecuaciones lineales, y solo se muestra la seccion del programa donde se realizan las iteraciones. En

el momento en que la ejecucion llegue a ese punto, debe ser evaluada para conocer si cumple las

imposiciones del Metodo de Jacobi: si la matriz de coeficientes es estrictamente diagonal dominante.

A continuacion se muestra que efectivamente la segunda codificacion aumenta el rendimiento del

programa y que de esta forma estamos aumentando el desempeno del programa. Para esta ocasion

se utilizo una matriz A suficientemente densa, con el fin de hacer mas notable la diferencia entre las

implementaciones; tambien tomemos en cuenta que se definio el numero de iteraciones (k = 100) a

fin de reducir el tiempo de ejecucion del programa, es decir, el resultado que se presenta es con el

objetivo de comparar cuando se tiene la condicion (if) y cuando se ha removido; no tanto a encontrar

la solucion del sistema de ecuaciones lineales, para este caso en particular. En la tabla 4.1 se realiza

la ejecucion del programa sin utilizar alguna de las banderas de compilacion.

Page 101: Esquemas iterativos en paralelo con OpenMP

4.2. Codificacion del metodo de Jacobi en C 85

Tabla 4.1: Metodo iterativo de Jacobi: primera evaluacion de rendimiento, observamos el porcentajede la reduccion del tiempo en ejecucion cuando se remueve la condicion (if).

Primera Evaluacion de RendimientoSin Bandera de Compilacion

Valor de Tiempo de Ejecucion Tiempo de Ejecucion Reduccion deN Con if (segundos) Sin if (segundos) Tiempo ( %)

100 0.006 0.005 15.5200 0.024 0.020 13.9300 0.056 0.046 17.4400 0.101 0.082 18.7500 0.159 0.127 19.8600 0.230 0.183 20.3700 0.315 0.249 21.7800 0.413 0.326 21.0900 0.526 0.414 21.2

1000 0.657 0.517 21.32000 2.461 2.084 15.33000 5.653 4.690 17.04000 10.221 8.343 18.45000 16.145 13.030 19.36000 23.416 18.761 19.97000 32.086 25.553 20.48000 42.125 33.386 20.79000 53.517 42.299 21.0

10000 66.229 52.198 21.2

Page 102: Esquemas iterativos en paralelo con OpenMP

86 Capıtulo 4. Metodo Iterativo de Jacobi

Vista general de Jacobi optimizado

for( k = 0; ; k++)

for(i = 0; i < N; i++)

dotVect = dot_vector(A[i], x_old, N);

x[i] = (b[i] - dotVect) / A[i][i] + x_old[i];

norma= normInfinita(x, x_old, n);

if(norma < E)

break;

clonar(x_old, x, n);

Figura 4.4: Codigo general de Jacobi optimizado.

Con base a lo que se observa en la tabla 4.1 decimos que la sentencia (if) es un problema de

rendimiento, el cual se torna mas grave conforme la matriz A se hace mas densa. Como se muestra,

representa un problema muy serio de rendimiento ya que en promedio se lleva la quinta parte del

tiempo de ejecucion. En la figura 4.3 se muestra en forma de grafica los resultados expuestos, en

ella si ilustra el porcentaje que se reduce cuando se elimina la sentencia mencionada.

Debido a lo anterior se concluye que un programa que tiene un gran numero de condiciones if

y que no sean fundamentalmente necesarias, se cataloga como un programa de bajo rendimiento.

Para este caso, remover la condicion antes mencionada represento una tarea muy facil y al mismo

tiempo resulto ser una enorme ventaja, esto no quiere decir que para absolutamente todos los casos,

el comportamiento sea semejante; pero en la mayorıa de los caso eso ocurrira. Este es un primer

paso para ir poco a poco refinando un programa, mas adelante se abordan distintas maneras para

aumentar el rendimiento del programa, y que se pueden implementar en otros problemas.

4.2.2. Optimizacion de codigo

En este apartado se realiza una optimizacion del codigo creado en la segunda version. Exclusi-

vamente en el producto punto, las cuales fueron estudiadas en el capıtulo anterior. El codigo de la

segunda implementacion unicamente se modifica el producto punto por su equivalente con unroll

looping y MMX. Se mide el desempeno computacional que tienen cada uno de ellos.

Page 103: Esquemas iterativos en paralelo con OpenMP

4.3. Metodo de Jacobi en paralelo con OpenMP 87

Figura 4.5: Tiempos de ejecucion de Jacobi en serie, versiones [Canonica, Unroll4, MMX] paran = 5000.

En la figura 4.4 se describe un codigo general que implementa el esquema de Jacobi. La funcion

“dot vector” representa el nombre de la funcion optimizada que llevara a cabo la multiplicacion de

dos vectores. Para este caso Unroll-4 o MMX que corresponde a las figuras 3.4 y 3.19 respectivamente

(Estas funciones se estudian con mas detalle en el capıtulo anterior).

En la figura 4.5 se ilustra el resultado de los tiempos de ejecucion de las tres versiones del

Esquema de Jacobi (Canonica, Unroll-4 y MMX) en ella se observa de una forma muy clara que el

desempeno realizado por la funcion MMX es muy superior a sus semejantes.

Con base a los resultados obtenidos en la figura 4.5 se concluye lo siguiente; el paradigma de

programacion MMX tiene un mayor desempeno computacional que Unroll-4, y se ve reflejado de

manera mas positiva bajando a la mitad (MMX) y a dos terceras partes (Unroll-4) el tiempo de

ejecucion implementando las tecnicas estudiadas en el capıtulo anterior. Este rango de ahorro de

tiempo es muy bien recibido por parte del usuario final. Sin embargo, esto no significa que para la

version en paralelo ocurra exactamente lo mismo. Para una aplicacion en serie es mejor la tenica

MMX.

4.3. Metodo de Jacobi en paralelo con OpenMP

En esta seccion se hace en paralelo la version canonica de Jacobi de la figura 4.4 utilizando la

directiva de OpenMP. Cuando se codifico el Metodo de Jacobi para un nucleo resulta obvio que

Page 104: Esquemas iterativos en paralelo con OpenMP

88 Capıtulo 4. Metodo Iterativo de Jacobi

el rendimiento que se obtiene no cumple con los requerimientos actuales. Los cuales consisten en

explotar al maximo los recursos de la computadoras a las que se tengan acceso. El programa de

la mencionada figura solo explota un procesador cuando se debe explotar todos los procesadores

(2, 4, 8) mediante el uso de programacion en paralelo. El principal beneficio de este paradigma es

la reduccion del tiempo de ejecucion de las aplicaciones con la distribucion de cargas de trabajo a

cada uno de los procesadores de la computadora. En la figura 4.6 se muestra el resultado obtenido

de una primera implementacion de Jacobi en paralelo.

Version canonica en paralelo de Jacobi

for(k = 0; ; k++)

#pragma omp parallel for default(none) \

shared(x,x_old,b,A,N) private(i,dotVect)

for(i = 0; i < N; i++)

dotVect = dot_can(A[i], x_old, N);

x[i] = (b[i] - dotVect) / A[i][i] + x_old[i];

norma = normInfinita(x, x_old, N);

if(norma < E)

break;

clonar(x_old, x, N);

Figura 4.6: Codigo de version canonica en paralelo de Jacobi.

El codigo de la figura 4.6 es una primera implementacion del Esquema de Jacobi en paralelo

con OpenMP. En la fraccion de codigo tenemos una funcion dot can(float *a, float *b, int n) que

realiza la multiplicacion de dos vectores de forma tradicional (canonica). Ademas en este programa

no se desarrolla todo el codigo necesario para dos funciones. La primera funcion normInfinita(float*

a,float* b,int n) calcula la norma infinita de la diferencia de los vectores argumento (a,b) de la

funcion. La segunda subrutina clonar(float* a,float* b,int n) en esta funcion se guardan los valores

del vector b al vector a, es decir a(1 : n) = b(1 : n). Cabe mencionar que este codigo terminara su

ejecucion si y solo si se cumple la condiccion de paro; la norma infinita del valor actual de x menos

el anterior, es decir (‖xk+1 − xk‖∞).

En la figura 4.7 se ilustra el speed-up que desempena el codigo de la figura 4.6. En ella se observa

Page 105: Esquemas iterativos en paralelo con OpenMP

4.3. Metodo de Jacobi en paralelo con OpenMP 89

102

103

104

0

1

2

3

4

5

6

Valor de N

Speed−

up

1−Core

2−Cores

4−Cores

8−Cores

Figura 4.7: Speed-up del metodo de Jacobi en paralelo en su version canonica.

el incremento de la velocidad de ejecucion cuando se incrementa el numero cores. El comportamiento

del speed-up es comparable al que se registro en la mutiplicacion matriz vector. Para valores de n

reducidos la ganancia disminuye conforme n → 0; aunado a ello cuanto mas grande sea el numero

de cores la ganancia disminuye. En el caso contrario, cuando n es mayor el aumento del speed-up

crece casi de forma proporcional para los casos de 2 y 4 cores; en el otro caso (8 cores) el incremento

es menor; aproximadamente 6 cuando deberıa estar cercano a los 8x; ello se debe al diseno de la

computadora empleada, esta cuenta con 2 procesadores de 4 cores cada uno de ellos, al utilizar el

total de 8 cores se vuelve imprescindible el uso del tercer nivel de cache el cual esta mas lejano. Ese

retraso en el acceso a los datos es el principal motivo por el cual no se cumple con lo teoricamente

esperado; Sin embargo, estos resultados son congruentes con la ley de Amdahl.

Con base a los resultados obtenido es concluyente que la version canonica de Jacobi es altamente

paralelizable lo cual se lleva a cabo solo con definir la directiva de OpenMP adecuada para el

algoritmo. Al igual que la multiplicacion de una matriz por un vector en este algoritmo no se presenta

la dependencia de operaciones; esto con base al planteamiento que sea realizado y principalmente

a las definiciones del metodo lo cual sea indica en la seccion siguiente. Realizar una aplicacion que

en terminos de computacion se mas eficiente, se hara uso de las tecnicas que en temas anteriores se

Page 106: Esquemas iterativos en paralelo con OpenMP

90 Capıtulo 4. Metodo Iterativo de Jacobi

trataron, como es el caso de la tecnologıa MMX.

4.4. Evaluacion de algoritmo en paralelo

En el capıtulo anterior se realizo una funcion para resolver el producto de una matriz por un

vector la cual implementa paralelismo a nivel de datos. Esta funcion es la que mejor rendimiento

presenta. Con base a la ecuacion de Jacobi (4.33) se utiliza dicha funcion para optimizar la ejecucion

del programa.

Como resultado de ello se tiene el programa como el que se describe en la figura 4.5 pero

realizando cambios significativos, en primer lugar incluimos la directiva pragma de la figura 4.6

esto indicara que la siguiente sentencia for sera tratada en paralelo. El resto consiste en cambiar

el nombre de la funcion “dot can” por “dot mmx” que corresponde a la subrutina realizada en la

figura 3.19 del capıtulo anterior (pagina 55). El resultado que se obtiene despues de realizar las

modificaciones planteadas; es una funcion que implementa el esquema iterativo de Jacobi utilizando

la tecnica de MMX. Como se estudio en el tema pasado la escalabilidad de MMX es diferente de la

version canonica, en la figura 4.8 se ilustra este hecho.

102

103

104

0

0.5

1

1.5

2

2.5

3

3.5

Valor de N

Speed−

up

1−Core

2−Cores

4−Cores

8−Cores

Figura 4.8: Speed-up del metodo de Jacobi en paralelo en su version MMX.

Page 107: Esquemas iterativos en paralelo con OpenMP

4.4. Evaluacion de algoritmo en paralelo 91

En la figura 4.8 se muestra un resultado muy claro, la escalabilidad de esta version es considera-

blemente mas pobre que la canonica. La ganancia de ejecutar con 4 y 8 cores es casi insignificante

con respecto a 2 cores y a lo teoricamente esperado, aun para un tamano de n relativamente ma-

yor; el speed-up para 4 cores es en promedio 2.7x mientras que para 8 cores es de 2.9x cuando

teoricamente debiera ser de 4x y 8x respectivamente. La consistencia de la escalabilidad comparada

con el problema Ax persiste. Al igual que en la version canonica para valores de 0 < n < 300 es

contraproducente el uso de mas de un procesador para la solucion del problema, para el resto de los

casos la situacion mejora conforme la matriz A se vuelve mas densa. Es claro que de cierto modo

la escalabilidad proporcional se presenta para la ejecucion en dos cores, en los valores 4000-10000

de n; el speed-up es insignificantemente menor al valor ideal 2x.

Con los resultados obtenidos es concluyente que la version canonica de Jacobi es mas escalable

que su version MMX; sin embargo, esta ultima tiene un mejor desempeno (para las condiciones de

ejecucion ya mencionadas). Estos resultados son muestra solida del beneficio de utilizar algoritmos

paralelos.

A lo largo del estudio del esquema iterativo de Jacobi se realiza una optimizacion para retirar

una sentencia if con lo que reducimos en 20 % el tiempo de ejecucion. Este cambio mencionando

representa un punto de partida para la optimizacion pero mas alla de ello permite remover una

condicion innecesaria para realizar la programacion en paralelo. Tomando la tecnica de programacion

MMX implementada en la funcion escrita en el capıtulo anterior se tienen resultados con un speed-

up de 3.0x para 8 nucleos, esta funcion es la que mejor desempeno computacional presento (en

el capıtulo 3). Cabe senalar que al igual que el tema anterior la version canonica tiene una mejor

escalabilidad con un promedio de 5.5x para 8 nucleos y para 2 y 4 cores una escalabilidad de 2.0x

y 3.8x lo cual representa practicamente una escalabilidad lineal.

Page 108: Esquemas iterativos en paralelo con OpenMP
Page 109: Esquemas iterativos en paralelo con OpenMP

Capıtulo 5Metodo de Gauss-Seidel

5.1. Concepto

Es preciso definir que es un metodo iterativo. Es aquel que progresivamente va calculando

aproximaciones a la solucion de un problema; repitiendo el mismo procedimiento, en cada iteracion,

a fin de obtener una mejor aproximacion que la inicial; el proceso se repite sobre esta nueva solucion

aproximada hasta que el resultado reciente cumpla con ciertas condiciones. Se desarrollan este tipo

de esquemas numericos cuando se desconoce un metodo que permita resolver el problema con una

solucion exacta. Tambien se utilizan cuando el metodo para determinar la solucion exacta requiere

mucho tiempo de calculo, cuando una respuesta aproximada es adecuada, y cuando el numero de

iteraciones es relativamente reducido.

El esquema de Gauss-Seidel (GS) es uno de los metodos iterativos mas populares a razon de

su facil aplicacion e implementacion en las computadoras. Consiste en despejar una incognita por

ecuacion y el resultado es utilizado en la misma iteracion para el calculo de las incognitas conse-

cuentes. Este metodo esta basado teoricamente en el esquema de Jacobi pero tienen diferencias muy

marcadas lo cual hace de GS mas eficiente.

La gran diferencia entre los metodos de Jacobi con respecto Gauss-Seidel es que este ultimo

utiliza los nuevos valores que se van obteniendo, durante la presente iteracion, para encontrar los

valores del resto de las incognitas; esto representa el motivo por el cual GS es generalmente superior

que Jacobi.

Al igual que en el metodo de Jacobi si la matriz de coeficientes es diagonal dominante [ver (4.25)

93

Page 110: Esquemas iterativos en paralelo con OpenMP

94 Capıtulo 5. Metodo de Gauss-Seidel

de la pagina 79] la convergencia es segura, en caso contrario puede o no converger. Como infiere

Gomez et al.[18], cuando no hay dominio diagonal, lo que se recomienda es hallar el coeficiente de

la matriz de mayor valor absoluto y despejar de ese renglon en el que se encontro, a la incognita

correspondiente, luego el procedimiento se repite con las restantes incognitas del sistema hasta

terminar.

Como menciona Karniadakis et al.[23], normalmente el Metodo de Gauss-Seidel converge dos

veces mas rapido que el de Jacobi; y cuando converge generalmente lo hace de forma lineal.

Con lo que se ha dicho con anterioridad, se procede a descomponer la matriz A de la ecuacion

Ax = b de la siguiente forma.

D − L− U = A (5.1)

Al sustituir la matrix A por su equivalente(5.1) tenemos lo siguiente

(D − L− U)x = b (5.2)

Realizando las siguientes operaciones para despejar x y de ese modo encontrar la forma matricial

del Metodo Iterativo de Gauss-Seidel,

(D − L)x− Ux = b

(D − L)x = Ux+ b

Por ultimo se despeja x para tener

x = (D − L)−1Ux+ (D − L)−1b (5.3)

En (5.3) se representa la forma matricial del Metodo Iterativo de Gauss-Seidel y la podemos

representar la siguiente forma iterativa y converge a la solucion x1, x2, . . . , xk para cualquier vector

inicial x0 ∈ RN

xk+1 = (D − L)−1Uxk + (D − L)−1b ∀xk ∈ RN , k = 1, 2, . . . , n (5.4)

Page 111: Esquemas iterativos en paralelo con OpenMP

5.1. Concepto 95

donde, (D − L)−1 es la inversa de (D − L), es decir

(D − L)−1(D − L) = I (5.5)

siendo I una identidad de la forma,

1 0 · · · 0

0 1 · · · 0...

.... . .

...

0 0 · · · 1

de forma compacta, tenemos

xk+1 = Hxk + b (5.6)

donde, H = (D − L)−1U y b = (D − L)−1b

A continuacion se muestra la ecuacion iterativa del Metodo de Gauss-Seidel

xk+1i = − 1

aii

i−1∑j=1

aijxk+1j +

n∑j=i+1

aijxkj

+1

aiibi (5.7)

donde, A ∈RN×N , y x, b ∈RN

El Metodo de Gauss-Seidel es facil para su aplicacion como se mostrara mas adelante. Como se

puede observar al comparar las ecuaciones iterativas del esquema de Jacobi (4.33) y la de este metodo

(5.7) notamos que son muy semejantes; lo importante aquı no es eso sino, encontrar las diferencias

entre ambos. La mas notoria es que en Gauss-Seidel se utilizan los nuevos valores obtenidos para

calcular el resto en la iteracion actual; mientras que en Jacobi se utilizan unicamente los valores

correspondientes a la iteracion anterior. El hecho de utilizar todos los nuevos valores, se vuelve muy

practico en computacion porque no solamente se va a reducir el numero de iteraciones necesarias

para converger, sino que ademas se utiliza una cantidad menor de memoria; esta propiedad nos da

la ventaja de guardar los nuevos valores en el espacio donde se encuentran los valores anteriores.

Con base a lo mencionado se puede describir el algoritmo de programacion para el metodo, en el

algoritmo 5.1 se indica.

Page 112: Esquemas iterativos en paralelo con OpenMP

96 Capıtulo 5. Metodo de Gauss-Seidel

Algoritmo 5.1 Algoritmo del Metodo de Gauss-Seidel

Esta definido por los siguientes cinco pasos:

1. Hacer k = 0

2. Mientras (4.27) o (4.28) sea falso repetir los pasos 3,4.

3. Hacer

xi =

bi −n∑

j=1j 6=iaijxj

aiii = 1, 2, . . . , n

4. Hacer k = k + 1

5. Mostrar los valores de (x1, x2, x3, . . . , xn)

Con la ayuda del algoritmo 5.1 se puede escribir el codigo de una funcion que implementa este

metodo. Si comparamos este algoritmo con el de Jacobi encontramos una diferencia principal, en

este metodo solo se utiliza una variable x con lo cual se ahorra el proceso de actualizar los datos

(en Jacobi xold = xnew). En los temas posteriores se analizan numericamente las diferencias entre

ambos metodos.

5.2. Programacion en lenguaje C

En esta seccion se realiza la implementacion computacional del Metodo de Gauss-Seidel con

Lenguaje C. Tomando la ecuacion iterativa de G-S (5.7) se realiza el codigo de la figura 5.1 para

una version canonica.Comparando esta implementacion con la del metodo de Jacobi, antes de hacerla paralela y

de utilizar el procesamiento vectorial, notamos que las diferencias en el codigo son mınimas, esto

no significa que el resultado sera semejante. Como se observa escribir el codigo para el metodo

de Gauss-Seidel es por demas sencillo. Cabe mencionar que el codigo de la figura 5.1 utiliza dos

vectores para x (x y x old) esto se debe exclusivamente por la condicion de paro. El vector x old se

utiliza para almacenar los valores de la iteracion anterior, ello para despues utilizarlo en el calculo

de la norma infinita de la diferencia de la iteracion actual respecto a la anterior ‖xk+1 − xk‖∞. Es

importante destacar que existen mas condiciones de paro donde no es necesario este vector.

Como menciona Burden et al.[7], el Metodo Iterativo de Gauss-Seidel es una mejora hecha al

esquema de Jacobi. A esto se debe la similitud, muy marcada, entre estos esquemas numericos, los

cuales en terminos de error arrojan resultados muy similares.

Page 113: Esquemas iterativos en paralelo con OpenMP

5.3. Codificacion en paralelo 97

Codificacion de Gauss-Seidel

for(k = 0; ; k++)

for(i = 0; i < n; i++)

x_old[i] = x[i];

suma = 0.0;

for(j = 0; j < n; j++)

suma += A[i][j] * x[j];

x[i] = (b[i] - suma)/A[i][i] + x[i];

if(nom_inf(x,x_old) < E)

break;

Figura 5.1: Metodo de Gauss-Seidel en lenguaje C, version canonica.

A lo largo de todo el documento se ha demostrado el deseo de que las aplicaciones sean paralelas,

con el fin de reducir los tiempo de ejecucion y ası aumentar el rendimiento de las aplicaciones en

general. Al igual que con el esquema numerico anterior, en temas consecuentes se hara la implemen-

tacion en paralelo del Metodo de Gauss-Seidel con el fin de medir la escalabilidad y rendimiento de

la aplicacion.

5.3. Codificacion en paralelo

La similitud entre los metodos de Gauss-Seidel y de Jacobi hace evidente una similitud muy

marcada en la programacion serial y paralela para ambos. Cuando la programacion es para la

arquitectura de memoria compartida el codigo para ambos metodos es tecnicamente muy similar.

Sin embargo, no ocurre los mismo para una ejecucion en una arquitectura con memoria distribuida;

las diferencias se centran en la actualizacion en tiempo real de los nuevos valores calculados que

deben estar disponibles para realizar el calculo del resto. Para implementar GS en sistemas de

memoria distribuidas se puede utilizar un algoritmo conocido como Black-Red el cual consiste en

dividir la matriz en bloques negros y rojos tan grandes como sean necesarios, la iteracion se divide

en dos etapas; para actualizar los bloques de los dos colores [23].

El objeto del presente documento es tratar la programacion en paralelo para computadoras con

Page 114: Esquemas iterativos en paralelo con OpenMP

98 Capıtulo 5. Metodo de Gauss-Seidel

arquitectura de memoria compartida. En la figura 5.2 se muestra el codigo de una aplicacion que

del metodo de Gauss-Seidel en paralelo con OpenMP. Como se ha mencionado en este capıtulo los

dos metodos (Jacobi y Gauss-Seidel) son tan semejantes que la directiva utilizada en el primero es

muy similar a la utilizada en el segundo; con lo cual el esfuerzo tambien es similar.

Codificacion en paralelo de Gauss-Seidel

for(k = 0; ; k++)

clonar_sv(x_old,x,n);

#pragma omp parallel for default(none) \

private(i,dotVect) shared(A,b,x,n)

for ( i = 0; i < n; i++ )

dotVect = vector_dot(A[i],x,n);

x[i] = (b[i] - dotVect) / A[i][i] + x[i];

norma = norma_inf(x,x_old,n);

if(norma < E)

break;

Figura 5.2: Metodo de Gauss-Seidel con OpenMP.

Para comprender el codigo de la figura 5.2 es necesario analizarlo de un forma mas detallada.

En los siguientes puntos se analizan las lıneas mas importantes:

1. clonar sv(x old, x, n): en esta funcion se guardan todos los elementos del vector x al

vector x old, es decir, x old(1 : n) = x(1 : n). Cabe senalar que esta lınea y el vector x old

estan presentes unicamente por la condicion de paro que se utiliza. Al igual que los ejemplos

anteriores, la condicion de paro es la norma infinita de la diferencia de los valores de la iteracion

presente (k + 1) menos la iteracion anterior (k), es decir ‖xk+1 − xk‖∞.

2. dotVect = vector dot(A[i],x,n): en esta lınea lo importante es la funcion llamada

vector dot esta funcion tiene la siguiente forma “float vector dot(float*,float*,int)” en ella se

regresa el valor de la siguiente operacion.

n∑j=0

xjyj

Page 115: Esquemas iterativos en paralelo con OpenMP

5.3. Codificacion en paralelo 99

Cabe senalar que durante este documento se han realizado diferentes codigos que resuelven la

operacion en cuestion (En el capıtulo 3). Todas esas funciones tienen la misma nomenclatura

que vector dot, por lo cual podemos elegir entre esas funciones.

En el metodo de Jacobi no existe la dependencia de operaciones para calcular el i-esimo valor

de la iteracion actual (xk+1i ). Ello convierte a Jacobi en un metodo facil para paralelizar. Para el

caso de Gauss-Seidel sı existe la dependencia de operaciones; para calcular xk+1i se necesitan los

valores actuales de todos los elementos de [xk+1(1 : i− 1)]. El codigo de la figura 5.2 no cumple con

ello; solo una aplicacion serial cumple estrictamente con el algoritmo original. Para comprender el

funcionamiento de la aplicacion se ilustra en la figura 5.3 como se puede descomponer un vector x

en dos subdominios para que cada uno de ellos sea calculado por un procesador.

Figura 5.3: Descomposicion del vector solucion x para dos procesadores.

Como se observa en la figura 5.3 cuando el procesador dos calcula los valores de su subdominio

(4:7) necesita los valores (0:4) que no estan completamente actualizados; durante una ejecucion

paralela ambos subdominios son actualizados al mismo tiempo. Para el caso de la figura en cuestion

se utilizan dos dominios haciendo referencia a que unicamente se utilizo dos procesadores, cuando

este numero aumente; la cantidad de subdominios debe ser identico. Es preciso mencionar que

mientras mas cercas se encuentre un subdominio de n; la cantidad de valores actualizados para el

calculo de nuevos valores sera menor. Con base a Candra et al.[10] esto se trata de una dependencia

no-removible.

Este hecho nos permite inferir que la cantidad de iteraciones aumentara para cumplir con la

condicion de paro. Para determinar la diferencia en la cantidad de iteraciones que ha cambiado,

resulta muy practico determinarlo mediante un programa. Ademas debe medirse si el proceso con-

verge a la misma solucion en serie que en paralelo, esto determinara que el resultado no se altera lo

cual es de vital importancia para la programacion en paralelo.

Para determinar si la cantidad de iteraciones cambia significativamente se evalua el codio de la

Page 116: Esquemas iterativos en paralelo con OpenMP

100 Capıtulo 5. Metodo de Gauss-Seidel

figura 5.2 con los siguientes parametros: el vector inicial sera nulo, es decir x0(1 : n) = 0. Aunado a

ello se utilizo presicion simple para la representaciones de los numero reales. Para tener un panorama

mas claro es necesario especificar los valores que seran utilizados en la matriz de coeficientes para

todos lo casos es tridiagonal con la siguiente forma:

An×n =

2.01 1 0 0 · · · 0

1 2.01 1 0 · · · 0

0 1 2.01 1 · · · 0... 0

. . .. . .

. . ....

0... 0 1 2.01 1

0 0 · · · 0 1 2.01

(5.8)

Como se puede observar la matriz A es sensiblemente diagonal dominante, lo cual aumenta el

radio espectral de la matriz y por ende permite acrecentar el numero de iteraciones; ello con el fin

de maximizar la diferencia. Como menciona Arnal y Penades [3, 33] el radio espectral de una matriz

determina la rapidez de convergencia para cualquier metodo iterativo; cuanto menor sea el radio

espectral, el sistema convergera mas rapido.

Tabla 5.1: Metodo de Gauss-Seidel en paralelo; iteraciones para converger.

Gauss-Seidel en paraleloiteraciones para converger

Valor de Numero de iteraciones por coreN 1 Core 2 cores 4 cores 8 cores

100 808 808 809 820200 981 980 980 983400 1073 1073 1073 1070600 1057 1057 1057 1054800 1043 1043 1043 1042

1000 1075 1075 1075 10772000 1097 1097 1097 10954000 1098 1098 1098 10986000 1121 1121 1121 11218000 1097 1097 1097 1093

10000 1112 1112 1112 1112

Page 117: Esquemas iterativos en paralelo con OpenMP

5.3. Codificacion en paralelo 101

En la tabla 5.1 se muestran los resultados que se obtienen con el numero de iteraciones para

cada valor de n. Conforme a estos resultados el numero de iteraciones con uno y dos cores es

practicamente invariable al igual que con cuatro nucleos; lo que significa que la convergencia del

metodo no crece. Para el caso de ocho cores ya existe una diferencia mas marcada que las anteriores;

la mayor diferencia para la ejecucion con ocho nucleos es para una matriz cuadrada con n = 100,

donde el aumento del numero de iteraciones es aproximadamente 1.5 %, tomando los siguientes

valores para la matriz (n = 200 y n = 400) donde las diferencias porcentuales son 0.3 % y -0.3 %

respectivamente. Con base a estos resultados se puede inferir que mientras la matriz sea mas pequena

es mas conveniente resolverla con una menor cantidad de procesadores. Para el resto de las matrices

(n > 400) la diferencia varıa en menor proporcion. Cabe senalar que en un numero considerable de

casos la diferencia es negativa; es decir la cantidad de iteraciones se reduce.

102

103

104

0

1

2

3

4

5

6

Valor de n

Speed−

up

1 Core

2 Cores

4 Cores

8 Cores

Figura 5.4: Escalabilidad paralela del metodo Gauss-Seidel version canonica.

Con los resultados obtenidos y que se muestran en la tabla 5.1, la cantidad de iteraciones que

varıa es despreciable, teniendo en cuenta que el promedio nos indica que la diferencia es mucho menor

al punto porcentual, lo cual es insignificante para este trabajo en particular. Otro punto importante

es el conocer si las ejecuciones en paralelo convergen a la misma solucion que la seriada, lo cual es

mas importante. Realizando las modificaciones necesarias puede comprobarse que efectivamente las

Page 118: Esquemas iterativos en paralelo con OpenMP

102 Capıtulo 5. Metodo de Gauss-Seidel

cuatro ejecuciones convergieron a la misma aproximacion.

Al igual que en el metodo de Jacobi, se mide la escalabilidad de Gauss-Seidel con el fin de

evidenciar el incremento en la velocidad del algoritmo por la ejecucion en multiples cores. En la

figura 5.4 se ilustran los resultados de este proceso. En la imagen se describe un speed-up para

dos cores casi proporcional para valores de n ≥ 1000. Para la ejecucion en cuatro cores el speed-

up es cercano a 3.8x para los mayores tamanos de la matriz (≥ 5000). En el ultimo de los casos,

para la ejecucion con ocho procesadores el speed-up se situa aproximadamente a 5.4x para los

valores mayores de n. Estos resultados indican que el codigo de la figura 5.2 tiene una escalabilidad

comparable con la de Jacobi con un valor menor de speed-up; esta diferencia no considerable ya que

se encuentra en el orden menor a una decima.

Con base a los resultados obtenidos en este bloque es concluyente que el metodo de Gauss-

Seidel es paralelizable con OpenMP sin mayor esfuerzo al del uso de una directiva. Cabe senalar

que no es necesario implementar el algoritmo GSBR (Gauss-Seidel Black-Red) para crear un codigo

paralelo en computadoras de memoria compartida. La diferencia del numero de iteraciones para

una ejecucion paralela no oscila muy lejos de una seriada. Los resultados obtenidos son comparables

con los del capıtulo anterior por lo cual la escalabilidad del algoritmo tiene punto a favor.

5.4. Gauss-Seidel versus Jacobi

En el capıtulo anterior se estudio el metodo de Jacobi, y en esta seccion se realiza la comparativa

entre este y el metodo de Gauss-Seidel, con el proposito de hacer notar las diferencias en rendimiento

que se obtienen en cada uno de ellos. Durante este capıtulo se ha indicado que este esquema es mejor

que el de Jacobi; con los resultados de esta seccion se demuestra esta afirmacion.

Para estudiar la convergencia de estos dos metodos considere la siguiente ecuacion diferencial

de segundo orden∂2

∂y2u+

∂2

∂x2u = f(x, y) en Ω = (0, 1)| × (0, 1) (5.9)

sujeta a

u(x, y) = g(x, y) sobre ∂Ω

Page 119: Esquemas iterativos en paralelo con OpenMP

5.4. Gauss-Seidel versus Jacobi 103

A priori conocemos la solucion analıtica

u(x, y) = senx cos y (5.10)

con ello se deriva f(x, y) de (5.9)

f(x, y) = −2 senx cos y (5.11)

Conocer la solucion analıtica nos ayuda a determinar el error numerico de los esquemas iterativos.

Tomando (5.9) y discretizando con diferencias finitas se tiene

ui+1j − 2uij + ui−1j

h2+uij+1 − 2uij + uij−1

h2= fij (5.12)

A continuacion se despeja uij de (5.12)

h2fij = ui+1j + ui−1j + uij+1 + uij−1 − 4uij

h2fij + 4uij = ui+1j + ui−1j + uij+1 + uij−1

4uij = −h2fij + ui+1j + ui−1j + uij+1 + uij−1

uij =−h2fij

4+ui+1j + ui−1j + uij+1 + uij−1

4

A continuacion se muestra la formula del problema

ui,j =1

4h2fij +

1

4(ui+1j + ui−1j + uij+1 + uij−1) (5.13)

Tomando (5.13) se puede hacer una adaptacion del problema para que cumpla los requerimien-

tos de los Metodos de Gauss-Seidel y Jacobi, respectivamente. A continuacion se muestran las

modificaciones para que estos se cumplan.

En primer lugar se muestra la modificacion para el esquema de Jacobi

uk+1i,j =

1

4h2fij +

1

4

(uki+1j + uki−1j + ukij+1 + ukij−1

)(5.14)

Page 120: Esquemas iterativos en paralelo con OpenMP

104 Capıtulo 5. Metodo de Gauss-Seidel

Codigo para Jacobi

for(k = 0; ;k++)

for(i = 1; i < n-1; i++)

for(j = 1; j < n-1; j++)

v[i][j] = -0.25 * h*h * f(i,j) + 0.25 * (u[i][j+1] \

+ u[i][j-1] + u[i+1][j] + u[i-1][j]));

if(norm_inf(u,v) < E)

break;

colonar_sm(u,v,n,n);

Figura 5.5: Metodo de Jacobi con diferencias finitas.

Codigo para Gauss-Seidel

for(k = 0; ;k++)

colonar_sm(v,u,n,n);

for(i = 1; i < n-1; i++)

for(j = 1; j < n-1; j++)

u[i][j] = -0.25 * h*h * f(i,j) + 0.25 * (u[i][j+1] \

+ u[i][j-1] + u[i+1][j] + u[i-1][j]));

if(norm_inf(u,v) < E)

break;

Figura 5.6: Metodo de Gauss-Seidel con diferencias finitas.

En segunda instancia se tiene la modificacion para el esquema de Gauss-Seidel

uk+1i,j =

1

4h2fij +

1

4

(uk+1i+1j + uk+1

i−1j + uk+1ij+1 + uk+1

ij−1

)(5.15)

Con ello se puede escribir el codio de las ecuaciones (5.14) y (5.15), a continuacion se muestra

una forma compacta de cada uno de los programas, donde se observa unicamente la fraccion donde

se llevan a cabo las iteraciones para encontrar la solucion, de cada uno de los programas. Cabe

mencionar que el margen de error utilizado para ambos casos es de 1e-8.

Page 121: Esquemas iterativos en paralelo con OpenMP

5.4. Gauss-Seidel versus Jacobi 105

El codigo de la figura 5.5 corresponde a la ecuacion (5.14) donde se resuelve el problema tratado

mediante el Metodo Iterativo de Jacobi. Mientras que en la figura 5.6 se escribe la implementacion

en codigo correspondiente a (5.15) donde se resuelve el problema con el Esquema de Gauss-Seidel.

En la tabla 5.2 se muestran los resultados, cuando se cuantifican las iteraciones necesarias para

converger y el error (con respecto de la solucion analıtica) de cada uno de ellos; para obtener esos

resultados se utilizo, como condicion de paro, la norma infinita de la diferencia de los resultados

de la iteracion actual con respecto a la anterior (‖uk+1 − uk‖∞ < η), con una tolerancia de

error η = 1−8 y para la representacion de los numeros reales en la computadora se utilizo doble

precision cientıfica (double en lenguaje C). Cabe recalcar que este problema es de dos dimensiones

(2-D). Es importante mencionar que para nuestro caso no utilizamos un lımite de iteraciones, esto

a consecuencia de que se conocıa que la ecuacion converge. Para casos donde se desconoce si la

solucion podrıa o no converger se debe limitar el numero de iteraciones, de lo contrario la aplicacion

se encontrara en un ciclo infinito.

Tabla 5.2: Convergencia de Gauss-Seidel vs Jacobi.

Gauss-Seidel versus Jacobiiteraciones para converger

Valor de Jacobi Gauss-SeidelN Iteraciones Error Iteraciones Error

4× 4 27 0.301769 14 0.3017698× 8 137 0.063374 68 0.063374

16× 16 525 0.014678 268 0.01467832× 32 1803 0.003563 928 0.00356664× 64 5692 0.000875 2961 0.000884

128× 128 16271 0.000236 8599 0.000230256× 256 49340 0.000061 26481 0.000056

Como se demuestra en las columnas dos y cuatro de la tabla (5.2), el metodo de Gauss-Seidel

converge generalmente cerca de dos veces mas rapido que el esquema de Jacobi, esto debido a que se

utilizan los nuevos valores obtenidos en la presente iteracion, para calcular el resto de las operaciones

de la iteracion actual [23]. En las columnas tres y cinco de la misma tabla se observa que conforme

Page 122: Esquemas iterativos en paralelo con OpenMP

106 Capıtulo 5. Metodo de Gauss-Seidel

se incrementa el numero de nodos (n× n) el error disminuye. Lo cual es consistente con el hecho

lımh→0‖u− un‖p → 0 (5.16)

donde h ≈ 1N2 , siendo u el valor exacto y un una aproximacion con n× n nodos.

En la figura 5.7 se ilustra el comportamiento de (5.16) para el problema de (5.15). En las

tres primeras graficas se plasman los resultados de la evaluacion del codigo de la figura 5.6 para

N = (4×4, 6×6, 8×8). La cuarta grafica representa la solucion analıtica. En estas graficas se ilustra

como al aumentar el numero de nodos a la aproximacion (un) se asemeja a la solucion exacta. El

costo computacional que se paga por una mejor aproximacion es muy alto, lo cual se observa en la

tabla 5.2. Esta situacion expone de mejor manera la gran disyuntiva exactitud versus rapidez; esta

eleccion se realiza de la mano de los fines del proyecto y de los recursos con los que se dispone para

el mismo.

−1

−0.8

−0.6

−0.4

−0.2

0

0.2

0.4

0.6

0.8

1

−1

−0.8

−0.6

−0.4

−0.2

0

0.2

0.4

0.6

0.8

1

N = 4× 4 N = 6× 6

−1

−0.8

−0.6

−0.4

−0.2

0

0.2

0.4

0.6

0.8

1

N = 8× 8 Solucion analıtica

Figura 5.7: Aproximacion numerica a u(x, y) = senx cos y con Gauss-Seidel.

Page 123: Esquemas iterativos en paralelo con OpenMP

5.4. Gauss-Seidel versus Jacobi 107

En esta seccion se mostro numericamente que el metodo de Gauss-Seidel converge aproximada-

mente dos veces mas rapido que el esquema de Jacobi. El estudio de la convergencia de ambos meto-

dos se limito unicamente a cuantificar las iteraciones. Cabe senalar que la rapidez de la convergencia

de los metodos iterativos depende de lo pequeno que sea el radio espectral de la matriz[3, 8, 33].

Para acelerar la convergencia se le puede asociar un metodo extrapolado o relajado con un factor

de relajacion ω el cual es un parametro fijo; calcular el valor optimo no es sencillo y se obtiene me-

diante procedimientos heurısticos [24, 33]. Todas estas optimizaciones dan como resultados nuevos

esquemas iterativos como por ejemplo el metodo de sobrerrelajacion acelerada. El estudio de estos

“metodos derivados” no es el objetivo de este documento.

En este capıtulo se analizo el metodo iterativo de Gauss-Seidel con la finalidad de escribir un

codigo; que implemente este esquema y que ademas pueda ser ejecutado en forma paralela. Se

comprobo que la convergencia del esquema iterativo de Gauss-Seidel es superior a Jacobi; dos veces

mas rapido. Este hecho hace que los tiempos de ejecucion para este metodo sean menores y por lo

tanto el rendimiento sea mayor. Es preciso mencionar que el error de los dos esquemas iterativos

tratados son muy similares lo cual es congruente con la similitud de ambos. Cabe senalar que en

ambientes de memoria compartida no es necesario implementar GSBR para funciones paralelas.

Debido a que todos los datos se encuentran alojados dentro de una memoria principal a la que

acceden todos los cores de forma local. Por otro lado es concluyente que este esquema es altamente

paralelizable con base a los resultados obtenidos. Se obtienen speed-up de 2x, 3.8x y 5.4x para 2, 4,

8 cores respectivamente. Estos resultados son semejantes a los obtenidos con el metodo de Jacobi

lo cual indica que el incremento en el speed-up continua conforme se aumenten el numero de cores

de acuerdo con el tamano del problema.

Page 124: Esquemas iterativos en paralelo con OpenMP
Page 125: Esquemas iterativos en paralelo con OpenMP

Capıtulo 6Conclusiones y trabajo a futuro

Conclusiones

Es comun el uso de esquemas iterativos para la solucion numerica de problemas que pueden

representarse por sistemas de ecuaciones lineales. Como muchos metodos numericos; este proceso es

muy demandante de tiempo de calculo. Con la reduccion de costos monetarios de las computadoras

paralelas y la aparicion de modelos de programacion paralela como OpenMP; se vuelve una necesidad

migrar los codigos a estas nuevas tecnologıas. En la presente tesis se demostraron los beneficios por

crear algoritmos para la programacion en paralelo. Es por ello que se hace incapie en el deseo de

generalizar la programacion en paralelo para las nuevas aplicaciones. A continuacion se expresa las

conclusiones.

Durante la realizacion de la multiplicacion matriz-vector se estudio como maximizar el rendi-

miento de la aplicacion seriada obteniendo un aumento a tasas de 1.6x y 2.0x para Unroll de 4

y MMX respectivamente. Para incrementar el rendimiento de estas funciones se utilizo banderas

de compilacion que catapultan el desempeno de 378 a 1500 MFLOPS para la version canonica y

en promedio 3000 MFLOPS para MMX. Cuando se establece el algoritmo para una programacion

paralela real se tiene los siguientes incrementos en el desempeno; la version canonica tiene un mejor

speed-up (5.4x) que Unroll y MMX (4.3x, 2.8x respectivamente) para 8-cores. Sin embargo, el mejor

rendimiento continuo siendo para la version MMX.

A lo largo del estudio del esquema iterativo de Jacobi se realiza una optimizacion para retirar

una sentencia if con lo que reducimos en 20 % el tiempo de ejecucion. Tomando las tecnicas de

109

Page 126: Esquemas iterativos en paralelo con OpenMP

110 Capıtulo 6. Conclusiones y trabajo a futuro

programacion hechas en el capıtulo 3 se tienen resultados semejantes a los anteriores con un speed-

up de 3.0x para 8 nucleos con MMX. Cabe senalar que al igual que el tema anterior la version

canonica tiene una mejor escalabilidad con un promedio de 5.5x para 8 nucleos y para 2 y 4 cores

una escalabilidad de 2.0x y 3.8x lo cual representa practicamente una escalabilidad lineal.

Se estudio el metodo iterativo de Gauss-Seidel (G-S) con la finalidad de determinar cual es mejor

opcion jacobi o G-S; con ello es concluyente que G-S converge normalmente dos veces mas rapido

y ambos con un error relativo semejante. Cuando el metodo se hace paralelo nos encontramos con

un aspecto realmente importante; el procedimiento puede dividirse en tantos bloques como cores

se tengan, esto no se reflejara significativamente en un aumento del numero de iteraciones. Como

consecuencia de ello se tienen un speed-up y escalabilidad muy semejante a la que se obtuvo con el

esquema de Jacobi; 5.4x para una ejecucion en 8 cores y 2.0x, 3.8x para 2 y 4 cores respectivamen-

te. Con estos resultados es concluyente que G-S representa una mejor opcion para resolver estos

problemas no solo en serie sino que ademas en paralelo.

Finalmente concluimos dos aspectos de gran importancia: cuando se busca obtener el mayor ren-

dimiento computacional (performance) es preciso escribir el codigo utilizando las funciones definidas

con la tecnologıa MMX, ası como utilizar las banderas de compilacion para indicar al compilador

que optimice las lıneas de codigo. En segundo lugar, cuando se busca que la aplicacion tenga una

mayor escalabilidad paralela se recomienda el uso de la version canonica con banderas de compi-

lacion lo cual no altera la curva de aceleracion. Estos resultados son congruentes con la literatura

existente.

Trabajo a futuro

En esta tesis se ha estudiado y creado dos modelos paralelos para la solucion de sistemas lineales

de ecuaciones con metodos iterativos. Se proporciona codigo fuente para computadoras de memoria

compartida.

Como lıneas futuras se piensa en migrar el codigo a las nuevas tecnologıas de programacion en

paralelo, aquellas que utilizan las tarjetas graficas. Donde la cantidad de unidades de procesamiento

es mucho mayor a las utilizadas en el presente documento. Ejemplos modernos de estas tecnologıas

son las propuestas por los dos gigantes de las tarjetas graficas AMD ATI y Nvidia. La empresa ATI

presenta su interfaz llamada ATI Streaming; por su parte Nvidia pone al alcance de todos su interfaz

Page 127: Esquemas iterativos en paralelo con OpenMP

Capıtulo 6. Conclusiones y trabajo a futuro 111

llamada CUDA. Estas tecnologıas son conocidas como manycore debido a que estan compuestas

por un gran numero de procesadores; juntos dan la capacidad de lanzar miles de hilos a la vez.

Otras lıneas futuras a seguir, consistira en aplicar los estudios realizados por terceros para

mejorar la velocidad de convergencia de estos metodos; lo que permitira optimizar las funciones

escritas en la presente tesis. Incluyendo los metodos ω-relajados y el metodo de sobrerrelajacion

acelerada (AOR).

En esta tesis se escribieron funciones paralelas para sistemas con memoria compartida. Sin

embargo, en muchas ocasiones se tienen mas de dos computadoras conectadas a una red de alta

velocidad; esto permite construir un sistema con memoria distribuida. Otro de nuestros objetivos,

consistira en la programacion de funciones hıbridas entre ambos paradigmas. Para ello se utili-

zara MPI (Message Passing Interface) y PVM (Parallel Virtual Machine) con motivos comparati-

vos. Con estos resultados se desarrollara una librerıa de acceso publico que implemente los metodos

tratados. El desarrollo de funciones para esquemas iterativos proyectados sobre subespacios de tipo

Krylov, sera otro de nuestros propositos.

Page 128: Esquemas iterativos en paralelo con OpenMP
Page 129: Esquemas iterativos en paralelo con OpenMP

Bibliografıa

[1] G.Y. Alpızar. Factorizacion de Cholesky como tecnica de precondicionamien-

to. Revista digital matematica, 13(1), Agosto-Febrero 2013. Recurso disponible en

http://www.tec-digital.itcr.ac.cr/revistamatematica/ARTICULOS V13 N1 2012/

RevistaDigital Geisel V13 n1 2012/, ultimo acceso noviembre de 2012.

[2] T. Ando, E. Chow, Y. Saad, and J. Skolnick. Krylov subspace methods for computing

hydrodynamic interactions in Brownian dynamics simulations. The Journal of Chemical

Physics, 2012. aceptado Julio 20, 2012. doi: 10.1063/1.4742347. Recurso disponible en

http://jcp.aip.org/resource/1/jcpsa6/v137/i6/p064106 s1?bypassSSO=1, ultimo acce-

so noviembre de 2012.

[3] J. Arnal-Garcıa. Algoritmos iterativos paralelos para la resolucion de sistemas no lineales. Te-

sis doctoral, Universidad de Alicante, Abril 2000. Recurso disponible en http://rua.ua.es/

dspace/bitstream/10045/3217/1/Arnal%20Garc%C3%ADa%2c%20Josep.pdf, ultimo acceso

noviembre de 2012.

[4] S. Balay, J. Brown, K. Buschelman, V. Eijkhout, W. Gropp, D Kaushik, L. Knepley, M. Curf-

man McInnes, B. Smith, H. Zhang, Mathematics, and Computer Science Division (Argon-

ne National Laboratory). PETSc Users Manual: revision 3.3. U.S. Department of Energy,

2012. Reporte disponible en http://www.osti.gov/bridge., ultimo acceso noviembre de

2012.

[5] A. Baldor. Algebra. Grupo Patria Cultural, 2007.

113

Page 130: Esquemas iterativos en paralelo con OpenMP

114 Bibliografıa

[6] M.A.P. Basurto and J.M.C. Espın. Introduccion a la Programacion en C. Aula Politecnica.

Edicions Upc, 2010.

[7] R.L. Burden and J.D. Faires. Numerical analysis. Cengage Learning, 2001.

[8] M.J. Castel de Haro. Metodos iterativos paralelos para la resolucion de sistemas lineales hermıti-

cos y definidos positivos. Tesis doctoral, Universidad de Alicante, Mayo 2000. Recurso dispo-

nible en http://rua.ua.es/dspace/handle/10045/3372, ultimo acceso Noviembre 2012.

[9] L.L. Chaillou. Calculo numerico: curso practico con apliaciones a la ingenierıa en alimentos.

Lucrecia, 2008.

[10] R. Chandra, R. Menon, L. Dagum, D. Kohr, D. Maydan, and J. McDonald. Parallel Program-

ming in OpenMP. Morgan Kaufmann, 2001.

[11] B. Chapman, G. Jost, and R. Pas. Using OpenMP: portable shared memory parallel program-

ming. Scientific and engineering computation. MIT Press, 2007.

[12] S.C. Chapra and R.P. Canale. Metodos numericos para ingenieros. McGraw-Hill, 2007.

[13] W.P. Cockshott and K. Renfrew. SIMD programming manual for Linux and Windows. Springer

professional computing. Springer, 2004.

[14] J.L. de la Fuente O’Connor. Tecnicas de calculo para sistemas de ecuaciones, programacion

lineal y programacion entera: codigos en FORTRAN y C con aplicaciones de sistemas de energıa

electrica. Reverte, 1997.

[15] H.M. Deitel and P.J. Deitel. Como programar en C, C++ y Java. Pearson Educacion, 2004.

[16] A. Gaul and N. Schlomer. Modified recycling MINRES with application to nonlinear Schrodin-

ger problems, Agosto 2012. Recurso disponible en http://arxiv.org/pdf/1208.0264.pdf,

ultimo acceso noviembre de 2012.

[17] GNU Press a division of the Free Software Foundation. The GNU

OpenMP Implementation, 2011. Manual de usuario, recurso disponible en

http://gcc.gnu.org/onlinedocs/libgomp.pdf, ultimo acceso noviembre de 2012.

Page 131: Esquemas iterativos en paralelo con OpenMP

Bibliografıa 115

[18] R. Gomez-Jimenez, D. Escobar-Hernandez, D.A. Gomez-Arias, J.L. Guerrero-Magana, J.M.A.

Gutierrez-Rocha, M.A. Hernandez-Hernandez, A.P. Puerto-Covarrubias, and L.M. Sandoval-

Magallanes. Elementos de metodos numericos para ingenierıa. McGraw-Hill, 2002.

[19] R.M. Hidalgo. Sincronizacion y caos en sistemas electronicos no lineales y sus apli-

caciones a las comunicaciones. Tesis doctoral, Universidad Nacional de Mar del Pla-

ta, Octubre 2003. Recurso disponible en http://www3.fi.mdp.edu.ar/electronica/

tesis/Tesis Hidalgo Roberto.pdf, ultimo acceso noviembre de 2012.

[20] M.D. Hill and M.R. Marty. Amdahl’s law in the multicore era. IEEE Computer Society,

pages 33–38, Julio 2008. Recurso disponible en http://research.cs.wisc.edu/multifacet/

papers/ieeecomputer08 amdahl multicore.pdf, ultimo acceso noviembre de 2012.

[21] T.Z. Huang, Y. Zhang, and L. Li. Modified incomplete Cholesky factorization for solving elec-

tromagnetic scattering problems. Progress In Electromagnetics Research B, 13:41–58, 2009.

Recurso disponible en http://www.jpier.org/PIERB/pierb13/03.08112407.pdf, ultimo ac-

ceso noviembre de 2012.

[22] Imad M. Jaimoukha and Ebrahim M. Kasenally. Implicitly restarted Krylov subspace methods

for stable partial realizations. SIAM J. Matrix Anal. Appl., 18(3):633–652, Julio 1997. Recurso

disponible en http://www2.ee.ic.ac.uk/publications/p449.pdf, ultimo acceso noviembre

de 2012.

[23] G. Karniadakis and R.M. Kirby. Parallel scientific computing in C++ and MPI: a seamless

approach to parallel algorithms and their implementation. Cambridge University Press, 2003.

[24] C.T. Kelley. Iterative methods for linear and nonlinear equations. Society for Industrial and

Applied Mathematics (siam), 1995.

[25] B. Kolman, D.R. Hill, and V.H.I. Mercado. Algebra lineal. Pearson Educacion, 2006.

[26] M.J. Martın-Santamarıa. Factorizacion de Cholesky modificada de matrices dispersas sobre

multiprocesadores. Tesis doctoral, Universidad de Santiago de Compostela, Julio 1999. Recur-

so disponible en http://gac.udc.es/tesis/MariaJMartin.pdf, ultimo acceso noviembre de

2012.

Page 132: Esquemas iterativos en paralelo con OpenMP

116 Bibliografıa

[27] M. Mittal, A. Peleg, and U. Weiser. MMX technology architecture overview. Intel journal,

1997. Recurso disponible en http://www.ece.sunysb.edu/∼midor/ESE345/MMX archit.pdf,

ultimo acceso noviembre 2012.

[28] S. Nakamura. Metodos numericos aplicados con software. Prentice-Hall Hispanoamericana,

1992.

[29] L. Null and J. Lobur. The Essentials of Computer Organization and Architecture. Jones &

Bartlett Learning, 2003.

[30] NVIDIA CUDA. NVIDIA CUDA C programming guide version 4.2, 2012. Ma-

nual de usuario, recurso disponible en http://developer.download.nvidia.com/compute/

DevZone/docs/html/C/doc/CUDA C Programming Guide.pdf, ultimo acceso noviembre de

2012.

[31] P.S. Pacheco. An introduction to parallel programing. Morgan Kaufmann, 2011.

[32] D. Page. A practical introduction to computer architecture. Texts in computer science. Springer,

2009.

[33] J. Penades-Martınez. Metodos iterativos paralelos para la resolucion de sistemas lineales ba-

sados en multiparticiones. Tesis doctoral, Universidad de Alicante, Noviembre 1993. Recurso

disponible en http://rua.ua.es/dspace/handle/10045/3806, ultimo acceso noviembre de

2012.

[34] W.P. Petersen and P. Arbenz. Introduction to Parallel Computing. Oxford University Press,

2004.

[35] C. Ramiro-Sanchez. Algoritmos paralelos para la resolucion de problemas de mınimos

cuadrados basados en transformaciones ortogonales sobre GPUs y multiprocesadores. Tesis

de maestrıa, Universitat Politecnica de Valencia, Diciembre 2010. Recurso disponible en

http://riunet.upv.es/bitstream/handle/10251/11319/PFM Carla Ramiro Sanchez.pdf,

ultimo acceso noviembre de 2012.

[36] A. Santos-Palomo and P. Guerrero-Garcıa. Resolviendo una sucesion de sis-

temas compatibles dispersos. XXVI Congreso Nacional de Estadıstica e In-

Page 133: Esquemas iterativos en paralelo con OpenMP

Bibliografıa 117

vestigacion Operativa Ubeda, 6-9 de Noviembre, 2001. Recurso disponible en

http://www.matap.uma.es/investigacion/tr/ma00 05.pdf, ultimo acceso noviembre

de 2012.

[37] C. Severance and K. Dowd. High Performance Computing. Draft version: Rice University, Hous-

ton, Texas (Connexions), 2011. Acceso Julio 2012, http://cnx.org/content/col11136/1.5/.

[38] S. Sidi-Ali-Cherif and K.M. Grigoriadis. Efficient model reduction of large scale systems using

Krylov-subspace iterative methods. International Journal of Engineering Science, Vol.41:507–

520, 2003. Recurso disponible en http://144.206.159.178/ft/484/78648/15146190.pdf,

ultimo acceso noviembre de 2012.

[39] Y. Skiba. Metodos y esquemas numericos: un analisis computacional. Universidad Nacional

Autonoma, 2005.

[40] R. M. Stallman and the GCC Developer Community. Using the GNU Compiler Collection: for

gcc version 4.2.4. GNU Press a division of the Free Software Foundation, 2005. Manual de

usuario, recurso disponible en http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc.pdf, ultimo

acceso noviembre de 2012.

[41] K. Sydsaeter, P. Hammond, and J.L.V. Cordoba. Matematicas para el analisis economico.

Fuera de coleccion Out of series. Prentice Hall, 1996.

[42] A.E. Tomas-Domımguez. Implementacion paralela de metodos de Krylov con reinicio para

problemas de valores propios y singulares. Tesis doctoral, Universitat Politecnica de Valencia,

Marzo 2009.