Professional Documents
Culture Documents
12
2.1. INTRODUCCIÓN.
13
poder disponer de esa potencia de cálculo, pero a un precio muy inferior. El concepto de
cluster nació cuando los pioneros de la súper computación intentaban difundir diferentes
procesos entre varias computadoras, para luego poder recoger los resultados que dichos
procesos debían producir. Con un hardware más asequible, se pudo perfilar que podrían
conseguirse resultados muy parecidos a los obtenidos con aquellas máquinas mucho más
costosas, como se ha venido probando desde entonces.
x Grid.
x Globus.
14
- Servicios de Información: Servicio de Descubrimiento y Monitorización.
- Gestión y Movimiento de Datos: Acceso Global al Almacenamiento Secundario y
FTP en grid, GridFTP.
x XML.
Los servicios Web basados en XML, ofrecen una forma de acceder a diversos servicios en
un entorno distribuido. Recientemente, el mundo de la informática en grid y los servicios Web
caminan juntos para ofrecer el grid como un servicio Web. La arquitectura está definida por la
Open Grid Services Architecture (OGSA). La versión 3.0 de Globus Toolkit, será una
implementación de referencia acorde con el estándar OGSA.
x Clustering.
x Aspectos de seguridad.
Hemos visto que los dos grandes sistemas de computación distribuida son el grid y el
cluster (sin mencionar las carísimas supercomputadoras), cada uno con sus ventajas e
inconvenientes particulares. Si tenemos presente nuestro objetivo final, el cual es tener un
conjunto de computadoras dedicadas exclusivamente al cálculo numérico distribuido,
llegamos a la conclusión de que la solución conveniente para llevar a cabo nuestro trabajo es
un cluster. Esto, además, coincide con la configuración que se dispone en el lugar de trabajo.
15
2.2. CLUSTER DE ORDENADORES.
x Alto rendimiento (HPC o High Performance Computing): este tipo de cluster está
diseñado para obtener el máximo rendimiento de la aplicación utilizada, incluso a
costa de la disponibilidad del sistema, es decir el cluster puede sufrir caídas. Este tipo
de configuración esta orientada a procesos que requieran mucha capacidad de cálculo.
x Balanceo de carga (Load-balancing): este tipo de cluster esta diseñado para balancear
la carga de trabajo entre varios servidores; esto permite tener, por ejemplo, un sitio
Web sin caídas por una carga excesiva de peticiones en un momento dado (excepto
cuando se sobrepase la capacidad de todas las máquinas). Actualmente un cluster load-
balancing es un fail-over, con el extra del balanceo de la carga y, a menudo, con
mayor número de nodos.
16
semi-homogéneo), o por el contrario, tener diferente hardware y sistema operativo (cluster
heterogéneo).
Para que un cluster funcione como tal, no basta solamente con conectar entre sí los
ordenadores, sino que es necesario dotarlo de un sistema de manejo del cluster, que se
encargue de interactuar con el usuario y los procesos que corren en él para optimizar el
funcionamiento.
Nodos.
Debe ser de fácil manejo y acceso, y permitir además múltiples procesos y usuarios.
Ejemplos se S.O. son: GNU/Linux, Unix (Solaris / HP-Ux / Aix), Windows (NT / 2000 / 2003
Server), Mac OS X, S.O. especiales para Clusters, etc.
Conexiones de Red.
Los nodos de un cluster pueden conectarse mediante una simple red Ethernet, o a
través de tecnologías especiales de alta velocidad como Fast-Ethernet, Gigabit-Ethernet,
Myrinet, Infiniband, SCI, etc.
Myrinet es una red de interconexión de clusters de altas prestaciones. La empresa
fabricante de Myrinet es Myricom. Desde 1995, han ido mejorando en rendimiento, hasta
obtener en la actualidad latencias de 3 microsegundos y anchos de banda de hasta 10Gbps.
Una de sus principales características, además de su rendimiento, es que el procesamiento de
las comunicaciones de red se hace a través de chips integrados en las tarjetas de red de
Myrinet (Lanai chips), descargando a la CPU de parte del procesamiento de las
comunicaciones. Físicamente, Myrinet consiste en dos cables de fibra óptica, upstream y
downstream, conectados mediante un único conector. Las especiales características de
Myrinet hacen que sea altamente escalable, gracias a la tecnología existente de conmutadores
y routers. Su presencia en clusters de gran tamaño es importante. De hecho, en la lista del
Top500 (www.top500.org), dentro de los clusters, la inmensa mayoría utilizan redes Myrinet.
Para nuestro trabajo particular, no se utiliza una red Myrinet, sino Gigabit-Ethernet,
de 1 Gbps, que es de lo que se dispone.
17
Middleware.
- Una interfaz única de acceso al sistema, denominada SSI (Single System Image), la
cual genera la sensación al usuario de que utiliza un único ordenador muy potente.
- Herramientas para la optimización y mantenimiento del sistema: migración de
procesos, checkpoint-restart (congelar uno o varios procesos, mudarlos de servidor y
continuar su funcionamiento en el nuevo host), balanceo de carga, tolerancia a fallos,
etc.
- Escalabilidad: debe poder detectar automáticamente nuevos servidores conectados al
cluster para proceder a su utilización.
Los modelos de clusters más conocidos por su amplia utilización en función del
middleware son:
- NUMA (Non-Uniform Memory Access).
- PVM (Parallel Virtual Machine).
- MPI (Message Pass Interface), que es la que nosotros utilizamos para desarrollar
nuestro trabajo.
Las máquinas de tipo NUMA, tienen acceso compartido a la memoria donde pueden
ejecutar su código de programa. En el kernel de Linux hay ya implementado NUMA, que
hace variar el número de accesos a las diferentes regiones de memoria.
18
MPI y PVM son herramientas ampliamente utilizadas, y son muy conocidas por
aquellos que entiende de súper computación basada en GNU/Linux. MPI es el estándar
abierto de bibliotecas de paso de mensajes. MPICH es una de las implementaciones más
usadas de MPI; tras MPICH se puede encontrar LAM, otra implementación basada en MPI,
que también son bibliotecas de código abierto. PVM es un middleware semejante a MPI,
ampliamente utilizado en clusters Beowulf. PVM habita en el espacio de usuario, y tiene la
ventaja de que no hacen falta modificaciones en el kernel de Linux. Básicamente, cada
usuario con derechos suficientes puede ejecutar PVM.
En el apartado 2.4. tendrá lugar una discusión sobre las diferencias entre MPI y PVM,
y se explicará en detalle el funcionamiento de MPI, ya que es la solución escogida para
desarrollar nuestro objetivo.
Para entender bien el fin de utilizar la MPI, es necesario realizar un estudio sobre el
Cálculo en Paralelo, que será de gran importancia para nuestro trabajo. La próxima sección se
ha dedicado a dicha tarea.
19
2.3. CÁLCULO EN PARALELO.
- El programa se diseña para correr en un solo ordenador con una única CPU.
- El problema a abordar es dividido en series discretas de instrucciones.
- Las instrucciones son ejecutadas una detrás de otra.
- Sólo una instrucción puede ser ejecutada en cada instante de tiempo.
Teniendo en cuenta ya qué es la computación en serie, para el caso más sencillo, podemos
definir la computación en paralelo como la utilización simultánea de múltiples recursos de
computación para resolver un problema. Esto es:
20
- Resuelto en menos tiempo con múltiples recursos computacionales que con un
recurso simple para la resolución en serie.
Existen diversas razones para utilizar la computación en paralelo, como ahorrar tiempo,
resolver grandes problemas, proporcionar concurrencia, superar los límites de memoria
existentes al utilizar un solo ordenador, etc.
- Tarea Paralela: Tarea que puede ser ejecutada de forma segura (produciendo
resultados correctos) por múltiples procesadores simultáneamente.
- Ejecución en paralelo: Ejecución de un programa por más de una tarea, siendo cada
tarea capaz de ejecutar la misma expresión o una diferente, y todas en un mismo
instante de tiempo.
21
- Memoria compartida: Desde el punto de vista del hardware, describe una arquitectura
de ordenador donde todos los procesadores tienen acceso directo a una memoria física
común. Desde el punto de vista del software, describe un modelo donde todas las
tareas paralelas tienen la misma representación de la memoria, y pueden direccionar y
acceder directamente a las mismas localizaciones de una memoria lógica, sin
preocuparse de donde se encuentra la memoria física.
- Coste operativo paralelo: Cantidad de tiempo requerido para coordinar las tareas
paralelas, contrario al tiempo útil de ejecución. El coste operativo paralelo puede
incluir factores como el tiempo de arranque y terminación de una tarea,
sincronización, comunicaciones de datos, coste del software impuesto por
compiladores, librerías, herramientas y sistema operativo paralelos, etc.
22
2.3.2. ARQUITECTURAS DE MEMORIA DE ORDENADORES PARALELOS.
Las máquinas de memoria compartida se pueden dividir en dos clases principales, basadas
en los tiempos de acceso a memoria: UMA (Acceso Uniforme a Memoria) y NUMA (Acceso
No-Uniforme a Memoria).
En el caso de UMA, las máquinas son del tipo SMP (Multiprocesador Simétrico –
procesadores idénticos-), y el acceso a memoria y los tiempos asociados a dicho acceso son
idénticos para todos los procesadores.
La arquitectura de NUMA viene determinada por dos o más SMP’s enlazados. Un SMP
puede acceder directamente a la memoria de otro SMP. No todos los procesadores tienen el
mismo tiempo de acceso a todas las memorias, ya que el acceso a través del enlace es más
lento.
Al igual que los sistemas de memoria compartida, los sistemas de memoria distribuida son
muy variados, pero comparten características comunes. Los sistemas de memoria distribuida
requieren una red de comunicación para conectar las memorias de cada procesador. Esta
configuración se muestra en la figura 6.
23
Cada procesador tiene su propia memoria local. Las direcciones de memoria de un
procesador no se mapean al resto de procesadores, de modo que no existe el concepto de
espacio de direccionamiento global a través de todos los procesadores.
Como cada procesador tiene su memoria local, cada cual opera independientemente del
resto. Los cambios hechos por cada uno en su memoria local no tienen efecto sobre las
memorias de los otros procesadores.
Cuando un procesador necesita acceder a los datos residentes en otro procesador, suele ser
tarea del programador definir explícitamente definir cómo y cuando se comunican los datos.
Asimismo, es responsabilidad del programador el lograr la sincronización entre tareas.
Hoy en día, los ordenadores más potentes en el mundo emplean una composición entre las
arquitecturas de memoria compartida y distribuida, así se muestra en la figura 7. En la tabla 1,
se presenta una comparativa entre las arquitecturas de memoria compartida y distribuida.
24
La componente de memoria compartida es, normalmente, una máquina SMP con
coherencia de caché. Los procesadores de un SMP dado pueden direccionar la memoria de esa
máquina de forma global.
Por otro lado, la componente de memoria distribuida se corresponde con el
funcionamiento en red de múltiples SMP’s. Cada SMP solamente tiene constancia de su
propia memoria, no de la memoria de otros SMP’s. Por tanto, son requeridas comunicaciones
de red para mover datos de un SMP a otro.
MPI MPI
Hilos Hilos
Comunicaciones MPI
OpenMP OpenMP
Mem. Compartida Mem. Compartida
Administración del
Ancho de banda sistema.
Características Ancho de banda Memoria-CPU. Programación
destacables. Memoria-CPU. Tiempos de acceso no complicada a la hora
uniformes. del desarrollo y el
mantenimiento.
Disponibilidad
Miles de ISVs. Miles de ISVs. Cientos ISVs.
del Software
Las tendencias actuales parecen indicar que este tipo de arquitectura de manejo de
memoria continuará prevaleciendo, y se incrementará el uso de este tipo de sistemas para la
computación en paralelo dentro del futuro visible.
Las ventajas e inconvenientes de este tipo de sistemas son la unión de las indicadas para
cada arquitectura por separado.
25
Los modelos de programación existen como una abstracción sobre las arquitecturas de
hardware y de memoria. Aunque no parezca claro a simple vista, estos modelos no son
específicos para un tipo particular de máquina o arquitectura de memoria. En realidad,
cualquiera de estos modelos, teóricamente, pueden ser implementados en cualquier hardware
subyacente.
El modelo a utilizar suele ser una combinación entre lo disponible y la elección personal.
No existe un modelo general y óptimo, aunque sí es verdad que hay mejores
implementaciones que otras de algunos modelos.
26
2.3.3.3. MODELO DE PASO DE MENSAJES.
En 1992, se creó el MPI Forum, con el principal objetivo de establecer una interfaz
estándar para las implementaciones de paso de mensajes. La primera parte de MPI (Interfaz
de Paso de Mensajes), entró en vigor en 1994. La segunda parte (MPI-2) a partir de 1996.
Hoy en día, MPI es el estándar para paso de mensajes más importante que existe,
reemplazando al resto de modelos de paso de mensajes. La mayoría de plataformas más
populares, si no todas, ofrecen al menos una implementación de MPI. Unas pocas ofrecen una
implementación completa de MPI-2.
Para arquitecturas de memoria compartida, las implementaciones de MPI, normalmente,
no utilizan una red para comunicaciones entre tareas, sino que hacen uso de un sistema de
memoria compartida (copias de la memoria) por razones de rendimiento.
27
Un conjunto de tareas trabajan colectivamente en la misma estructura de datos; sin
embargo, cada tarea trabaja en una partición diferente de dicha estructura. Todas las tareas
realizan la misma operación en su partición de trabajo.
En arquitecturas de memoria compartida, todas las tareas deben tener acceso a la
estructura de datos por medio del direccionamiento global a la memoria común. En
arquitecturas de memoria distribuida, la estructura de datos es dividida, y reside como
“trozos” en la memoria local de cada tarea.
Citaremos sólo los tres modelos más comunes distintos a los anteriores.
28
Como se muestra en la figura 9, un mismo programa es ejecutado por todas las
tareas simultáneamente. En cualquier instante de tiempo, las tareas pueden estar
ejecutando las mismas o diferentes instrucciones dentro del mismo programa.
Los programas SPMD normalmente tienen la lógica necesaria programada para
permitir a las diferentes tareas la ramificación o ejecución condicional de aquellas
partes del programa que les son designadas para ejecutarlas. Esto es, las tareas no
tienen que ejecutar necesariamente todo el programa, tal vez sólo una porción del
mismo. Además, cada tarea puede utilizar datos diferentes.
MPMD (Multiple Program Multiple Data). Al igual que SPMD, MPMD es,
actualmente, es un modelo de programación de “alto nivel” que puede ser construido
sobre cualquier combinación de los modelos de programación en paralelo ya
mencionados.
Las aplicaciones MPMD típicamente tienen múltiples ficheros objetos ejecutables
(programas); así se muestra en la figura 10.
29
2.4. DISEÑO DE PROGRAMAS EN PARALELO.
30
Otro aspecto importante a tener en cuenta es el tema de los cuellos de botella: hay que
localizar aquellas áreas del programa que son desproporcionadamente lentas o que provocan
que el trabajo paralelizable sea detenido o aplazado. Por ejemplo, todo lo referente a la
entrada / salida de datos es, normalmente, algo que ralentiza un programa. Puede que sea
posible reestructurar el programa o utilizar algoritmos diferentes para reducir o eliminar áreas
lentas innecesarias.
Por otro lado, es de vital importancia encontrar inhibidores del paralelismo; una clase
común de inhibidor del paralelismo es la dependencia de datos.
Es aconsejable estudiar varios algoritmos posibles para buscar mejoras en el
funcionamiento de la aplicación paralela.
2.4.3. PARTICIÓN.
Uno de los primeros pasos en el diseño de un programa paralelo es dividir el problema en
trozos discretos de trabajo que pueden ser distribuidos a múltiples tareas. Esto es conocido
como descomposición o particionamiento.
Hay dos formas básicas para lograr la partición de trabajo computacional entre tareas
paralelas: descomposición de dominio y descomposición funcional.
Descomposición de dominio.
Hay varios caminos para particionar datos. Se presentan en la figura 12, para una y dos
dimensiones. Para dos dimensiones (2D), se particiona en función de los índices de fila y
columna (‘*’ es no partición para el índice al que se hace referencia).
31
Figura 12. Partición mediante descomposición de dominio.
Descomposición funcional.
En este método, el objetivo se centra en la computación que va a ser realizada, más que en
los datos manipulados por la computación. El problema es descompuesto de acuerdo al
trabajo que se va realizar. Entonces, cada tarea es una porción del trabajo total.
2.4.4. COMUNICACIONES.
Algunos tipos de problemas pueden ser descompuestos y ejecutados en paralelo con
ninguna, o casi ninguna, necesidad de compartir datos entre tareas. Sin embargo, la mayoría
de las aplicaciones no son tan simples, y requieren que las tareas compartan datos entre ellas.
Hay un número importante de factores a considerar cuando se diseñan comunicaciones
entre las tareas de un programa paralelo, a saber:
Coste de comunicaciones:
- La comunicación entre tareas siempre implica un coste operativo.
32
- Ciertos recursos de las máquinas y varios ciclos de CPU que podrían ser
empleados para la computación son utilizados para empaquetar y transmitir
datos.
- Frecuentemente, las comunicaciones requieren algún tipo de sincronización
entre tareas, que puede resultar en tareas que se esperan unas a otras en vez de
estar realizando el trabajo de computación.
- El cursar el tráfico de comunicaciones puede saturar el ancho de banda
disponible de la red, agravando los problemas de rendimiento.
33
distinto, según se especifique. Ejemplos de comunicaciones
colectivas son: difusión, recolección, reducción y dispersión de
datos entre tareas.
2.4.5. SINCRONIZACIÓN
Veamos ahora una pequeña síntesis de los tipos de sincronización posibles:
Barrera: normalmente, implica a todas las tareas. Cada tarea realiza su trabajo
hasta que alcanza la barrera. Entonces, la tarea que llega a la barrera se para o se
bloquea. Cuando la última tarea alcanza la barrera, todas las tareas son
sincronizadas. Lo que ocurre a partir de aquí, varía de unos programas a otros.
Frecuentemente, se realizará un conjunto de trabajos en serie. En otros casos, las
tareas son liberadas automáticamente para continuar con sus trabajos.
34
2.4.6. DEPENDENCIA DE DATOS.
Se dice que existe una dependencia entre sentencias de un programa cuando el orden de
ejecución de las sentencias afecta al resultado del programa. Una dependencia de datos
resulta del uso múltiple de la misma zona de almacenamiento por diferentes tareas.
Las dependencias son muy importantes para la programación en paralelo, ya que son uno
de los inhibidores primarios para el paralelismo.
Aunque todas las dependencias son importantes para identificar cuándo es posible la
programación en paralelo, las dependencias acarreadas por los bucles son particularmente
importantes, puesto que los bucles son, posiblemente, el objetivo más común de los esfuerzos
de paralelización.
En arquitecturas de memoria distribuida, se han de comunicar los datos requeridos en los
puntos de sincronización. Para arquitecturas de memoria compartida, se han de sincronizar las
operaciones de lectura / escritura entre tareas.
35
2.4.8. GRANULARIDAD.
En computación en paralelo, la granularidad es una medida cualitativa de la tasa de
computación frente a comunicación. Típicamente, los periodos de computación son separados
de los periodos de comunicación por eventos de sincronización.
El tipo granularidad más eficiente, en general, no es ni una ni otra, sino que depende del
algoritmo utilizado y del entorno hardware en que corre. En la mayoría de los casos, la
sobrecarga asociada con las comunicaciones y la sincronización es alta en relación con la
velocidad de ejecución, de modo que es ventajoso utilizar granularidad gruesa. El paralelismo
de granularidad fina puede reducir la sobrecarga debida al desequilibrio de carga.
36
peticiones de lectura al mismo tiempo. Las operaciones de E/S que necesitan ser conducidas a
través de la red (sistema de ficheros no local, como es el caso de un sistema NFS), podrán
causar cuellos de botella severos.
Por otro lado, decir que existen sistemas de ficheros paralelos disponibles, por ejemplo:
GPFS (General Parallel File System for AIX, de IBM), Lustre (para clusters Linux),
PVFS/PVFS2 (Parallel Virtual File System, para clusters Linux), PanFS (Panasas ActiveScale
File System, para clusters Linux), HP SFS (HP StorageWorks Scalable File Share, que es un
sistema de ficheros paralelo basado en Lustre, también para clusters Linux).
La especificación de la interfaz de E/S paralela para MPI ha estado disponible desde 1996
como parte de MPI-2. Actualmente, existen implementaciones de pago y libres de MPI-2.
Algunos aspectos a tener en cuenta a la hora de realizar operaciones de E/S paralelas son:
Si ninguna parte del código puede ser paralelizada, P es cero, por tanto, speedeup es uno
(no se produce incremento de velocidad). Por el contrario, si P es uno (todo el código es
paralelizable), speedup es infinito, en teoría (existen límites hard y software, evidentemente).
Si el 50% del código es paralelizable, quiere decir que el código paralelo será el doble de
rápido que el código serie.
37
1
speedup (2)
P
+S
N
Los factores que intervienen en (2) son:
- P: fracción de código serie paralelizable.
- N: número de procesadores que trabajan en paralelo.
- S: Fracción de código serie no paralelizable (S = 1 – P).
Es obvio que hay límites marcados para el paralelismo, marcados por la escalabilidad. A
continuación se muestra una tabla comparativa de lo mencionado.
speedup
N
P = 0.50 P = 0.90 P = 0.99
10 1.82 5.26 9.17
100 1.98 9.17 50.25
1000 1.99 9.91 90.99
10000 1.99 9.91 99.02
Complejidad.
En general, las aplicaciones paralelas son mucho más complejas que las correspondientes
aplicaciones serie, incluso puede que lo sean en un orden de magnitud. No sólo se tiene
múltiples flujos de instrucciones ejecutándose a la vez, sino también datos fluyendo por ellos.
Los costes de complejidad son medidos virtualmente en tiempo de programación,
teniendo en cuenta cada etapa del ciclo de desarrollo del software, esto es: diseño,
codificación, depurado, ajustes y mantenimiento.
Adquirir buenas costumbres para desarrollar software es esencial cuando se trabaja con
aplicaciones paralelas, especialmente si alguien ajeno a la labor actual tendrá que trabajar
sobre ella posteriormente.
Portabilidad.
38
Requerimientos de recursos.
La cantidad de memoria requerida puede ser mayor para códigos paralelos que para
códigos en serie, debido a la necesidad de replicar datos y por la sobrecarga asociada con las
librerías y subsistemas de soporte paralelo.
Escalabilidad.
39
2.5. MPI Vs. PVM. IMPLEMENTACIONES DE MPI.
El modelo de computación de PVM es simple, pero muy general, y da cabida a una amplia
variedad de estructuras de programas de aplicación. La interfaz de programación es
intencionadamente directa, de modo que permite la implementación de estructuras de
programa simples, de forma intuitiva. La filosofía es la siguiente: el usuario escribe su código
de aplicación como una colección de tareas que cooperan entre ellas. Cada tarea accede a los
recursos de PVM a través de una librería de interfaces de rutinas estándar. Estas rutinas
permiten la inicialización y terminación de tareas a través de la red, así como la comunicación
y sincronización entre las mismas. Las primitivas de paso de mensajes de PVM están
orientadas a operación heterogénea, involucrando construcciones fuertemente tipadas para
buffering y transmisión. Las construcciones de comunicación incluyen estructuras de datos
para el envío y recepción de mensajes, así como primitivas de alto nivel, tales como difusión,
sincronización de barrera y suma global (reducción).
Las tareas PVM, pueden tener estructuras de dependencia y de control absoluto, es decir,
en cualquier punto de la ejecución de una aplicación concurrente, cualquier tarea existente
puede comenzar o parar otras tareas, o añadir o eliminar ordenadores de la máquina virtual.
Todo proceso se puede comunicar y/o sincronizar con otro. Cualquier estructura de
dependencia y de control específica puede ser implementada bajo el sistema PVM, con el
apropiado uso de construcciones PVM y sentencias de control de flujo de lenguaje máquina.
40
2.5.2. DIFERENCIAS ENTRE MPI Y PVM.
A menudo se comparan MPI y PVM. Normalmente, estas comparaciones empiezan con la
no mencionada suposición de que ambas representan diferentes soluciones para el mismo
problema. En realidad, a menudo los dos sistemas están resolviendo problemas diferentes.
Aunque MPI y PVM hayan surgido de orígenes diferentes, ambas son especificaciones de
librerías que pueden utilizarse para el cómputo en paralelo, por esta razón es natural
compararlas. La complicación de comparar estos dos métodos es que surgen determinados
problemas, tales como que ambos utilizan la misma palabra para conceptos distintos. Por
ejemplo, un grupo de MPI y un grupo de PVM son objetos bastantes distintos, aunque tengan
similaridades superficiales.
No veremos aquí casi ninguna diferencia. Si es necesario, se aconseja acudir a [22], donde
se realiza una comparativa de MPI y PVM bastante aclaratoria. Sí comentaremos una
diferencia notable, por la importancia que tiene para nuestro trabajo, y que es una de las
explicaciones de porqué se ha elegido MPI como solución adoptada. A continuación se
comenta esta diferencia. PVM, a través de su máquina virtual (implementada como demonios
PVM), proporciona un sistema operativo distribuido, simple pero útil. Algunas interfaces
especiales, tales como “pvm_reg_tasker”, permiten al sistema PVM interactuar con otros
sistemas de gestión de recursos. MPI no suministra una máquina virtual, ni siquiera MPI-2.
Según el MPI Forum, MPI sería una librería para escribir programas de aplicación, no un
sistema operativo distribuido. MPI, más bien, proporciona un camino, a través de un nuevo
objeto MPI (MPI_Info), para comunicarse con cualquier mecanismo que suministre los
servicios del sistema operativo distribuido. El cluster montado en nuestro entorno de trabajo
es homogéneo, todos los nodos disponen del mismo sistema operativo (ya instalado) y tienen
la misma configuración hardware. Esta es la razón de que utilicemos MPI, ya que el sistema
operativo ya instalado en los nodos es el que se encarga de la gestión de recursos.
No obstante, la razón de mayor peso para escoger MPI frente a PVM, es que la librería de
cálculo en paralelo PETSc, que en breve describiremos, hace uso de MPI. Esta simple razón
marca la forma de trabajar y sus implicaciones pertinentes.
41
- NT-MPICH: es un puerto-Windows NT. Contiene un nuevo Dispositivo-
Winsocket (ch_wsock) para comunicación de baja latencia vía TCP/IP, y
una adaptación del dispositivo de memoria compartida ch_lfshmem.
Contiene el dispositivo ch_wsock2, que básicamente es una combinación
de ch_wsock y ch_lfshmem. NT-MPICH soporta las funciones de logging
de MPE y MPI-IO (MPI-E/S) vía ROMIO. También están disponibles un
servicio de ejecución remota y una shell gráfica.
- SCI-MPICH: es la primera implementación de MPI disponible de libre
distribución, que se comunica directamente a través de una red SCI
(Scalable Coherent Interface) rápida. SCI es un estándar cuya
implementación más destacada es una red de área de sistema (SAN) de
altas prestaciones para interconexión de clusters. SCI-MPICH está
disponible para Solaris x86, Linux y también para Windows NT.
42
PowerMPI, para sistemas Parsytec.
43
2.6. PRINCIPIOS BÁSICOS DE FUNCIONAMIENTO DE MPI.
2.6.1. INTRODUCCIÓN.
En el inicio del apartado 2.3.3, se presentaba una introducción a los modelos de
programación en paralelo, donde se incluía el modelo de paso de mensajes. Posteriormente,
en la sección 2.3.3.5., se habló brevemente de los modelos de computación en paralelo SPMD
(Single Program, Multiple Data) y MPMD (Multipe Program, Multiple Data).
A lo largo del tiempo, se han ido implementando diversas variantes de los modelos que se
han ido proponiendo. Por ejemplo, HPF es una interfaz SPMD. Realmente, SPMD y MPMD
son esencialmente lo mismo, puesto que cualquier modelo MPMD puede descomponerse en
SPMD’s.
Una computación en paralelo, consiste en que varios procesos trabajan a la vez sobre
algunos datos locales. Cada proceso tiene variables puramente locales, y no hay ningún
mecanismo por el que cualquier proceso pueda acceder directamente a la memoria de otro.
La compartición de datos entre procesos tiene lugar a través del paso de mensajes, esto es,
envío y recepción explícitos de datos entre procesos.
Hacer notar que el modelo involucra a procesos que, en principio, no necesariamente han
de correr en diferentes procesadores.
Una primera razón para la utilización de este modelo, es que es extremadamente general,
por tanto, puede ser implementado en una gran variedad de plataformas. De forma general,
este modelo permite más control sobre la localización de datos y el flujo dentro de una
aplicación paralela que, por ejemplo, el modelo de memoria compartida.
MPI, del inglés Message Pass Interface, es una implementación del paradigma de paso de
mensajes, que pretende ofrecer una realización del modelo SPMD. MPI es una librería de
funciones (en C) o subrutinas (en Fortran) que pueden ser incluidas en el código fuente de
nuestro programa de aplicación para lograr la comunicación de datos entre procesos.
MPI fue desarrollado tras dos años de discusiones dirigidas por el MPI Forum, un grupo
de sesenta personas representando unas cuarenta organizaciones.
El estándar MPI-1 fue definido en 1994. Este especifica los nombres, secuencias de
llamada y resultados de subrutinas y funciones para ser invocados desde Fortran 77 y C,
respectivamente. Todas las implementaciones de MPI deben ser conformes a las reglas
definidas, de modo que se asegure la portabilidad. Los programas MPI deberían correr en
cualquier plataforma que soporte el estándar MPI. La implementación detallada de las
librerías se deja para los fabricantes, que son libres de producir versiones optimizadas para sus
máquinas.
El estándar MPI-2 provee características adicionales no presentes en MPI-1, incluyendo
herramientas para E/S paralela y gestión dinámica de procesos, entre otras.
MPI, en su interés de buscar la portabilidad del código, proporciona soporte para diversas
arquitecturas paralelas heterogéneas. Además, provee una gran cantidad de funcionalidad,
incluyendo distintas formas de comunicación, rutinas especiales para operaciones colectivas
comunes y la capacidad de manejar tipos de datos definidos por el usuario y diferentes
topologías.
44
Los programas de paso de mensajes, consisten en múltiples instancias de un programa
serie que se comunican por llamadas de librería. En líneas generales, estas llamadas se pueden
dividir en cuatro clases:
Los nombres de todas las entidades MPI (rutinas, constantes, tipos, etc.), comienzan con
‘MPI_’, para evitar conflictos. Así, los nombres de las rutinas en Fortran tienen el formato
“MPI_XXXXX (parámetros, IERR)” (todo en mayúsculas), y en C “MPI_Xxxxx
(parámetros)”.
Las constantes MPI van todas en mayúsculas, tanto en C como en Fortran, por ejemplo:
MPI_COMM_WORLD, MPI_REAL, etc.
Los nombres de los tipos definidos en C, corresponden a muchas entidades MPI (en
Fortran son todos enteros), y siguen la convención de nombrado de funciones C ya descrita;
por ejemplo, MPI_Comm es un tipo correspondiente a un comunicador MPI.
45
Todos los prototipos de rutinas MPI, comandos y constantes, se encuentran muy bien
explicados en el manual Web de MPI [18].
int err;
…
err = MPI_Xxxx(parámetros) ;
…
En Fortran, las subrutinas MPI tienen un argumento entero adicional, que siempre es el
último de la lista de argumentos, y que contiene el estado de error cuando retorna la llamada.
Esto se muestra a continuación:
INTEGER IERR;
…
CALL MPI_XXXXX(parámetros, IERR) ;
…
MPI define y mantiene sus propias estructuras de datos internas, relacionadas con la
comunicación y demás aspectos que conciernen el uso de MPI. Se puede hacer referencia a
esos datos a través de indicadores, que son devueltos por distintas llamadas MPI, y pueden
ser utilizados cono argumentos en otras llamadas MPI.
En C, los indicadores son punteros a tipos de datos especialmente definidos (creados
mediante el mecanismo ‘typedef’ de C). Los arrays son indexados comenzando por ‘0’.
En Fortran, los indicadores son enteros (posiblemente arrays de enteros), y los arrays son
indexados comenzando por ‘1’.
Por ejemplo, MPI_SUCCESS es un entero en C y en Fortran. MPI_COMM_WORLD en C
es un objeto de tipo MPI_Comm (un comunicador), y en Fortran es un entero.
Los indicadores pueden ser copiados utilizando la operación de asignación estándar en C y
en Fortran.
MPI proporciona sus propios tipos de datos de referencia, correspondientes a los distintos
tipos de datos elementales de C y Fortran.
46
Así mismo, MPI permite la traducción automática entre las diferentes representaciones de
tipos en un entorno heterogéneo. Como norma general, los tipos de datos MPI dados en una
recepción deben coincidir con los tipos de datos especificados en un envío.
Además, MPI permite definir tipos de datos arbitrarios construidos a partir de los tipos
básicos, aunque esto no se verá aquí (si es necesario, se aconseja dirigirse al estándar de MPI,
cuya dirección Web se proporciona en la sección 6). En las tablas 3 y 4, se presenta una
comparativa los tipos de datos MPI y los de C y Fortran.
La primera rutina llamada en cualquier programa MPI debe ser la rutina de inicialización
‘MPI_INIT’. Ésta establece el entorno MPI, devolviendo un código de error si ha habido
algún problema. Además, esta rutina debe ser llamada una sola vez en cualquier programa.
En C, la declaración es la siguiente:
int err;
…
err = MPI_Init(&argc, &argv);
Observar que los argumentos de ‘MPI_Init’ son las direcciones de argc y argv, las
variables que contienen los argumentos de línea de comandos pasados al programa.
En Fortran:
INTEGER IERR
…
CALL MPI_INIT(IERR)
47
2.6.2.5. CIERRE DE LAS COMUNICACIONES MPI.
int err;
...
err = MPI_Finalize();
En Fortran:
INTEGER IERR
...
call MPI_FINALIZE(IERR)
Los tres aspectos fundamentales de las comunicaciones punto a punto MPI son:
fuente y destino,
mensajes y
envío y recepción de mensajes.
48
Los mensajes pendientes no se mantienen en una simple cola FIFO, sino que poseen
varios atributos que puede utilizar el proceso destino para determinar qué mensaje recibir.
Un mensaje está formado por un conjunto de bloques de datos, que constituyen el cuerpo
del mensaje, y por un envoltorio, que indica los procesos origen y destino.
MPI utiliza tres partes de información para caracterizar el cuerpo del mensaje de forma
flexible: un buffer, el tipo de datos a enviar y el número de elementos del tipo de datos a ser
enviados. El buffer hace referencia a la localización de comienzo en memoria donde se
encuentran los datos salientes (para enviar) o donde se almacenan los datos entrantes (para
recibir). En el caso más sencillo, el tipo de datos es un tipo elemental tal como flota/REAL,
int/INTEGER, etc. En aplicaciones más avanzadas, puede ser un tipo definido por el usuario,
que es combinación de los tipos básicos. MPI estandariza la designación de tipos elementales.
Esto quiere decir que no hemos de preocuparnos por la representación de dichos tipos en las
distintas máquinas que conforman un entorno heterogéneo.
El envoltorio tiene cuatro partes: el proceso fuente, el proceso destino, el comunicador que
incluye a los procesos fuente y destino, y una etiqueta utilizada para clasificar mensajes.
MPI proporciona una gran flexibilidad a la hora de especificar cómo son enviados los
mensajes. Hay una gran variedad de modos de comunicación que definen el procedimiento
utilizado para transmitir el mensaje, así como un conjunto de criterios para determinar cuando
se completa un evento de comunicación (un envío o recepción particular). Por ejemplo, un
envío síncrono es completado cuando el acuse de recibo del mensaje ha sido aceptado en su
destino. Un envío bufferado es completado cuando los datos salientes han sido copiados a un
buffer local (no se especifica nada sobre la llegada del mensaje a su destino).
En todos los casos, la finalización de un envío implica que es seguro sobrescribir las áreas
de memoria donde los datos fueron almacenados originalmente. Hay cuatro modos de
comunicación disponibles para el envío de datos: estándar, síncrono, bufferado y preparado.
Para recepción sólo hay un modo: una recepción es completada cuando los datos entrantes
realmente han llegado, y están disponibles para su utilización.
Además del modo de envío, un envío o recepción puede ser bloqueante o no-bloqueante.
Un envío o recepción bloqueante no regresa de la llamada a la subrutina hasta que la
operación ha sido realmente completada. Así se asegura que el criterio de terminación
pertinente ha sido satisfecho antes de que el proceso llamante pueda proceder con su
ejecución.
49
Un envío o recepción no-bloqueante regresa inmediatamente de la subrutina, sin ninguna
información sobre si el criterio de terminación ha sido satisfecho. Esto tiene la ventaja de que
el procesador puede realizar otras tareas, mientras las comunicaciones tienen lugar en segundo
plano. Posteriormente, se puede verificar si la operación ha sido realmente completada.
Al realizar una llamada ‘MPI_SEND’, la rutina acepta los siguientes argumentos: del
cuerpo del mensaje tomará el buffer, el tipo de datos y el número de los mismos dentro del
buffer; del envoltorio aceptará el proceso destino, la etiqueta con la clase del mensaje y el
comunicador (el proceso fuente se define implícitamente).
Al llamar a ‘MPI_RECV’, los argumentos que toma dicha rutina son similares a los que
acepta ‘MPI_SEND’, con la diferencia de que algunos de los parámetros se utilizan de forma
distinta. El cuerpo del mensaje tiene los mismos parámetros que los citados para el envío; el
envoltorio contendrá el proceso fuente, la etiqueta de la clase del mensaje y el comunicador
(el proceso destino se define de forma implícita). Además hay un argumento más: el estado,
que da información sobre el mensaje que ha sido recibido.
Los argumentos del envoltorio determinan qué mensaje puede ser recibido por la llamada,
de modo que el proceso fuente, la etiqueta y el comunicador deben coincidir con alguno de los
mensajes pendientes, en orden a ser recibidos. Se pueden utilizar comodines para el valor del
proceso fuente y de la etiqueta, de modo que se puedan recibir mensajes desde cualquier
origen y con cualquier etiqueta. No se puede hacer lo mismo con los comunicadores.
En general, el emisor y el receptor deben estar de acuerdo en el tipo de datos del mensaje,
y es responsabilidad del programador garantizar este acuerdo. Si el emisor y el receptor
utilizan tipos de datos incompatibles, el resultado será indefinido.
Cuando se envía un mensaje utilizando ‘MPI_SEND’, puede ocurrir una de las dos cosas
siguientes:
50
La primera opción permite al proceso remitente dedicarse a otras cosas después de que se
complete la copia. La segunda opción minimiza el uso de memoria, pero puede dar lugar a un
retardo extra para el proceso remitente, retardo que puede ser significativo.
MPI proporciona otra manera de invocar las operaciones de envío y recepción. Es posible
separar el comienzo de una operación de envío o recepción de su finalización, haciendo dos
llamadas separadas a MPI. La primera llamada inicia la operación y, la segunda, la completa.
Entre las dos llamadas, el programa puede seguir ejecutando las operaciones que se precisen.
Las operaciones de comunicación subyacentes son las mismas, tanto si se realiza el envío y
recepción en una llamada simple o en dos llamadas separadas. La diferencia es la interfaz
utilizada.
Al hecho de iniciar una operación de envío se le llama ordenar un envío, y para recepción
se denomina ordenar una recepción. Una vez que un envío o recepción ha sido mandado,
MPI proporciona dos maneras distintas de completarlo. Un proceso puede testear para ver si
la operación ha sido completada, sin bloquear la finalización de dicha operación.
Alternativamente, un proceso puede esperar a que la operación se complete.
Después de mandar un envío o recepción con una llamada a una rutina no-bloqueante, el
proceso de mandado necesita alguna forma de referirse a la operación ordenada. MPI utiliza
indicadores de petición para este propósito. Con estos indicadores, se puede chequear el
estado de las operaciones ordenadas o esperar a su finalización.
El uso selectivo de rutinas no-bloqueantes hace mucho más fácil escribir código evitando
los posibles atascos, cosa que es bastante ventajosa, sobre todo en sistemas que presentan
grandes latencias. Por contra, se incrementa la complejidad del código, haciendo más difícil el
depurado y el mantenimiento del mismo.
51
El programador debe asegurar que todos los procesos que han de comunicarse ejecuten las
mismas operaciones colectivas, y en el mismo orden.
x Operación de difusión:
52
x Operaciones de recolección y dispersión:
x Operaciones de reducción:
OPERACIÓN DESCRIPCIÓN
MPI_MAX Máximo.
MPI_MIN Mínimo.
MPI_SUM Suma.
MPI_PROD Producto.
MPI_LAND AND lógico.
MPI_BAND AND binario.
MPI_LOR OR lógico.
MPI_BOR OR binario.
MPI_LXOR XOR lógico.
MPI_BXOR XOR binario.
53
x Operación de sincronización de barrera:
Hay ocasiones en las que algunos procesadores no pueden continuar con su ejecución
hasta que otros procesadores han completado las instrucciones que están ejecutando. Un
ejemplo común de este comportamiento ocurre cuando el proceso raíz lee datos y los
transmite a otros procesadores. El resto de procesadores deben esperar hasta que se complete
la operación de E/S y se terminen de mover los datos.
La rutina ‘MPI_BARRIER’ bloquea al proceso llamante hasta que todos los procesos del
grupo han llamado a dicha función. Cuando ‘MPI_BARRIER’ devuelve el control al
programa principal, todos los procesos son sincronizados en la barrera.
‘MPI_BARRIER’ está implementada mediante software, lo que provoca que pueda
generar una sobrecarga sustancial en algunas máquinas. Esto implica que sólo se utilice
sincronización por barrera en casos realmente necesarios.
x Operaciones avanzadas:
2.6.5. COMUNICADORES.
Un comunicador es un indicador que representa un grupo de procesadores, que se puede
comunicar con otro. Se requiere el nombre del comunicador como argumento para todas las
comunicaciones punto a punto y colectivas.
El comunicador especificado en las llamadas de envío y recepción debe coincidir para que
tenga lugar la comunicación. Los procesadores se pueden comunicar sólo si comparten un
mismo comunicador. Puede que haya muchos comunicadores, y un proceso dado puede ser
miembro de un número de diferentes comunicadores. Dentro de cada comunicador, los
procesos son numerados consecutivamente, empezando por ‘0’. Este número de identificación
es conocido como el ‘rank’ (orden) del proceso en ese comunicador. El rank se utiliza
también para especificar la fuente y el destino en las llamadas de envío y recepción de datos.
Si un proceso pertenece a más de un comunicador, su rank en cada uno puede ser distinto y,
normalmente, lo será.
MPI proporciona automáticamente un comunicador básico llamado
‘MPI_COMM_WORLD’, que es un comunicador consistente en todos los procesos.
Utilizando ‘MPI_COMM_WORLD’, cada proceso se puede comunicar con cada uno del
resto de procesos.
54
También es posible definir comunicadores adicionales consistentes en subconjuntos de los
procesos disponibles. Con respecto a esto, decir que en MPI existen dos tipos de
comunicadores: intra-comunicadores e inter-comunicadores. Los intra-comunicadores son,
esencialmente, un conjunto de procesos que pueden enviarse mensajes los unos a los otros y
estar involucrados en operaciones de comunicación colectiva. Por ejemplo,
‘MPI_COMM_WORLD’ es un intra-comunicador. Los inter-comunicadores, como su propio
nombre indica, son utilizados para enviar mensajes entre procesos pertenecientes a intra-
comunicadores disjuntos.
Un comunicador está formado por un grupo y un contexto. Un grupo es una colección
ordenada de procesos. Si un grupo consiste en ‘p’ procesos, a cada proceso en el grupo se le
asigna un único rank, que será un entero no negativo en el rango [0, p-1]. Un contexto puede
ser visto como una etiqueta definida por el sistema que se asocia al grupo. Así, dos procesos
que pertenecen al mismo grupo y que utilizan el mismo contexto pueden comunicarse. Este
par grupo-contexto es la forma más básica de un comunicador.
Se pueden asociar más datos a un comunicador. En particular, se puede imponer una
topología o estructura a los procesos de un comunicador, permitiendo un esquema de
direccionamiento más natural.
MPI_Comm comm;
En este caso, los argumentos ‘COMM’, ‘RANK’ e ‘IERR’ son todos del tipo ‘INTEGER’.
Existen diversas rutinas en la librería MPI que realizan diversas tareas relacionadas con la
gestión de comunicadores. Enunciaremos algunas de ellas, las más importantes:
55
‘MPI_GROUP_FREE’: libera un grupo al sistema cuando no se necesita más.
56
2.6.7. ENTRADA / SALIDA PARALELA: MPI-2 Vs. MPI-1
2.6.7.1. INTRODUCCIÓN.
En este punto, veremos cómo múltiples procesos pueden compartir datos almacenados en
espacios de memoria separados. Esto se logra mediante el envío de mensajes entre procesos,
puesto que seguimos hablando de MPI. En esta introducción a la E/S paralela, nos
centraremos en la E/S referida al manejo de ficheros.
El tema de la E/S paralela cubre la cuestión de cómo son distribuidos los datos entre los
dispositivos de E/S. Mientras el subsistema de memoria puede ser diferente de una máquina a
otra, los métodos lógicos de acceso a memoria son, en general, comunes, esto es, debería
aplicarse el mismo modelo de una máquina a otra. La E/S paralela es complicada por el
asunto de que las configuraciones físicas y lógicas difieren de un ordenador a otro.
MPI-2 es la primera versión de MPI que incluye rutinas para el maneja de E/S paralela, no
ocurre así con MPI-1.
Entrada.
Computación.
Salida.
Para aplicaciones científicas, la mayoría de lo que se ha visto hasta ahora sobre MPI se
dirige a la fase de computación. Con sistemas paralelos que permiten modelos de
computación mayores, estas aplicaciones, a menudo, producen grandes cantidades de datos de
salida.
En esta situación, la E/S serie de una máquina paralela puede dar lugar a importantes
penalizaciones por diversas razones:
Puede ser que el tiempo requerido para la fase de E/S a un fichero, canalizada a través de
un solo procesador, sea del mismo orden o mayor que el tiempo requerido para la
computación en paralelo. Esto lleva a replantearse el modelo de E/S, y a ver que el problema
de tiempo del cálculo en paralelo no está muchas veces en la propia computación, sino en la
E/S de datos. Por esta razón aparece la E/S paralela, para dar solución a los problemas que
presenta la E/S serie.
57
están utilizando mallas y rejillas de una resolución más fina de lo habitual. Con frecuencia, los
cálculos realizados en cada nodo necesitan ser almacenados para análisis posteriores. Estas
grandes rejillas o mallas computacionales incrementan los requerimientos de E/S por el gran
número de puntos de datos a ser salvados. Además, incrementan el tiempo de E/S, porque los
datos están siendo dirigidos a través de procesadores más lentos en máquinas masivamente
paralelas.
Otro ejemplo de aplicaciones que incrementan su rendimiento con el uso de la E/S
paralela, son aquellas que tienen pocos cálculos, pero muchas referencias on-line a bases de
datos.
- La E/S serie es la visión tradicional que tienen los lenguajes de alto nivel de la E/S
en general.
- Existe un manejador de fichero único.
- El acceso a ficheros puede ser secuencial o aleatorio, teniendo también en cuenta
los atributos de los ficheros, tales como sólo lectura/escritura, etc.
- Los datos pueden ser escritos con o sin formato, en modo binario o modo texto.
- Existen funciones integradas en el propio sistema para acceso a la E/S.
58
rank de cada proceso. Al final de la ejecución, los ficheros se combinan en un solo fichero de
datos.
Las máquinas paralelas pueden tener sistemas de E/S paralela que se ajusten a una de las
dos categorías presentadas, aunque es posible tener sistemas híbridos que cumplan las
características de ambas.
Uno de los cambios significantes del paso de MPI-1 a MPI-2, fue la adición de la E/S
paralela. Antes de la aparición de MPI-2, se podía lograr la E/S paralela sin llamadas a MPI
con métodos tales como los sistemas de ficheros paralelos, donde se llevaba a cabo una
partición lógica de ficheros.
La E/S paralela de MPI-2, proporciona una interfaz de alto nivel con soporte para la
partición de ficheros de datos entre procesos, y una interfaz colectiva para soporte de
transferencias completas de estructuras de datos entre ficheros y memorias de procesos.
Ahora, la lectura y escritura de datos son tratadas mucho más como envío de mensajes a disco
y recepción de mensajes desde los dispositivos de almacenamiento de datos. No se utilizan las
rutinas estándar de E/S de C, C++ y Fortran.
Algunas de las características destacables de la E/S paralela de MPI-2 son:
59
2.7. LIBRERÍAS DE MATEMÁTICAS PARALELAS.
2.7.1. INTRODUCCIÓN.
La gran ventaja de las librerías de Matemáticas paralelas, es que no hemos de escribir el
código MPI que se necesita como soporte para implementar un programa paralelo. Lo único
que se ha de hacer es llamar a una subrutina de la librería de matemáticas, que ya incluye el
código MPI necesario. Estas librerías son completas y legibles, y han sido optimizadas desde
un punto de vista serie y paralelo, a partir de algoritmos paralelos excelentes.
Las librerías que yacen sobre el área con el término “global”, son las librerías paralelas.
De forma análoga a lo que ocurre en el caso de las librerías serie, ScaLAPACK contiene y
está construida sobre PBLAS. Estas librerías se utilizan en sistemas multiprocesador para
cálculos de Álgebra lineal en paralelo. En la figura 19, se puede observar que ScaLAPACK
está construida también sobre BLACS, y esto se debe a que esta última librería es la
encargada de transferir los datos de la memoria local de un procesador a otra. En realidad, las
rutinas de la librería BLACS son rutinas de envoltorio que llaman a una librería de paso de
mensajes de más bajo nivel, la cual suele ser MPI.
BLAS y PBLAS son las librerías que contienen las versiones serie y paralela,
respectivamente, de los procedimientos del Álgebra lineal básica. Cada librería contiene
rutinas que pertenecen a uno de los tres niveles siguientes:
60
- Nivel 2: Operaciones matriz – vector.
- Nivel 3: Operaciones matriz – matriz.
LAPACK y ScaLAPACK contienen rutinas para cálculos de Álgebra lineal más
sofisticados. Hay tres tipos de problemas avanzados que pueden resolver estas librerías:
- Solución de un conjunto de ecuaciones lineales simultáneas.
- Problemas de autovalores / autovectores.
- Método de aproximación de mínimos cuadrados
2.7.2.1. EJEMPLO 1
Las columnas de la matriz y los elementos del vector columna se reparten entre los
procesadores mediante operaciones de dispersión (scatter) de MPI.
El problema que se ha presentado está bien para implementarlo en Fortran, ya que este
lenguaje almacena las matrices por columnas. Además, sólo es necesario difundir una parte
del vector multiplicado a cada proceso, no el vector entero.
El caso del lenguaje C es el contrario, almacena las matrices por filas, y sería necesario
que todos los procesos contengan el vector multiplicado en su totalidad, para poder realizar el
producto fila de la matriz por vector. Esto se presenta en la figura 21.
61
Para realizar esto mismo en Fortran, lo primero
es difundir (broadcast de MPI) el vector
multiplicado completo a todos los procesos.
Posteriormente, se distribuyen las filas (scatter de
MPI) entre los procesos y cada uno realiza su
multiplicación independiente. Por último, se hace
uso de la operación de recolección (gather de MPI)
para obtener el vector final.
Figura 21. Producto paralelo matriz por
vector descompuesto por filas.
2.7.2.2. EJEMPLO 2
Figura 22. Producto paralelo matriz-matriz en Fortran. Figura 23. Producto paralelo matriz-matriz en C.
62
PARASOL, que es un entorno integrado para la solución de sistemas lineales
dispersos; está escrito en Fortran 90 y utiliza MPI-1.1 para las comunicaciones.
PETSc: “The Portable, Extensible Toolkit for Scientific Computation”.
PETSc es un conjunto de librerías numéricas para la solución paralela de sistemas
lineales dispersos, ecuaciones no lineales provenientes de la discretización de
PDE’s, etc. El acercamiento y la familiarización con esta librería es el objetivo
final de nuestro estudio, de ahí que se dedique una sección completa a dicho fin.
63