SlideShare uma empresa Scribd logo
1 de 27
Rendimiento de Algoritmos Paralelos de Multiplicación de
         Matrices implementados con MPI

                            Cristhian Parra1, Fernando Mancía1
               1
                   Facultad Politécnica de la Universidad Nacional de Asunción
                     Estudiantes del 9no Semestre de Ingeniería Informática
                                  {cparra,fmancia}@cnc.una.py



  Resumen: El problema de la multiplicación de matrices, ha sido ampliamente
  estudiado en el ámbito académico, y sus soluciones han encontrado aplicaciones en
  diversos campos del mundo científico. La facilidad para dividir este problema en
  diferentes partes independientes, ha causado el surgimiento de numerosos algoritmos
  paralelos que lo resuelven eficientemente. En este trabajo, se presentan los detalles de
  implementación de 4 algoritmos bien conocidos, aplicados a matrices cuadradas
  densas. También se presentan los resultados de algunas pruebas llevadas a cabo para
  analizar el rendimiento de cada algoritmo.

  Palabras Clave: matrices, algoritmos de multiplicación de matrices, particionamiento
  de datos, algoritmos paralelos, MPI, Cannon, DNS, particionamiento por bloque
  cíclico, 2D diagonal.
1 Introducción
Los algoritmos de matrices densas, y entre ellos los de multiplicación de matrices, han
encontrado numerosas aplicaciones en la resolución de problemas tanto numéricos, como
aquellos que no son numéricos.

En ciencias de la computación, la multiplicación de matrices ha encontrado usos importantes
en campos como la Criptografía o la Computación y Diseño Gráfico [3]. Todas estas
aplicaciones han motivado el estudio y optimización de algoritmos que resuelvan este
problema. Además, las matrices y sus operaciones son una parte muy importante del Álgebra
Lineal, cuyas aplicaciones en el mundo científico y de la computación son innumerables.

La facilidad con que se puede particionar el problema de multiplicar dos matrices cuadradas
y densas, lo convierten en un candidato ideal para estudiar los conceptos de computación
paralela, y permiten que sea fácil formular algoritmos que aprovechen los recursos de un
entorno paralelo.

En este trabajo, se describen 4 algoritmos paralelos para multiplicar matrices cuadradas y
densas, incluyendo la explicación de los detalles de implementación. Se presentan los
resultados de diversas pruebas realizadas, y las conclusiones extraídas a partir del análisis de
estas pruebas.

El objetivo del trabajo es llevar a la práctica conceptos de computación paralela, analizar
algoritmos paralelos para multiplicación de matrices, realizar las implementaciones y
ejecutar pruebas que nos permitan extender el análisis preliminar.


2 Descripción general.
En primer lugar, es importante definir el problema que queremos resolver y sus parámetros
correspondientes.

Dada dos matrices densas de tamaño NxN, se necesita obtener el resultado de la
multiplicación de estas dos matrices, que es otra matriz NxN igualmente densa, en un tiempo
razonable. Una Matriz es Densa cuando existe un bajo porcentaje de ceros en la misma.

El parámetro fundamental del problema es el tamaño de la matriz, cuantificada por N. En un
entorno de ejecución paralelo, existen dos parámetros más que se tienen en cuenta para
nuestros análisis: la cantidad de procesos y la cantidad de procesadores físicos.

Para resolver el problema, se implementan los siguientes 4 algoritmos:
       ✔ Algoritmo 2D con particionamiento por bloques y distribución cíclica, basada en
            el particionamiento propuesto en el capítulo 3 de [1], que se llamará en adelante
            2D cíclico.
       ✔ Algoritmo DNS, explicado en [1] y extendido en [4] y [5].
       ✔ Algoritmo de Cannon, explicado en [1] y generalizado en [4].
       ✔ Algoritmo 2D-Diagonal, presentado en [5].


El trabajo está organizado de la siguiente manera:
   1. Las secciones 1 y 2 proporcionan una visión global del trabajo realizado.


                                               2/27
2. La sección 3 proporciona una explicación detallada de cada algoritmo y su
     implementación.
  3. En la sección 4 se describen las pruebas realizadas.
  4. La sección 5 alberga la descripción de las métricas obtenidas, los resultados en forma
     de gráficos, acompañados de algunos comentarios que forman parte del análisis de
     dichos resultados.
  5. La sección 6 proporciona algunas reflexiones de conclusión a las que llegamos al
     finalizar el trabajo.
  6. La sección 7 propone algunas problemáticas y trabajos futuros.
  7. La sección 8 presenta nuestras fuentes de información.
  8. La sección 9, presenta en forma de anexo, las tablas resumidas de resultados.

2.1 Preliminares

2.1.1 Detalles de implementación comunes a todos los algoritmos:

La implementación fue hecha usando el lenguaje de programación C (Ansi C) y la
implementación del estándar MPI conocido como OpenMPI. Todo el desarrollo y las
pruebas realizadas, fueron llevadas a cabo en el Sistema Operativo Linux Fedora 9, con
distintas versiones menores del kernel 2.6.25.

Las matrices se generan en tiempo de ejecución, ya que esto era más práctico para realizar
las pruebas de rendimiento, aunque está disponible la posibilidad de leer las matrices de
archivos en formatos de MatrixMarket, como se hacen [6].

Las matrices son representadas en forma lineal, por lo que para saber el elemento Mat[i,j] se
debe acceder de la siguiente manera:
  Mat[(i*cant_columas) + j]

La implementación MPI utilizada, OpenMPI, está disponible para su descarga gratuita en [7]
y es Open Source.

Para las pruebas realizadas, establecimos cantidades de procesos fijos: 4, 9 y 16 procesos.
Solo en el caso de DNS utilizamos cantidades de proceso de 8 y 27, ya que en este algoritmo
se requería una cantidad cúbica. Ejecutamos los algoritmos en un entorno de cuatro
computadoras conectadas mediante una red ethernet de 10/100 Mbps.

De las cuatro máquinas que utilizamos para pruebas, tres contaban con procesadores doble
núcleo. Detalles más precisos sobre el ambiente de prueba se presentan en la sección 4.

2.1.2 Disponibilidad del código fuente:

Todo el proyecto está disponible a través de Subversion en el repositorio de Google Code,
http://mmulfpuna.googlecode.com/svn/trunk/srcmpi. Personas que no son miembros del
proyecto pueden acceder al mismo y descargar los fuentes de la siguiente manera:

  svn checkout http://mmulfpuna.googlecode.com/svn/trunk/srcmpi mmulfpuna-
  read-only




                                             3/27
3 Algoritmos Implementados

3.1 Algoritmo 2D Cíclico
En realidad, no existe un algoritmo 2D con particionamiento por Bloque Cíclico. Solo existe
el concepto sobre el particionamiento por bloque y la distribución cíclica de los bloques, que
se presenta y explica en [1].

3.1.1 Particionamiento por Bloques cíclico:

Cuando se debe particionar un determinado problema, para distribuirlo entre distintos
procesos, dos objetivos igualmente importante, suelen entrar en conflicto:
       ✔ Balancear correctamente la carga.
       ✔ Minimizar el tiempo de ociosidad (Idling) de los procesos.

En términos de la multiplicación de matrices, el primer objetivo implica distribuir las tareas
de multiplicación en los procesos, de manera que todos los procesos computen matrices
igualmente densas. El segundo objetivo implica solapamiento de comunicaciones con
cómputo.

Además de estos objetivos, existe la realidad de que normalmente existen menos
procesadores físicos disponibles, que la cantidad de procesos en los que queremos dividir
nuestro problema.

Para dar solución a este último problema, y al mismo tiempo encontrar una optimización
equilibrada de los dos objetivos presentados, el particionamiento por Bloques cíclicos
establece lo siguiente:
       ✔ Dividir el problema en más tareas que procesos.
       ✔ Asignar las tareas a los procesos de manera cíclica, de manera tal a que se
            solapen adecuadamente las comunicaciones con las tareas de cómputo.
       ✔ Agrupar los procesos en bloque, de manera tal a que cada proceso, se encargue
            de zonas distintas de la matriz y no asuma el cómputo de largos bloques
            consecutivos que pueden tener un patrón de carga mayor que otras partes de la
            matriz.




Figura 1. Particionamiento por Bloque con distribución o mapeamiento Cíclico. La imagen (a) muestra
                            la versión 1D y la imagen (b) la versión 2D.


La Figura 1 muestra un ejemplo de este tipo de particionamiento y mapeamiento1.

1   Las figuras fueron extraídas directamente de [1] para extender y clarificar las explicaciones.

                                                     4/27
Nótese que si la matriz es densa, el agrupamiento de bloques de las matrices hace que al
final, a cada proceso le haya tocado una bloque de tarea de cada zona distinta de la matriz,
haciendo que el balance general de la carga sea equilibrado.

3.1.2 Algoritmo implementado:

El algoritmo implementado, utiliza el particionamiento descrito en la sección anterior, y lo
aplica a la matriz de salida. De esta manera, cada proceso calcula un bloque de la salida.

Se sigue exactamente la idea del particionamiento, y se utiliza un esquema maestro-esclavo
para paralelizar el trabajo.

Lo primero que realiza el algoritmo es dividir la matriz de salida, de tamaño N, en N tareas
diferentes, lo que implica hacer una división en  N ×  N bloques. La elección de la
cantidad de tareas, corresponde a que es el número óptimo que permite tener tamaños de
bloque balanceados.

Luego, se recorren los índices de la matriz resultado en bloques  P × P tareas, y se
asignan estas a los procesos P i de manera cíclica, según se muestra en la siguiente
ecuación.
                                  ∀ i=0 k ⇒ P i=k mod P
Elegido el proceso al cual asignar una tarea, se empaquetan los datos que requerirá este (filas
y columnas de las matrices de entrada), y se le envía este paquete en un solo Mensaje a
través de MPI_Send.

En cuánto al esquema maestro-esclavo, existen dos posibilidades:
      ✔ La existencia de un proceso dedicado exclusivamente a la asignación y
           distribución de tareas.
      ✔ El proceso 0 es el maestro, y además procesa localmente algunos bloques.

La segunda opción es atractiva por su simpleza, y sería recomendable en redes de mucha
latencia, sin embargo, cuando estamos en redes de alto rendimiento, puede ocurrir que el
proceso maestro se convierta en un cuello de botella.

La implementación probada en este trabajo corresponde a la segunda opción, por su
simplicidad. La estructura principal del algoritmo es la siguiente:

          int SP = sqrt(P); int ST = sqrt(N); int k = 0;

          for (i=0; i < N; i += SP) {
            for (j=0; j < N; j += SP) {
              for (x=i; x < (i+SP); x += ST) {
                for (y=j; y < (j+SP); y += ST) {
                  ...
                  int Pdest = P%k;
                  ...
                  if (Pdestino != 0) {

                      Bloque <-- Empaquetar Bloque (x,y)
                      /* Implica empaquetar desde x, ST



                                              5/27
* filas de A, y desde y, ST
                       * columnas de B
                       */
                     MPI_Send( Bloque, ST * ST *N,
                                MPI_FLOAT, Pdest, Tag,
                                MPI_COMM_WORLD);
                   } else {
                     Bloque Local <-- Empaquetar Bloque
                                       (x,y) Local
                   }
                   ...
                   k++;
                  }
                }
                ...
                Multiplicar Bloque Local.
                Cargar resultado en C.
                ...
                for(proc = 0; proc < P, proc++) {
                  if (proc != 0) {
                    MPI_Status status;
                    MPI_Recv( BloqueRec, ST * ST * N,
                              MPI_FLOAT, 0, Tag,
                              MPI_COMM_WORLD, &status);
                    Cargar BloqueRec a matriz C
                  }
                }
            }
          }
          ...


El código ejecutado por los esclavos es sencillamente el siguiente:
          while (done == 0) {
            ...
            MPI_Recv( Bloques, ST * ST * N, MPI_FLOAT,0, Tag,
                      MPI_COMM_WORLD, &status);
            ...
            Multiplicar los bloques recibidos.
            ...
            MPI_Send( Salida, ST * ST, MPI_FLOAT, 0, Tag,
                      MPI_COMM_WORLD);
          }
          ...


El algoritmo presentará una sobrecarga y un cuello de botella importante en redes de alto
rendimiento, en las cuales el tiempo de envío de mensajes será mucho menor que el tiempo
que dura la computación, y muy pronto los procesadores esclavos se quedarán ociosos.


3.1.3 Costo Asintótico.

Para analizar el costo asintótico, debemos basarnos en la longitud del ciclo principal del
algoritmo. Los principales costos de comunicación se encuentran en el Send más interno. Por
cada tarea, se realiza un envío desde el maestro a un esclavo, a lo que este responde con otro
Send de la respuesta.




                                              6/27
Además, aunque no figura en nuestro algoritmo simplificado mostrado en la página anterior,
luego de cada envío, a los procesos se les envía una pequeño mensaje de 1 palabra para
confirmar la continuidad del ciclo. Podríamos considerar, para simplificar el análisis, que se
envía un solo mensaje, pero con una palabra más de longitud.

En síntesis, teniendo en cuenta que se realizan N tareas, se realizarían N Sends, menos la
cantidad de veces en la que el proceso asignado es el 0. Para simplificar el análisis, diremos
que en realidad el Proceso 0, se envía su tarea a sí mismo, de manera a tener tantos envíos
como tareas. En cada uno de estos envíos, se envían palabras de tipo float, igual a la cantidad
de elementos de los bloques de matriz enviados. Por cada tarea, se envía un bloque de
   N × N (filas de A) más N × N (columnas de B).
A esto hay que sumarle la cantidad de envíos realizados desde los procesos para enviar sus
resultados. En estos envíos la cantidad de palabras es igual a  N ×  N =N , ya que
corresponde al bloque resultado de la multiplicación de los bloques citados más arriba. A
cada proceso, se le asignan N/P tareas, por lo cual, esta es la cantidad de envíos de respuesta.

Además, por cada envío realizado desde el proceso maestro, se realiza 1 envío más para
confirmar la continuación o no del algoritmo. En síntesis, se realiza la siguiente cantidad de
envíos. De esta manera, tenemos la siguiente función sobre el tiempo de comunicaciones.
                                      1
                       t s× N ×2      t w ×N 2× N × N N 1
                                      P
En cuánto al cómputo, cada proceso realiza un cómputo similar de orden               N 3 , sin
                                                                                     P
embargo, hay una importante sobrecarga para el proceso maestro que además de realizar el
cómputo de computación, realiza un cómputo lineal por cada envío (cargar el buffer de
envío) y otro cómputo extra de cargar las matrices en la estructura final a medida que llegan
las respuestas. Aún así, esta sobrecarga no afecta el orden asintótico del cómputo realizado
en cada proceso.

3.2 Algoritmo 2D Diagonal
El algoritmo 2D diagonal es un algoritmo que sirve como base a otro, de tipo 3D, que
optimiza las comunicaciones realizadas.

Se organizan los P procesos en una malla 2D de  P× P procesos. La matriz A es
particionada en  P grupos de columnas y lo propio se hace con la matriz B, pero en
grupos de filas.

En el primer paso del algoritmo, se realizan  P envíos para armar la distribución inicial
del algoritmo. Luego de esta distribución los procesadores pjj en la diagonal principal tienen
cada uno el jth grupo de filas de B y el jth grupo de columnas de A.

A partir de aquí, se crean dos sub-topologías: una que conecta a los procesos con sus pares
de la misma fila, y otra que conecta a los procesos con sus pares de la misma columna.
Entonces se inicia la lógica principal del algoritmo, que consiste en hacer 3 pasos muy
sencillos:



                                               7/27
1. Broadcasting (MPI_Bcast) desde Pjj a los procesos de la misma fila Pj* para enviar a
       todos el jth grupo de columnas de A, como se muestra en la Figura 22.
    2. One to all personalized Broadcast (MPI_Scatter) de los subbloques de tamaño
           N           N     del jth grupo de filas de B, desde Pjj . De esta manera, cada proceso
                  ×        
              P         P
       Pj* se encarga de computar el producto externo de las columnas de A y las filas de B
       inicialmente almacenadas en pjj.
    3. All to One Reduce (MPI_Reduce) desde cada proceso al proceso diagonal
       correspondiente a su columna, a través de la operación de suma.

El término personalizado del paso 2, se refiere a que solo la porción del grupo de filas de B
(Bik) que es necesario para computar una columna i del producto externo de la jth columna de
A por la jth fila de B, se le pasa al procesador Pkj

La ultima etapa reduce el resultado por adición a lo largo de la dirección y. La matriz final C
se obtiene a lo largo de los procesadores diagonales. Cada procesador, envía su producto
externo a la diagonal principal que se encarga de procesar C*,i




                          Figura 2. Esquema general del algoritmo 2D Diagonal.
De esta manera, a lo largo de la diagonal principal se encuentra el resultado final de la
multiplicación. A continuación se muestra el bloque de código principal del algoritmo. Es
notable la simplicidad del mismo.
              ...

              remains[0] = 0;
              remains[1] = 1;

2   Las figuras fueron extraídas directamente de [5] para extender y clarificar las explicaciones.

                                                     8/27
MPI_Cart_sub(Comm2d,remains,&commF);

           remains[0] = 1;
           remains[1] = 0;
           MPI_Cart_sub(Comm2d,remains,&commC);
           ...
           int rrank = mycoords[0];
           MPI_Bcast(IthGrupoA,GrupSize*N,MPI_FLOAT,rrank,commF);

           if (mycoords[0] == mycoords[1] && mycoords[0] ) {
             cargar_blocks(BloquesB,IthGrupoB,N,GrupSize,GrupSize);
           }


           MPI_Scatter( BloquesB, GrupSize*GrupSize, MPI_FLOAT,
                        BloqueB,GrupSize*GrupSize, MPI_FLOAT,
                        mycoords[0], commF);

           calcular_producto_externo();

           MPI_Reduce( IProduct,IProductReduced,GrupSize*N,
                       MPI_FLOAT,MPI_SUM,mycoords[1],commC);
           ...


3.2.1 Costo Asintótico.

El gasto de comunicación realizado en este algoritmo, se resume en la suma de los gastos en
las tres operaciones fundamentales que realiza el algoritmo:
   1.  P operaciones de Broadcasting, una en cada proceso diagonal, enviando
           N          palabras correspondientes a las filas de A.
               × N
           P
  2. Una operación de Scatter en la que se distribuyen       N     N   palabras a a cada
                                                              ×   
                                                             P P
     proceso de una fila de la malla.
  3. Una operación de Reduce a los largo de las columnas que reduce bloques de
         N          palabras.
               × N
           P
Teniendo en cuenta estos parámetros, y en base a los costos de las primitivas de
comunicación presentadas y analizadas con profundidad en el capítulo 4 de [1], nuestro
tiempo de ejecución estaría definido por los siguientes componentes:

Broadcasting entre     P    procesos:

                N
  t st w ×      ×N ×log  P 
                P
Scatter entre    P    procesos:
                          N     N
  t s×log  P t w ×     ×   ×  P−1
                          P P
Reduce entre     P    procesos (mismo costo que el Broadcast):

                                             9/27
N
    t st w ×      ×N ×log   P 
                  P
La suma final de estos tres componentes es la siguientes:
                                               N2
                    3×t s×log   P t w ×      × 2×log   P P−1
                                               P
3.3 Algoritmo de Cannon
El algoritmo es una versión de uso eficiente de memoria, comparada con el algoritmo simple.
Utiliza una malla de procesadores virtuales y la partición de los datos son de entrada
inicialmente para las matrices A y B, aunque a nivel de mapeamiento de tareas, tenemos un
mapeamiento de salidas, ya que cada proceso computa un bloque de la matriz de salida.

Para comenzar se crea la topología cartesiana de 2 dimensiones, y en cada dimensión se
tienen  P procesos. Entonces quedan identificados los procesos desde P 0,0 hasta
    P  P −1 ,  P −1 .
                                                                          N
Las matrices A y B se particionan en bloques de tamaño           Tam=        quedando en cada
                                                                          P
procesador en cada momento un bloque de tamaño Tam de A y otro de B. Luego el Proceso
P0,0 es el encargado de pasar al resto de los procesos el bloque que le corresponde.

El algoritmo propone una alineación inicial de los bloques de A y B en cada proceso. En la
implementación presentada el proceso P0,0 es el encargado de enviar al Proceso P(i,j) el bloque
de A y B ya alineado quedando en el proceso P(i, j) el bloque A(i, j+i) y el bloque B(i+j , j).

En el caso de que i j  P  , hacemos i j−  P  para simular una estructura
toroidal (circular). Una vez que cada procesador ya tiene los bloques A y B que le
corresponden, los multiplica y almacena su resultado en un bloque para C con las
coordenadas del mismo proceso. Luego se hacen   P −1 corrimientos circulares en
cada procesador, de las filas de A por la izquierda y las columnas B por arriba. Las figuras
siguientes, ilustran el proceso de manera gráfica. Luego se muestra el código principal del
algoritmo implementado3.




3   Las imágenes presentadas en esta sección fueron extraídas de [1] para aclarar mejor el algoritmo
    implementado.

                                                 10/27
Figure 3. Alineación inicial de A y B.




   Figure 4. A y B luego de la alineación inicial y luego del primer corrimiento.




   Figure 5. Alineación de las submatrices luego del tercer y cuarto corrimiento.

for(pasos=1; pasos< raiz_p; pasos++){

   // Desplazamiento Para Matriz A
   MPI_Cart_shift(malla, 1, -1, &origen,
                  &destino);

   MPI_Sendrecv_replace(buffA, tam_bloq *
                     tam_bloq, MPI_FLOAT,
                     destino, 0 , origen,
                     0, malla, &estado_msg );

   // Desplazamiento Para Matriz B
   MPI_Cart_shift(malla, 0, -1, &origen,
                  &destino);

   MPI_Sendrecv_replace(buffB, tam_bloq *
                     tam_bloq, MPI_FLOAT,
                     destino, 0 , origen,
                     0, malla, &estado_msg );

   //Pasamos del buffer al bloque local
   buff2Bloque(bloqueA, tamanho_bloque,
                buffA);

   buff2Bloque(bloqueB, tamanho_bloque,
                buffB);

   //Multiplicación
   acumular_multiplicar(bloqueA, bloqueB,
                          bloqueC);
  }


                                        11/27
En cada paso, cada procesador multiplica su bloque de A por su bloque de B, y le suma al
bloque de C que tiene. Finaliza el algoritmo y cada procesador P(i, j) tiene el bloque C(i, j) de la
matriz resultado.

3.3.1 Diferencias, Mejoras

El alineamiento inicial que se propone en el artículo [4], el algoritmo asume que en cada
procesador P(i,j) se encuentra el bloque A(i,j) y B(i,j) y luego realiza i corrimientos a la izquierda
para A y j corrimientos arriba para B. En nuestra implementación, sin embargo, el proceso
P(0,0) calcula que bloque de A y de B es el que corresponde a los demás procesos después de
la alineación inicial.

Pensamos que esto podría mejorar el tiempo de ejecución en cada proceso evitando los
corrimientos iniciales, pero esta mejora solo se dará en el caso de que efectivamente el
proceso P(0,0) sea el encargado de distribuir los bloques, caso contrario no sería una mejora.

3.3.2 Limitaciones

Las limitaciones y verificaciones de la implementación presentada son las siguientes:
  • La cantidad de procesos debe ser un cuadrado perfecto. Para la distribución equitativa
      de los bloques a los procesos en cada dimensión.
  • La cantidad de elementos (N) debe ser divisible entre la raíz cuadrada de la cantidad de
      procesos (P). Para que todos los bloques tengan el mismo tamaño, haciendo mas
      sencilla la implementación.

3.3.3 Análisis Asintótico

Considerando solamente los corrimientos de a uno y la multiplicación de cada bloque en los
procesos, tenemos que en cada corrimiento se pasan tam_bloque * tam_bloque elementos,
              N     N    N2
que es         ×   =    , que seria para cada proceso, tanto para A y B, por lo cual
              P P P
multiplicamos este término por 2.

Si consideramos la comunicación y el tiempo de inicialización, tenemos que el gasto de
comunicación es el siguientes:

                                                           N2
                                           2×t st w ×      
                                                           P
Por su parte, el procesamiento en sí de la multiplicación, asumiendo que esta y la suma
toman una unidad de tiempo, entonces tendríamos un costo de tam_bloq * tam_bloq
*tam_bloq es decir:

                                    N     N     N    N3
                                     ×   ×   =
                                    P  P  P  P ×  P 
Entonces el tiempo total de ejecución paralelo sería:

                                           N3                 N
                                    T p=      2×t s t w ×    
                                           P                  P
                                                 12/27
3.4 Algoritmo DNS (Dekel, Nassimi, Sahni)
El DNS es un algoritmo para la multiplicación de matrices densas, que lleva las siglas de sus
creadores (Dekel, Nassimi, Sahni). Está basado en particionamiento de datos intermedios y
está diseñado para usar una topología de procesadores en tres dimensiones. El algoritmo
asume que en cada procesador se realiza una simple multiplicación escalar o de matrices en
bloques más pequeños. Para la descripción se tienen P procesadores y el tamaño de bloques
entonces es q= P . Generalizamos para que el algoritmo resuelva por bloques.
                 3



En la implementación realizada, se crea la topología en 3 dimensiones, luego el proceso
P(0,0,0) realiza la distribución de los bloques de A y B en los procesos del plano 0. Después de
este paso, todos los procesos P(i,j0) tienen el bloque A(i,j) y el bloque B(i,j). Este paso de
comunicación inicial en el plano cero no se especifica como parte del algoritmo en su
definición, sin embargo, para la implementación de este trabajo se ha decidido hacerlo.

Luego cada proceso del plano 0 (Pi,j,0), envía las columnas j de A(*,j) y las filas i de B(i,*) a los
pla0nos k=i para el bloque de A y k=j para el bloque de B. En los demás planos cada
proceso recibe su parte de A y B.

A continuación, cada proceso que está en el plano k=j y tiene la columna j debe replicar su
bloque de A a los demás procesos que comparten su plano, para lo cual se utiliza la primitiva
MPI_Bcast. Lo mismo para los procesos de k=i y que tienen la fila i, caso en el que se
replica el bloque de B a los de su mismo plano y fila. A continuación se muestra la parte del
código que realiza dicha acción.
           int remainA[3]={0,1,0};
           MPI_Comm comm_1d_A;
           MPI_Cart_sub(comm_3d, remainA, &comm_1d_A );
           MPI_Bcast(buffA, tamanho_bloque *
                    tamanho_bloque, MPI_FLOAT, micoord[2],
                    comm_1d_A);

           int remainB[3]={1,0,0};
           MPI_Comm comm_1d_B;
           MPI_Cart_sub(comm_3d, remainB, &comm_1d_B );
           MPI_Bcast(buffB, tamanho_bloque *
                    tamanho_bloque, MPI_FLOAT, micoord[2],
                    comm_1d_B);


Luego cada uno de los P procesadores ya tiene el bloque de A y de B que le corresponde, es
decir, el procesador P(i,j,k) tiene el bloque A(i,k) y el bloque B(k,j).

Después de eso cada proceso realiza una simple multiplicación entre el bloque de A y B que
tiene, y utilizando la función MPI_Reduce se realiza un all_to_one_reduce entre los
elementos P(i,j,*) a través de la operación de suma. A continuación se resume el código para
el paso final.
              acumular_multiplicar(bloqueA, bloqueB,
                                   bloqueC);
              bloque2Buff(bloqueC, tamanho_bloque, buffC);

              //Creamos un comunicador vertical
              MPI_Comm comm_vertical;
              int comm_vertical_id;
              int remain[3]={0,0,1};
              MPI_Cart_sub(comm_3d, remain,


                                                13/27
&comm_vertical);
             MPI_Comm_rank(comm_vertical,
                             &comm_vertical_id);

             MPI_Reduce( buffC , bufferFinal,
                         tamanho_bloque * tamanho_bloque,
                         MPI_FLOAT, MPI_SUM, 0,
                         comm_vertical);

             buff2Bloque(bloqueFinal, tamanho_bloque,
                         bufferFinal);



Las siguientes dos imágenes, ilustran el algoritmo visualmente.




     Figure 6. La distribución inicial de A y B, y luego de realizar el envío de Aij desde Pij0 a Pijj




                                                   14/27
Figure 7. Distribución luego del los Broadcastings de A y B


3.4.1 Diferencias con la propuesta original.

En la implementación presentada el proceso (0,0,0) es el que lee toda la matriz A y B y
empieza a distribuir a los procesos del plano cero. Esto hace que este proceso se pueda
constituir en un cuello de botella al inicio del algoritmo, sobre todo para el caso de matrices
grandes, en el que se puede producir la saturación del socket de envío de este proceso.

Por otro lado, los elementos se tratan por bloques, en lugar de elementos como se muestra en
[1].

Además, para el paso final del Reduce, todos los procesos P(i,j,k) suman su bloque de C entre
los P(i,j,*) y estos se almacenan en los procesos del plano cero. Entonces al finalizar el
algoritmo, la matriz C está distribuida entre los procesos P(0,0,0) a P(q,q,0), siendo q= P
                                                                                         3


3.4.2 Limitaciones:

Las limitaciones y verificaciones de la implementación presentada son las siguientes:
  • La cantidad de procesos debe ser un cubo perfecto. Para la distribución equitativa de
      los bloques a los procesos en cada una de las 3 dimensiones.
  • La cantidad de elementos (N) debe ser divisible entre la raíz cúbica de la cantidad de
      procesos (P). Para que todos los bloques tengan el mismo tamaño, haciendo mas
      sencilla la implementación.

3.4.3 Tiempo de ejecución

Toma un paso para multiplicar y q pasos para sumar, con costo Θ (log q), siempre teniendo
  q= P .
     3



En cuanto a la comunicación, el primer paso de comunicación uno a uno se ejecuta en A y en
                                                        n 2
B y toma un tiempo para cada matriz de           tstw×  tw×log q  . El segundo
                                                        q


                                               15/27
paso es un broadcast de uno a todos que se ejecuta en A y en B y toma un tiempo para cada
                           n 2
matriz de    ts×logqtw×  ×log q
                           q
La acumulación de nodo simple final se ejecuta una sola vez (para la matriz C) y toma un
                                  2
                          n
tiempo      tslogqtw×  ×log q
                          q

4 Plan de Pruebas.
A continuación se describen los detalles de las pruebas, desde las configuraciones y entorno
de ejecución paralelo hasta los cálculos de los datos de prueba y como éstos fueron
ejecutados.

4.1 Datos de prueba
Los parámetros de ejecución de los algoritmos paralelos son los siguientes:
  • N = Tamaño de la matrices de entrada y resultado
  • P = Cantidad de procesos.
  • C = Cantidad de máquinas.

Atendiendo las limitaciones de N y P descritas en cada algoritmo en la sección 3, a
continuación se presenta una tabla que resume el plan de ejecución de las pruebas. La
cantidad de máquinas (C ) fue constante e igual 4 (7 procesadores= 3 dual core + 1 single
core), luego se detallan totalmente las especificaciones de las mismas.

Para que la comparación pueda ser hecha, agrupamos los valores en 3 tamaños de N y 3 de P,
en cada caso, cada algoritmo puede tener una pequeña . La idea de las pruebas era lo
siguiente: como se tenían 4 máquinas y 7 procesadores, entonces probar con P menor a 4

                             Resumen agrupado de las pruebas.

                   N= 400 ~500              N= 900                N = 1200~1800
     P=4           Cannon                   Cannon                Cannon
                   2D                       2D                    2D
                   2DD                      2DD                   2DD(N=1800)
     P= 8 ~9       Cannon                   Cannon                Cannon
                   DNS (P=8)                DNS (P=8)             DNS (P=8)
                   2D (N= 441)              2D                    2D (N =1764)
                   2DD                      2DD                   2DD
     P=16~27       Cannon                   Cannon                Cannon
                   DNS (P=27)               DNS (P=27)            DNS (P=27)
                   2D                       2D                    2D
                   2DD                      2DD                   2DD




                                             16/27
4.2 Entorno
Para la ejecución se usaron 4 máquinas con sistema operativo Linux Fedora Core 9, kernel
2.6.25.x. Se instaló y configuró la librería OPEN-MPI 1.2.2 y se uso el compilador mpicc,
para las ejecuciones se usó mpirun. También se configuró la red y los servidores SSH de
cada host para que se pueda ejecutar.

Además se configuró la autentificación DSA, para eso en el host maestro donde se lanza la
ejecución se generó la clave pública con ssh-keygen y se le pasó a cada una de las demás
máquinas para que pueda interactuar vía ssh con esa autentificación. El usuario común usado
en cada host uno fue mpiuser.
    Máquina               Procesador            Memoria RAM            S.O
   cparra-portatil     Intel Core Duo1,6          1,5 GB             Linux Fedora Core 9.
                       Ghz. Cache L2 4MB                               Kernel 2.6.25.xx
   liz                 Intel Core Duo. 1,46       1,0 GB             Linux Fedora Core 9.
                       Ghz. Cache L2 2MB.                              Kernel 2.6.25.xx
   fmanciahome         Intel Core Duo. 3,00       1,0 GB             Linux Fedora Core 9.
                       Ghz. Cache L2 4MB                               Kernel 2.6.25.xx
   familia             Intel Pentium IV 1,8       512 MB             Linux Fedora Core 9.
                       Ghz (single core)                               Kernel 2.6.25.xx



5 Resultados Obtenidos
Se presentan en esta sección, los gráficos más importantes que resumen los principales
resultados obtenidos en las pruebas.


5.1 Métricas
Por cada prueba, se extrajeron los valores de las siguientes métricas:
       ✔ Tiempo de Ejecución en paralelo, obtenido como el tiempo de ejecución de un
           proceso paralelo en particular. Los procesos de nuestras implementaciones
           medían sus tiempos y estas medidas eran enviadas al proceso cero que se
           encargaba de guardarlas para su posterior análisis. De los tiempos de ejecución
           de los P procesos, se marca al mayor como el tiempo de ejecución paralelo de
           todo el algoritmo.
       ✔ Aceleración, que es el ratio entre el mejor tiempo secuencial y el tiempo de
           ejecución paralelo. Para este propósito, ejecutamos un algoritmo secuencial en
           una sola máquina para cada tamaño de N utilizado en las pruebas.
       ✔ Sobre Costo, definido como la diferencia entre el producto del tiempo paralelo
           por P y el tiempo secuencial.
       ✔ Eficiencia: definido como la relación entre la aceleración y la cantidad de
           procesos lanzados.

De estas métricas, presentamos los resultados obtenidos para las dos primeras y la eficiencia.




                                              17/27
5.2 Tiempos de ejecución:


                   P=4;N=600                                          P=4;N=900
 6.0000                                             18.0000
                                                    16.0000
 5.0000
                                                    14.0000
 4.0000                                             12.0000
                                                    10.0000
 3.0000
                                                     8.0000
 2.0000                                              6.0000

 1.0000                                              4.0000
                                                     2.0000
 0.0000                                              0.0000
             2D         CANNON      2DDIAGONAL                   2D          CANNON    2DDIAGONAL




                                            P=4;N=1200
                          45.0000

                          40.0000
                          35.0000
                          30.0000

                          25.0000

                          20.0000
                          15.0000
                          10.0000
                           5.0000

                           0.0000
                                      2D          CANNON       2DDIAGONAL




          Figure 8. Tiempos de ejecución de los algoritmos para la ejecución con 4 procesos

La Figure 8 muestra los tiempos de ejecución paralela de cada algoritmo cuando se ejecutan
en cuatro procesos y distintos tamaños de N. En general, se nota el bajo rendimiento del
algoritmo 2D cíclico debido a que el proceso cero distribuye y realiza mucho cómputo. Esto
no variará en ninguna de los resultados que se presentarán en esta sección.

Además, se puede notar que el aumento en los tamaños de la entrada no afectan el
rendimiento relativo de los algoritmos. Esta tendencia se mantuvo en casi todas las pruebas
salvo algunas excepciones.

Cannon se muestra más rápido que el algoritmo 2D diagonal, aunque el algoritmo 2D
diagonal presenta tiempos de ejecución mínimos en los procesos no diagonales, lo cual es un
dato muy interesante. Esto no se muestra en los gráficos, pero forma parte de los resultados
obtenidos.

El cuello de botella precisamente del 2D diagonal está en los procesos diagonales, que
realizan un trabajo de cómputo adicional de empaquetamiento de mensajes y recepción de
resultados. Dicho de otro modo, el 2D diagonal presenta una mayor eficiencia de
comunicación, pero tiene problemas en el desbalanceo del trabajo existente, poniendo mayor
carga de trabajo en los procesos diagonales.

Con 4 procesos no se realizaron pruebas de DNS, que requiere un número cúbico de
procesos.



                                                 18/27
P=9;N=600                                                                                       P=9;N=1200
    5.0000
                                                                                    4 0.00 00
    4.5000
                                                                                    3 5.00 00
    4.0000

    3.5000                                                                          3 0.00 00

    3.0000                                                                          2 5.00 00

    2.5000
                                                                                    2 0.00 00
    2.0000
                                                                                    1 5.00 00
    1.5000
                                                                                    1 0.00 00
    1.0000

    0.5000                                                                           5 .0 00 0

    0.0000                                                                           0 .0 00 0

               2D        DNS               CANNON             2DDIAGONAL                                  2D                 DNS     C AN N ON        2 D D IAGON AL




                                                                      P=9;N=900
                               16.0000


                               14.0000


                               12.0000


                               10.0000


                                8.0000


                                6.0000


                                4.0000


                                2.0000


                                0.0000

                                                    2D                     DNS                   CANNON         2DDIAGONAL




             Figure 9. Tiempos de ejecución de los algoritmos para la ejecución con 9 procesos


   Con nueve procesos, ya se incluye en el análisis al algoritmo DNS, que muestra tiempos
de ejecución muy similares al de Cannon. Sin embargo, las tendencias que se manifestaron
en los primeros resultados con 4 procesos, se mantienen y sigue siendo Cannon el algoritmo
con menor tiempo de ejecución, seguido del DNS y del 2D Diagonal. El 2D cíclico, como
siempre, se mantiene en la última posición por los problemas que ya explicábamos más
arriba.

                      P=16;N=600                                                                                  P=16;N=900
    5.0000                                                                              25.0000

    4.5000

    4.0000                                                                              20.0000

    3.5000

    3.0000                                                                              15.0000


    2.5000
                                                                                        10.0000
    2.0000

    1.5000
                                                                                          5.0000
    1.0000

    0.5000
                                                                                          0.0000
    0.0000
                                                                                                           2D            DNS       CANNON        2DDIAGONAL
                2D      DNS              CANNON          2DDIAGONAL




                                                                                 19/27
P=16;N=1200
                            45.0000
                            40.0000
                            35.0000
                            30.0000
                            25.0000
                            20.0000
                            15.0000
                            10.0000
                             5.0000
                             0.0000
                                       2D       DNS       CANNON    2DDIAG-
                                                                    ONAL




         Figure 10. Tiempos de ejecución de los algoritmos para la ejecución con 16 procesos

Para la ejecución de los algoritmos en 16 procesos, como se muestra en la Figure 10 se
presentan excepciones.

Para matrices pequeñas, la tendencia se mantiene, pero a medida que aumentamos el número
de matrices llega el caso en el que DNS llega a un tiempo de ejecución inferior al de Cannon.

En realidad, mirando los tres conjuntos de gráficos, podemos ver que DNS presenta mejoras
en su tiempo de ejecución a medida que aumenta el tamaño de las matrices, fenómeno que no
es tan notable en los demás algoritmos.

5.3 Aceleración y Eficiencia.
En esta sección, se presentan los resultados de la aceleración y la eficiencia de los algoritmos
implementados.

La aceleración y la eficiencia de los algoritmos siguen en el mismo patrón relativo que los
gráficos de tiempo de ejecución, lo cual era de esperarse.

Lo notable en estos trabajos es que en ciertos casos, el 2D Cíclico tiene peor rendimiento que
el algoritmo secuencial óptimo, lo que permite reafirmar la necesidad de separar a un proceso
dedicado para que se comporte como maestro.
                  P=4;N=400
                                                                        P=4;N=600
3.5000
                                                      3.5000
3.0000
                                                      3.0000
2.5000
2.0000                                                2.5000

1.5000                                                2.0000

1.0000                                                1.5000

0.5000                                                1.0000
0.0000
                                                      0.5000
             2D        CANNON         2DDIAG-
                                      ONAL            0.0000
                                                                   2D         CANNON   2DDIAGONAL




                                                20/27
P=4;N=1200
                      3.5000


                      3.0000


                      2.5000


                      2.0000


                      1.5000


                      1.0000


                      0.5000


                      0.0000

                                   2D              CANNON                 2DDIAGONAL




   Figure 11. Aceleración y Eficiencia (en menor escala) de los algoritmos para la ejecución con 4
                                             procesos


Además, otra cosa notable es que ninguno de los algoritmos tiene una eficiencia mayor al
70%, lo que habla de que las sobrecargas por comunicación y otros cómputos están
aproximadamente entre el 50% y el 70%.

                   P=9;N=600                                                    P=9;N=900

  1.6000                                             4.0000
  1.4000                                             3.5000
  1.2000                                             3.0000
  1.0000                                             2.5000
  0.8000                                             2.0000
  0.6000                                             1.5000
  0.4000                                             1.0000
  0.2000                                             0.5000
  0.0000                                             0.0000
            2D       DNS        CAN     2DDI-                        2D            DNS      CANNON   2DDIAG-
                                NON     AGONAL                                                       ONAL


                                           P=9; N=1200
                       4.5000
                       4.0000
                       3.5000
                       3.0000
                       2.5000
                       2.0000
                       1.5000
                       1.0000
                       0.5000
                       0.0000
                                  2D         DNS            CANNON        2DDIAGONAL



 Figure 12. Aceleración y Eficiencia (en menor escala) de los algoritmos para la ejecución con 8 y 9
                                             procesos




                                                 21/27
Al aumentar el número de procesos a 9, podemos incluir a DNS en el análisis y se confirma
lo que se puede notar con los tiempos de ejecución: DNS aumenta notablemente a medida
que se procesan tamaños mayores de la entrada. Para N=600, DNS tiene un rendimiento
inferior al algoritmo secuencial, mientras que al llegar a tamaños superiores al 1000, llega a
alcanzar una eficiencia cercana al 70%.

Otra cosa notable de estos resultados es el rendimiento superescalar de Cannon cuando la N
llega a 1200. Por una lado, el entorno de ejecución paralelo de las pruebas no era totalmente
homogéneo, y las pruebas secuenciales se ejecutaron en uno de los nodos que no
necesariamente podría obtener los mejores resultados. Por otra parte, algunos de los nodos
del entorno estaban equipados con procesadores de dos núcleos, lo cual pudo haber
incrementado el nivel de paralelismo. Cualquiera de estos motivos puede explicar la
superescalabilidad.

O tal vez esta superescalabilidad se debe a alguna de las razones tradicionales explicadas en
[1]: los algoritmos paralelos efectivamente realizan menos trabajo en proporción que el
algoritmo secuencial, o la división de los datos hace que para los bloques más pequeños de
datos, se aproveche mejor las capacidades de la cache de cada nodo.

                 P=16;N=600                                            P=16;N=900
                                                     5.0000
 1.4000
                                                     4.5000
 1.2000
                                                     4.0000

 1.0000                                              3.5000

                                                     3.0000
 0.8000
                                                     2.5000
 0.6000
                                                     2.0000

 0.4000                                              1.5000

                                                     1.0000
 0.2000
                                                     0.5000
 0.0000                                              0.0000
            2D       DNS        CANNON   2DDIAG-                  2D       DNS      CANNO N   2DDIAGO NAL
                                         ONAL



                                         P=16;N=1200
                       4.0000

                       3.5000

                       3.0000

                       2.5000

                       2.0000

                       1.5000

                       1.0000

                       0.5000

                       0.0000
                                   2D         DNS             CANNON   2DDIAGONAL



 Figure 13. Aceleración y Eficiencia (en menor escala) de los algoritmos para la ejecución con 16 y 27
                                              procesos




                                                   22/27
Por otro lado, debido a la presencia de nodos con procesadores doble núcleo, teóricamente la
aceleración debería dispararse entre los resultados con 4 procesos y aquellos obtenidos con 8
o 9. Sin embargo esto no sucede lo que nos lleva a la conclusión de que la implementación
MPI utilizada no aprovecha al máximo las posibilidades de multiprocesamiento en los nodos.

Los tres últimos gráficos de aceleración y eficiencia sencillamente confirman las tendencias
presentadas en los demás resultados. Para tamaños grandes de matrices, la aceleración de
DNS es superior a la de Cannon, probablemente por su menos sobrecarga de comunicación.

Por otro lado, aunque esto no se nota en los gráficos, de los resultados extraídos en las
pruebas, también pudimos notar al revisar los tiempos de ejecución de cada proceso
ejecutado por un algoritmo, que el DNS es el que presenta mayor estabilidad. Por su parte,
Cannon es el que presenta mayores variaciones entre los tiempos de ejecución de los
distintos procesos. 2D Diagonal por su parte, presenta la misma inestabilidad que Cannon y
bajos tiempos de ejecución en los procesos no diagonales, mientras que el tiempo de
ejecución se dispara en la diagonal de la topología.


6 Conclusiones
       ✔   Se alcanzaron los objetivos de profundizar los conceptos de programación
           paralela a través de la implementación de algoritmos paralelos.
       ✔   Se pudo comprobar que la paralización de la solución efectivamente disminuye
           el tiempo de solución del mismo.
       ✔   En el caso particular de la multiplicación de matrices, casi todos los algoritmos
           aceleraron la solución, con excepción del algoritmo 2D cíclico.
       ✔   A partir de tamaños de matrices superiores a 1000, ninguno de los algoritmos
           paralelos tiene aceleración inferior a 1, y a medida que aumenta el tamaño,
           algunos algoritmos mejoran su rendimiento.
       ✔   Cannon ofrece, entre todos los algoritmos paralelos implementados, las mejores
           prestaciones en cuánto a tiempo de ejecución se refiere.
       ✔   DNS sin embargo, aumenta su rendimiento a medida que aumenta el tamaño de
           las matrices de entrada.
       ✔   En cuánto a la variabilidad de los algoritmos, entendiendo variabilidad como
           variación entre los tiempos de ejecución de cada proceso, DNS ha probado ser el
           algoritmo más estable.
       ✔   Cannon, sin embargo, es el más inestable en este sentido.
       ✔   2D diagonal tiene una variabilidad similar a la de Cannon, con el agregado de
           que los procesos diagonales presentan tiempos de ejecución muy superiores que
           los que no son diagonales.


7 Trabajos Futuros

  • Mejorar el modelo maestro-esclavo del algoritmo 2D cíclico: el problema
     fundamental en la implementación del algoritmo 2D cíclico, es que el proceso maestro
     se convierte en un cuello de botella cuando se procesan matrices grandes. Una solución
     interesante que puede aumentar dramáticamente el rendimiento de este algoritmo es
     dedicar uno de los procesos a la tarea exclusiva de ser maestro y distribuidor de tareas.




                                             23/27
Esto podría permitir que efectivamente se optimice el solapamiento del cómputo con
   las comunicaciones, y se reduciría al mínimo el Idling time gracias a que tan pronto un
   proceso quede libre, seriá asignado a una nueva tareas.

   Otra mejora en este modelo consiste en reducir la restricción de asignación cíclica, y
   permitir que la asignación de tareas se realice directamente al procesador que quedó
   libre primero. Esto se puede implementar fácilmente reemplazando la asignación
   circular, por un mecanismo de cola de procesos a la que se irán agregando los procesos
   por orden de llegada a medida que quedan libres.

   Finalmente, una mejora más que se le podría realizar al algoritmo 2D consiste en
   implementar un mecanismo de pre-empaquetamiento de datos a enviar. Es decir, una
   vez que el proceso maestro termino de asignar una ráfaga de tareas, que comience
   inmediatamente a empaquetar los próximos mensajes para que cuando llegue el
   momento, estos estén listos y se minimice el tiempo de ociosidad del proceso maestro.

 • Aprovechamiento de las capacidades multi-hilos de los procesadores con múltiples
   núcleos: MPI no aprovecha las capacidades de los procesadores de manejar hilos. El
   resultado es que cada proceso es lanzado en cada procesador como un proceso pesado.
   Un trabajo interesante seriá realizar una implementación de estos algoritmos sobre una
   implementación de MPI que aproveche la capacidad de multihilado de los
   procesadores, como la que se propone en [8], y lance las tareas como hilos en cada
   nodo y no como procesos pesados. En los resultados obtenidos por este trabajo se notó
   que la utilización de procesadores doble-núcleo en la ejecución de los procesos por
   medio de MPI, no generaba mejoras muy notables en la aceleración.

 • Otro trabajo interesante, sería analizar el rendimiento de estos algoritmos para matrices
   no densas, en busca de posibles optimizaciones particulares a los mismos aplicables a
   distintos tipos de matrices especiales.


8 Referencias
  [1]    Ananth Grama, Anshul Gupta, George Karypis, Vipin Kumar: Introduction to Parallel
           Computing, Second Edition. Addison Wesley. 2003.
  [2]    MatrixMarket - Mathematical and Computational Sciences Division NIST (National
           Institute Standars and Technology) - http://math.nist.gov/MatrixMarket/
  [3]   http://en.wikipedia.org/wiki/Matrix_(mathematics)
  [4]   Generalized Cannon's algorithm for parallel matrix multiplication. Hyuk-Jae Lee, James P.
           Robertson, José A. B. Fortes.
  [5]   Communication Efficient Matrix Multiplication on Hypercubes. Himanshu Gupta, P.
           Sadayappan.
  [6]   Rendimiento de Algoritmos Paralelos de Multiplicación de Matrices implementados con
           Hilos. Cristhian Parra, Fernando Mancía. Facultad Politécnica de la Universidad de
           Asunción, 2008.
  [7]   www.open-mpi.org
  [8]   F. García, A. Calderón, J. Carretero, MiMPI: a multithread-safe implementation of MPI, in:
           Recent Advances in Parallel Virtual Machine and Message-Passing Interface, Proceedings
           of the Sixth European PVM/MPI Users' Group Meeting, Lecture Notes in Computer
           Science 1697, Springer, September 1999, pp. 207-214.




                                              24/27
9 Anexo: Tablas de Resultados.

                                 Re sultados obte nidos con 4 proc e sos
                         Tie mpo     Tie mpo Ac ele rac Sobre Efic ie nci                        Eficie n Efic ie nc
 Alg oritmo   Tamaño                                                                Costo
                         Parale lo Se c ue nc ial  ión     C osto        a                        c ia*     ia**
2D               40 0     2,08 4 6      1,0727    0,514 6     7,2657     0,128 6     8 ,338 4 0,128 6       0,0735
CANNON           40 0     0,4 4 8 4     1,0727    2,3924      0,7208     0,598 1     1,7934 0,598 1 0,34 18
2DDIAG ONAL      40 0      0,7767       1,0727    1,38 10     2,034 2    0,34 53      3,1069 0,34 53        0,1973
2D               576      5,29 80       1,4811    0 ,279 6   19 ,710 9 0 ,0 6 9 9           --         --         --
CANNON           600       1,7351      1,4 8 11   0,8 536     5,4 591    0,2134      6,94 03 0,2134         0,1219
2DDIAG ONAL      600       3,0172      1,4 8 11   0,4 909 10,58 76       0,1227     12,068 7 0,1227 0,0701
2D               900     15,7728      16,8 34 0   1,0673 4 6,2572        0,2668     63,0913 0,2668          0,1525
CANNON           900       5,6179     16,8 34 0   2,9965      5,6375     0,74 91    22,4 715 0,74 91 0,4 28 1
2DDIAG ONAL      900       8 ,5221    16,8 34 0   1,9753 17,254 2        0,4 938    34 ,08 8 2 0,4 938      0,28 22
2D              129 6     40 ,2125           --         --          --         --           --         --         --
CANNON          120 0     13,3522     4 0,568 7   3,038 3 12,8 4 02      0,7596 53,4 08 8 0,7596 0,4 34 0
2DDIAG ONAL     120 0    20,8 328     4 0,568 7   1,94 73 4 2,7626       0,4 8 68   8 3,3313 0,4 8 68 0,278 2
2D              16 0 0    69,5011     8 7,1772    1,254 3 190,8 274      0,3136 278 ,004 5 0,3136 0,1792
CANNON          150 0     30,7217           --          --          --         --           --         --        --
2DDIAG ONAL     150 0    4 1,9274      79,5236    1,8 967 8 8 ,18 61     0,4 74 2 167,7097 0,4 74 2         0,2710
2D              180 0            --          --         --          --         --           --         --         --
CANNON          180 0            --          --         --          --         --           --         --         --
2DDIAG ONAL     180 0     73,3709     137,5139    1,8 74 2 155,9695      0,4 68 6 293,4 8 34 0,4 68 6       0,2677
2D              250 0 223,4 08 8      377,6175    1,6903 516,0178        0,4 226 8 93,6353 0,4 226 0,24 15
CANNON          250 0           --          --          --          --         --           --         --        --
               Tabla 1. Resultados en la ejecución de los algoritmos con 4 procesos.




                                                    25/27
Re sultados obte nidos c on 9 proc e sos (8 para DNS)
                                  Tie mpo
              Tam      Tie mpo                 Ac e le ra Sobre     Efic ie n               Efic ie n Efic ie n
 Alg oritmo                      Se c ue nc ia                                C osto
              año      Parale lo                c ión     C osto      c ia                   c ia*     c ia**
                                       l
2D              441      2,3232      1,4 8 11 0,6375      19,4 273 0,0708       20,908 4 0,1594         0,0911
DNS            40 0      0,4 220      1,0727 2,54 16        2,3037 0,3177         3,3764 0,6354         0,3631
CANNO N        40 0           --          --        --           --        --          --         --         --
2DDIAG O NAL 40 0             --          --        --           --        --          --         --         --
2D             576        4,4131      1,4811        --           --        --          --          --        --
DNS            600        1,8514      1,4811 0 ,80 0 0     13,330 3 0 ,10 0 0    14,8114 0 ,20 0 0      0 ,1143
CANNO N        600       1,04 11     1,4 8 11 1,4 227      7,8 8 8 4 0,158 1      9,3695 0,3557 0,2032
2DDIAG O NAL 6 0 0       2,138 7     1,4 8 11 0,6925      17,7671 0,0769        19,24 8 2 0,1731 0,098 9
2D             900      13,6772     16,8 34 0 1,2308     106,2608 0,1368        123,094 9 0,3077 0,1758
DNS            900       5,7700     16,8 34 0 2,9175      29,3256 0,364 7        4 6,1596 0,7294 0,4 168
CANNO N        900       5,0051     16,8 34 0 3,3634      28 ,2121 0,3737       4 5,04 61 0,8 4 08 0,4 8 05
2DDIAG O NAL 9 0 0       7,5669     16,8 34 0 2,224 7     51,268 2 0,24 72       68 ,1023 0,5562 0,3178
2D            129 6     35,2415           --        --           --        --          --          --        --
DNS           120 0     14,176 2    40 ,56 87 2,86 17     72,840 7 0 ,3577      113,40 9 4 0 ,7154 0 ,40 88
CANNO N       120 0     10,0516     4 0,568 7 4 ,0361     4 9,8 953 0,4 4 8 5   90,4 64 0 1,0090 0,5766
2DDIAG O NAL 120 0      17,3277     4 0,568 7 2,34 13    115,38 07 0,2601 155,94 94 0,58 53 0,334 5
2D            176 4     79,54 51    129,7509 1,6312      58 6,154 9 0,18 12 715,9058 0,4 078            0,2330
DNS           16 0 0          --          --        --           --        --          --         --         --
CANNO N       150 0     22,6051      79,5236 3,5179      123,9226 0,3909 203,4 4 63 0,8 795 0,5026
2DDIAG O NAL 150 0      34 ,8 575    79,5236 2,28 14     234 ,1936 0,2535       313,7172 0,5703 0,3259
2D            176 4     79 ,5451 129 ,750 9    1,6 312   586 ,1549    0 ,1812 715,9 0 58 0 ,40 78 0 ,2330
DNS           180 0            --         --        --           --        --          --          --        --
CANNO N       180 0            --         --        --           --        --          --          --        --
2DDIAG O NAL 180 0      62,4 08 9   137,5139 2,2034      4 24 ,1659 0,24 4 8    561,6798     0,5509 0,314 8
2D            250 0           --          --        --           --        --          --         --         --
DNS           250 0           --          --        --           --        --          --         --         --
CANNO N       250 0           --          --        --           --        --          --         --         --
2DDIAG O NAL 270 0     231,6767 4 93,714 2 2,1310 1591,3765 0,2368 208 5,0907 0,5328 0,304 4
                Tabla 2. Resultados en la ejecución de los algoritmos con 9 procesos.




                                                     26/27
Re sultados obte nidos c on 16 proc e sos (27 proc e sos para DNS)
                                Tie mpo
               Tam Tie mpo                   Ac e le ra Sobre    Efic ie n          Efic ie n Efic ie n
 Alg oritmo                    Se c ue nc ia                                 C osto
               año Parale lo                  c ión     C osto      c ia             c ia*     c ia**
                                     l
2D              40 0     1,8 58 8     1,0727 0,5771       28 ,668 1 0,0361     29,74 07 0,14 4 3 0,08 24
DNS             40 0           --         --        --           --       --          --       --       --
CANNO N         40 0     0,398 7      1,0727 2,6905         5,3062 0,168 2       6,378 9 0,6726 0,38 4 4
2DDIAG O NAL 40 0        0,718 8      1,0727 1,4 924      10,4 277 0,0933      11,5004     0,3731 0,2132
2D              576      4,6 245      1,4811        --           --       --          --       --        --
DNS             600       1,49 31     1,4811 0 ,9 9 20     38,8323 0 ,0 36 7    40 ,3134 0 ,2480    0 ,1417
CANNO N         600      1,238 7     1,4 8 11 1,1958      18 ,3373 0,074 7     19,8 18 4 0,298 9 0,1708
2DDIAG O NAL 6 0 0       2,3018      1,4 8 11 0,64 35     35,34 8 3 0,04 02    36,8 294    0,1609 0,0919
2D             10 24    71,1670     78 ,6965 1,1058 1059,9755 0,0691 1138 ,6720 0,2765 0,158 0
DNS             900      8 ,64 99   16,8 34 0 1,94 61    216,714 0 0,0721 233,54 8 1 0,4 8 65 0,278 0
CANNO N         900      3,7332     16,8 34 0 4 ,5093     4 2,8 971 0,28 18     59,7312 1,1273 0,64 4 2
2DDIAG O NAL 80 0        5,5556     10,9094     1,9637    77,98 03 0,1227      8 8 ,8 8 96 0,4 909 0,28 05
2D             129 6    39 ,6 770          --       --           --       --          --       --        --
DNS            120 0    11,4744     40 ,56 87   3,5356   26 9 ,239 9 0 ,130 9 30 9 ,80 85 0 ,8839 0 ,50 51
CANNO N        120 0    12,7215     4 0,568 7 3,18 90    162,9753 0,1993 203,54 4 0 0,7972 0,4 556
2DDIAG O NAL 120 0      21,0735     4 0,568 7 1,9251     296,6076 0,1203       337,1763 0,4 8 13 0,2750
2D             16 0 0   69,0511     8 7,1772 1,2625 1017,6399 0,078 9               ### 0,3156 0,18 04
DNS            150 0    25,1913      79,5236 3,1568      600,64 25 0,1169 68 0,1661 0,78 92 0,4 510
CANNO N        150 0    24 ,5998     79,5236 3,2327      314 ,0730 0,2020      393,5967 0,8 08 2 0,4 618
2DDIAG O NAL 150 0      39,2616      79,5236 2,0255      54 8 ,6622 0,1266 628 ,18 58 0,5064 0,28 94
2D             180 0           --          --       --           --       --          --       --        --
DNS            180 0    43,30 0 1   137,5139    3,1758   10 31,5883 0 ,1176 116 9 ,10 22 0 ,79 40   0 ,4537
CANNO N        180 0           --          --       --           --       --          --       --        --
2DDIAG O NAL 180 0      73,7756     137,5139 1,8 639 104 2,8 94 9 0,1165            ### 0,4 660 0,2663
2D             270 0           --         --        --           --       --          --       --       --
DNS            270 0           --         --        --           --       --          --       --       --
CANNO N        270 0           --         --        --           --       --          --       --       --
2DDIAG O NAL 270 0 236,38 50 4 93,714 2 2,08 8 6 328 8 ,4 4 57 0,1305 378 2,1599 0,5222 0,298 4
              Tabla 3. Resultados en la ejecución de los algoritmos con 16 y 27 procesos.




                                                     27/27

Mais conteúdo relacionado

Mais procurados

Teoría de complejidad computacional (tcc)
Teoría de complejidad computacional (tcc)Teoría de complejidad computacional (tcc)
Teoría de complejidad computacional (tcc)Raquel Nuñez
 
Sistemas ecuacion simulink
Sistemas ecuacion simulinkSistemas ecuacion simulink
Sistemas ecuacion simulinkAlex Santos
 
Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)
Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)
Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)Rubi Veronica Chimal Cuxin
 
Practica 5 simulink-5156
Practica 5 simulink-5156Practica 5 simulink-5156
Practica 5 simulink-5156RossiHeredia1
 
Actividad no13 y_14_de_2do_parcial
Actividad no13 y_14_de_2do_parcialActividad no13 y_14_de_2do_parcial
Actividad no13 y_14_de_2do_parcialCarlos Mendoza
 
2 detalles de simulink y control
2 detalles de simulink y control2 detalles de simulink y control
2 detalles de simulink y controlMartin Carlos
 
Paralelismo
ParalelismoParalelismo
Paralelismoahawhn
 
Utp i_ay_se_sistemas difusos i 2013-3
 Utp i_ay_se_sistemas difusos i 2013-3 Utp i_ay_se_sistemas difusos i 2013-3
Utp i_ay_se_sistemas difusos i 2013-3jcbenitezp
 
Redes de neuronas recurrentes
Redes de neuronas recurrentesRedes de neuronas recurrentes
Redes de neuronas recurrentesSpacetoshare
 

Mais procurados (10)

Teoría de complejidad computacional (tcc)
Teoría de complejidad computacional (tcc)Teoría de complejidad computacional (tcc)
Teoría de complejidad computacional (tcc)
 
Sistemas ecuacion simulink
Sistemas ecuacion simulinkSistemas ecuacion simulink
Sistemas ecuacion simulink
 
Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)
Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)
Informe técnico Unidad 7 Análisis de algoritmos (Rubí Veronica)
 
2. Recursividad
2. Recursividad2. Recursividad
2. Recursividad
 
Practica 5 simulink-5156
Practica 5 simulink-5156Practica 5 simulink-5156
Practica 5 simulink-5156
 
Actividad no13 y_14_de_2do_parcial
Actividad no13 y_14_de_2do_parcialActividad no13 y_14_de_2do_parcial
Actividad no13 y_14_de_2do_parcial
 
2 detalles de simulink y control
2 detalles de simulink y control2 detalles de simulink y control
2 detalles de simulink y control
 
Paralelismo
ParalelismoParalelismo
Paralelismo
 
Utp i_ay_se_sistemas difusos i 2013-3
 Utp i_ay_se_sistemas difusos i 2013-3 Utp i_ay_se_sistemas difusos i 2013-3
Utp i_ay_se_sistemas difusos i 2013-3
 
Redes de neuronas recurrentes
Redes de neuronas recurrentesRedes de neuronas recurrentes
Redes de neuronas recurrentes
 

Semelhante a Rendimiento Algoritmos Paralelos Multiplicación Matrices MPI

Aplicación de análisis numérico en alabes
Aplicación de análisis numérico en alabesAplicación de análisis numérico en alabes
Aplicación de análisis numérico en alabesMateoLeonidez
 
1.introduccion analisis
1.introduccion analisis1.introduccion analisis
1.introduccion analisisrjvillon
 
Reconocimiento de Dígitos Manuscritos usando la Dase de Datos MNIST
Reconocimiento de Dígitos Manuscritos usando la Dase de Datos MNISTReconocimiento de Dígitos Manuscritos usando la Dase de Datos MNIST
Reconocimiento de Dígitos Manuscritos usando la Dase de Datos MNISTEmilio Garcia
 
Metodos de programcion no lineal
Metodos de programcion no linealMetodos de programcion no lineal
Metodos de programcion no linealAngel Jhoan
 
Manual algoritmos y_estructura_de_datos
Manual algoritmos y_estructura_de_datosManual algoritmos y_estructura_de_datos
Manual algoritmos y_estructura_de_datosJuan Timoteo Cori
 
Análisis de algoritmo
Análisis de algoritmoAnálisis de algoritmo
Análisis de algoritmoGaston Demundo
 
301401 10 practica1-informe fibra
301401 10 practica1-informe fibra301401 10 practica1-informe fibra
301401 10 practica1-informe fibraFabioAcevedo
 
Actividad 14: Diseño de Algoritmos Paralelos
Actividad 14: Diseño de Algoritmos ParalelosActividad 14: Diseño de Algoritmos Paralelos
Actividad 14: Diseño de Algoritmos ParalelosCarlosHung9
 
Implementación de un módulo para el entrenamiento y evaluación de redes neuro...
Implementación de un módulo para el entrenamiento y evaluación de redes neuro...Implementación de un módulo para el entrenamiento y evaluación de redes neuro...
Implementación de un módulo para el entrenamiento y evaluación de redes neuro...Adrián Palacios Corella
 
Investigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptxInvestigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptxcarlosPEREZMENDEZ2
 
Investigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptxInvestigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptxcarlosPEREZMENDEZ2
 
Diseño de Algoritmos Paralelos Roderick Beriguete .pptx
Diseño de Algoritmos Paralelos Roderick Beriguete .pptxDiseño de Algoritmos Paralelos Roderick Beriguete .pptx
Diseño de Algoritmos Paralelos Roderick Beriguete .pptxRoderickx12
 

Semelhante a Rendimiento Algoritmos Paralelos Multiplicación Matrices MPI (20)

Aplicación de análisis numérico en alabes
Aplicación de análisis numérico en alabesAplicación de análisis numérico en alabes
Aplicación de análisis numérico en alabes
 
Optimizacion en IMRT
Optimizacion en IMRTOptimizacion en IMRT
Optimizacion en IMRT
 
1.introduccion analisis
1.introduccion analisis1.introduccion analisis
1.introduccion analisis
 
Reconocimiento de Dígitos Manuscritos usando la Dase de Datos MNIST
Reconocimiento de Dígitos Manuscritos usando la Dase de Datos MNISTReconocimiento de Dígitos Manuscritos usando la Dase de Datos MNIST
Reconocimiento de Dígitos Manuscritos usando la Dase de Datos MNIST
 
MATLAB Tutorial
MATLAB TutorialMATLAB Tutorial
MATLAB Tutorial
 
Metodos de programcion no lineal
Metodos de programcion no linealMetodos de programcion no lineal
Metodos de programcion no lineal
 
Manual algoritmos y_estructura_de_datos
Manual algoritmos y_estructura_de_datosManual algoritmos y_estructura_de_datos
Manual algoritmos y_estructura_de_datos
 
2 Taller modelacion matemática 2018-1 UNAL
2 Taller modelacion matemática 2018-1 UNAL2 Taller modelacion matemática 2018-1 UNAL
2 Taller modelacion matemática 2018-1 UNAL
 
Análisis de algoritmo
Análisis de algoritmoAnálisis de algoritmo
Análisis de algoritmo
 
Manual estructura de_datos_2010___h._caselli_g
Manual estructura de_datos_2010___h._caselli_gManual estructura de_datos_2010___h._caselli_g
Manual estructura de_datos_2010___h._caselli_g
 
Paradigmas
ParadigmasParadigmas
Paradigmas
 
Generación
GeneraciónGeneración
Generación
 
301401 10 practica1-informe fibra
301401 10 practica1-informe fibra301401 10 practica1-informe fibra
301401 10 practica1-informe fibra
 
Actividad 14: Diseño de Algoritmos Paralelos
Actividad 14: Diseño de Algoritmos ParalelosActividad 14: Diseño de Algoritmos Paralelos
Actividad 14: Diseño de Algoritmos Paralelos
 
01.introduccion metricauml
01.introduccion metricauml01.introduccion metricauml
01.introduccion metricauml
 
Implementación de un módulo para el entrenamiento y evaluación de redes neuro...
Implementación de un módulo para el entrenamiento y evaluación de redes neuro...Implementación de un módulo para el entrenamiento y evaluación de redes neuro...
Implementación de un módulo para el entrenamiento y evaluación de redes neuro...
 
Investigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptxInvestigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptx
 
Investigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptxInvestigación_Operaciones_Clase_01.pptx
Investigación_Operaciones_Clase_01.pptx
 
Act 14_Analis de algoritmos.pdf
Act 14_Analis de algoritmos.pdfAct 14_Analis de algoritmos.pdf
Act 14_Analis de algoritmos.pdf
 
Diseño de Algoritmos Paralelos Roderick Beriguete .pptx
Diseño de Algoritmos Paralelos Roderick Beriguete .pptxDiseño de Algoritmos Paralelos Roderick Beriguete .pptx
Diseño de Algoritmos Paralelos Roderick Beriguete .pptx
 

Rendimiento Algoritmos Paralelos Multiplicación Matrices MPI

  • 1. Rendimiento de Algoritmos Paralelos de Multiplicación de Matrices implementados con MPI Cristhian Parra1, Fernando Mancía1 1 Facultad Politécnica de la Universidad Nacional de Asunción Estudiantes del 9no Semestre de Ingeniería Informática {cparra,fmancia}@cnc.una.py Resumen: El problema de la multiplicación de matrices, ha sido ampliamente estudiado en el ámbito académico, y sus soluciones han encontrado aplicaciones en diversos campos del mundo científico. La facilidad para dividir este problema en diferentes partes independientes, ha causado el surgimiento de numerosos algoritmos paralelos que lo resuelven eficientemente. En este trabajo, se presentan los detalles de implementación de 4 algoritmos bien conocidos, aplicados a matrices cuadradas densas. También se presentan los resultados de algunas pruebas llevadas a cabo para analizar el rendimiento de cada algoritmo. Palabras Clave: matrices, algoritmos de multiplicación de matrices, particionamiento de datos, algoritmos paralelos, MPI, Cannon, DNS, particionamiento por bloque cíclico, 2D diagonal.
  • 2. 1 Introducción Los algoritmos de matrices densas, y entre ellos los de multiplicación de matrices, han encontrado numerosas aplicaciones en la resolución de problemas tanto numéricos, como aquellos que no son numéricos. En ciencias de la computación, la multiplicación de matrices ha encontrado usos importantes en campos como la Criptografía o la Computación y Diseño Gráfico [3]. Todas estas aplicaciones han motivado el estudio y optimización de algoritmos que resuelvan este problema. Además, las matrices y sus operaciones son una parte muy importante del Álgebra Lineal, cuyas aplicaciones en el mundo científico y de la computación son innumerables. La facilidad con que se puede particionar el problema de multiplicar dos matrices cuadradas y densas, lo convierten en un candidato ideal para estudiar los conceptos de computación paralela, y permiten que sea fácil formular algoritmos que aprovechen los recursos de un entorno paralelo. En este trabajo, se describen 4 algoritmos paralelos para multiplicar matrices cuadradas y densas, incluyendo la explicación de los detalles de implementación. Se presentan los resultados de diversas pruebas realizadas, y las conclusiones extraídas a partir del análisis de estas pruebas. El objetivo del trabajo es llevar a la práctica conceptos de computación paralela, analizar algoritmos paralelos para multiplicación de matrices, realizar las implementaciones y ejecutar pruebas que nos permitan extender el análisis preliminar. 2 Descripción general. En primer lugar, es importante definir el problema que queremos resolver y sus parámetros correspondientes. Dada dos matrices densas de tamaño NxN, se necesita obtener el resultado de la multiplicación de estas dos matrices, que es otra matriz NxN igualmente densa, en un tiempo razonable. Una Matriz es Densa cuando existe un bajo porcentaje de ceros en la misma. El parámetro fundamental del problema es el tamaño de la matriz, cuantificada por N. En un entorno de ejecución paralelo, existen dos parámetros más que se tienen en cuenta para nuestros análisis: la cantidad de procesos y la cantidad de procesadores físicos. Para resolver el problema, se implementan los siguientes 4 algoritmos: ✔ Algoritmo 2D con particionamiento por bloques y distribución cíclica, basada en el particionamiento propuesto en el capítulo 3 de [1], que se llamará en adelante 2D cíclico. ✔ Algoritmo DNS, explicado en [1] y extendido en [4] y [5]. ✔ Algoritmo de Cannon, explicado en [1] y generalizado en [4]. ✔ Algoritmo 2D-Diagonal, presentado en [5]. El trabajo está organizado de la siguiente manera: 1. Las secciones 1 y 2 proporcionan una visión global del trabajo realizado. 2/27
  • 3. 2. La sección 3 proporciona una explicación detallada de cada algoritmo y su implementación. 3. En la sección 4 se describen las pruebas realizadas. 4. La sección 5 alberga la descripción de las métricas obtenidas, los resultados en forma de gráficos, acompañados de algunos comentarios que forman parte del análisis de dichos resultados. 5. La sección 6 proporciona algunas reflexiones de conclusión a las que llegamos al finalizar el trabajo. 6. La sección 7 propone algunas problemáticas y trabajos futuros. 7. La sección 8 presenta nuestras fuentes de información. 8. La sección 9, presenta en forma de anexo, las tablas resumidas de resultados. 2.1 Preliminares 2.1.1 Detalles de implementación comunes a todos los algoritmos: La implementación fue hecha usando el lenguaje de programación C (Ansi C) y la implementación del estándar MPI conocido como OpenMPI. Todo el desarrollo y las pruebas realizadas, fueron llevadas a cabo en el Sistema Operativo Linux Fedora 9, con distintas versiones menores del kernel 2.6.25. Las matrices se generan en tiempo de ejecución, ya que esto era más práctico para realizar las pruebas de rendimiento, aunque está disponible la posibilidad de leer las matrices de archivos en formatos de MatrixMarket, como se hacen [6]. Las matrices son representadas en forma lineal, por lo que para saber el elemento Mat[i,j] se debe acceder de la siguiente manera: Mat[(i*cant_columas) + j] La implementación MPI utilizada, OpenMPI, está disponible para su descarga gratuita en [7] y es Open Source. Para las pruebas realizadas, establecimos cantidades de procesos fijos: 4, 9 y 16 procesos. Solo en el caso de DNS utilizamos cantidades de proceso de 8 y 27, ya que en este algoritmo se requería una cantidad cúbica. Ejecutamos los algoritmos en un entorno de cuatro computadoras conectadas mediante una red ethernet de 10/100 Mbps. De las cuatro máquinas que utilizamos para pruebas, tres contaban con procesadores doble núcleo. Detalles más precisos sobre el ambiente de prueba se presentan en la sección 4. 2.1.2 Disponibilidad del código fuente: Todo el proyecto está disponible a través de Subversion en el repositorio de Google Code, http://mmulfpuna.googlecode.com/svn/trunk/srcmpi. Personas que no son miembros del proyecto pueden acceder al mismo y descargar los fuentes de la siguiente manera: svn checkout http://mmulfpuna.googlecode.com/svn/trunk/srcmpi mmulfpuna- read-only 3/27
  • 4. 3 Algoritmos Implementados 3.1 Algoritmo 2D Cíclico En realidad, no existe un algoritmo 2D con particionamiento por Bloque Cíclico. Solo existe el concepto sobre el particionamiento por bloque y la distribución cíclica de los bloques, que se presenta y explica en [1]. 3.1.1 Particionamiento por Bloques cíclico: Cuando se debe particionar un determinado problema, para distribuirlo entre distintos procesos, dos objetivos igualmente importante, suelen entrar en conflicto: ✔ Balancear correctamente la carga. ✔ Minimizar el tiempo de ociosidad (Idling) de los procesos. En términos de la multiplicación de matrices, el primer objetivo implica distribuir las tareas de multiplicación en los procesos, de manera que todos los procesos computen matrices igualmente densas. El segundo objetivo implica solapamiento de comunicaciones con cómputo. Además de estos objetivos, existe la realidad de que normalmente existen menos procesadores físicos disponibles, que la cantidad de procesos en los que queremos dividir nuestro problema. Para dar solución a este último problema, y al mismo tiempo encontrar una optimización equilibrada de los dos objetivos presentados, el particionamiento por Bloques cíclicos establece lo siguiente: ✔ Dividir el problema en más tareas que procesos. ✔ Asignar las tareas a los procesos de manera cíclica, de manera tal a que se solapen adecuadamente las comunicaciones con las tareas de cómputo. ✔ Agrupar los procesos en bloque, de manera tal a que cada proceso, se encargue de zonas distintas de la matriz y no asuma el cómputo de largos bloques consecutivos que pueden tener un patrón de carga mayor que otras partes de la matriz. Figura 1. Particionamiento por Bloque con distribución o mapeamiento Cíclico. La imagen (a) muestra la versión 1D y la imagen (b) la versión 2D. La Figura 1 muestra un ejemplo de este tipo de particionamiento y mapeamiento1. 1 Las figuras fueron extraídas directamente de [1] para extender y clarificar las explicaciones. 4/27
  • 5. Nótese que si la matriz es densa, el agrupamiento de bloques de las matrices hace que al final, a cada proceso le haya tocado una bloque de tarea de cada zona distinta de la matriz, haciendo que el balance general de la carga sea equilibrado. 3.1.2 Algoritmo implementado: El algoritmo implementado, utiliza el particionamiento descrito en la sección anterior, y lo aplica a la matriz de salida. De esta manera, cada proceso calcula un bloque de la salida. Se sigue exactamente la idea del particionamiento, y se utiliza un esquema maestro-esclavo para paralelizar el trabajo. Lo primero que realiza el algoritmo es dividir la matriz de salida, de tamaño N, en N tareas diferentes, lo que implica hacer una división en  N ×  N bloques. La elección de la cantidad de tareas, corresponde a que es el número óptimo que permite tener tamaños de bloque balanceados. Luego, se recorren los índices de la matriz resultado en bloques  P × P tareas, y se asignan estas a los procesos P i de manera cíclica, según se muestra en la siguiente ecuación. ∀ i=0 k ⇒ P i=k mod P Elegido el proceso al cual asignar una tarea, se empaquetan los datos que requerirá este (filas y columnas de las matrices de entrada), y se le envía este paquete en un solo Mensaje a través de MPI_Send. En cuánto al esquema maestro-esclavo, existen dos posibilidades: ✔ La existencia de un proceso dedicado exclusivamente a la asignación y distribución de tareas. ✔ El proceso 0 es el maestro, y además procesa localmente algunos bloques. La segunda opción es atractiva por su simpleza, y sería recomendable en redes de mucha latencia, sin embargo, cuando estamos en redes de alto rendimiento, puede ocurrir que el proceso maestro se convierta en un cuello de botella. La implementación probada en este trabajo corresponde a la segunda opción, por su simplicidad. La estructura principal del algoritmo es la siguiente: int SP = sqrt(P); int ST = sqrt(N); int k = 0; for (i=0; i < N; i += SP) { for (j=0; j < N; j += SP) { for (x=i; x < (i+SP); x += ST) { for (y=j; y < (j+SP); y += ST) { ... int Pdest = P%k; ... if (Pdestino != 0) { Bloque <-- Empaquetar Bloque (x,y) /* Implica empaquetar desde x, ST 5/27
  • 6. * filas de A, y desde y, ST * columnas de B */ MPI_Send( Bloque, ST * ST *N, MPI_FLOAT, Pdest, Tag, MPI_COMM_WORLD); } else { Bloque Local <-- Empaquetar Bloque (x,y) Local } ... k++; } } ... Multiplicar Bloque Local. Cargar resultado en C. ... for(proc = 0; proc < P, proc++) { if (proc != 0) { MPI_Status status; MPI_Recv( BloqueRec, ST * ST * N, MPI_FLOAT, 0, Tag, MPI_COMM_WORLD, &status); Cargar BloqueRec a matriz C } } } } ... El código ejecutado por los esclavos es sencillamente el siguiente: while (done == 0) { ... MPI_Recv( Bloques, ST * ST * N, MPI_FLOAT,0, Tag, MPI_COMM_WORLD, &status); ... Multiplicar los bloques recibidos. ... MPI_Send( Salida, ST * ST, MPI_FLOAT, 0, Tag, MPI_COMM_WORLD); } ... El algoritmo presentará una sobrecarga y un cuello de botella importante en redes de alto rendimiento, en las cuales el tiempo de envío de mensajes será mucho menor que el tiempo que dura la computación, y muy pronto los procesadores esclavos se quedarán ociosos. 3.1.3 Costo Asintótico. Para analizar el costo asintótico, debemos basarnos en la longitud del ciclo principal del algoritmo. Los principales costos de comunicación se encuentran en el Send más interno. Por cada tarea, se realiza un envío desde el maestro a un esclavo, a lo que este responde con otro Send de la respuesta. 6/27
  • 7. Además, aunque no figura en nuestro algoritmo simplificado mostrado en la página anterior, luego de cada envío, a los procesos se les envía una pequeño mensaje de 1 palabra para confirmar la continuidad del ciclo. Podríamos considerar, para simplificar el análisis, que se envía un solo mensaje, pero con una palabra más de longitud. En síntesis, teniendo en cuenta que se realizan N tareas, se realizarían N Sends, menos la cantidad de veces en la que el proceso asignado es el 0. Para simplificar el análisis, diremos que en realidad el Proceso 0, se envía su tarea a sí mismo, de manera a tener tantos envíos como tareas. En cada uno de estos envíos, se envían palabras de tipo float, igual a la cantidad de elementos de los bloques de matriz enviados. Por cada tarea, se envía un bloque de  N × N (filas de A) más N × N (columnas de B). A esto hay que sumarle la cantidad de envíos realizados desde los procesos para enviar sus resultados. En estos envíos la cantidad de palabras es igual a  N ×  N =N , ya que corresponde al bloque resultado de la multiplicación de los bloques citados más arriba. A cada proceso, se le asignan N/P tareas, por lo cual, esta es la cantidad de envíos de respuesta. Además, por cada envío realizado desde el proceso maestro, se realiza 1 envío más para confirmar la continuación o no del algoritmo. En síntesis, se realiza la siguiente cantidad de envíos. De esta manera, tenemos la siguiente función sobre el tiempo de comunicaciones. 1 t s× N ×2 t w ×N 2× N × N N 1 P En cuánto al cómputo, cada proceso realiza un cómputo similar de orden N 3 , sin P embargo, hay una importante sobrecarga para el proceso maestro que además de realizar el cómputo de computación, realiza un cómputo lineal por cada envío (cargar el buffer de envío) y otro cómputo extra de cargar las matrices en la estructura final a medida que llegan las respuestas. Aún así, esta sobrecarga no afecta el orden asintótico del cómputo realizado en cada proceso. 3.2 Algoritmo 2D Diagonal El algoritmo 2D diagonal es un algoritmo que sirve como base a otro, de tipo 3D, que optimiza las comunicaciones realizadas. Se organizan los P procesos en una malla 2D de  P× P procesos. La matriz A es particionada en  P grupos de columnas y lo propio se hace con la matriz B, pero en grupos de filas. En el primer paso del algoritmo, se realizan  P envíos para armar la distribución inicial del algoritmo. Luego de esta distribución los procesadores pjj en la diagonal principal tienen cada uno el jth grupo de filas de B y el jth grupo de columnas de A. A partir de aquí, se crean dos sub-topologías: una que conecta a los procesos con sus pares de la misma fila, y otra que conecta a los procesos con sus pares de la misma columna. Entonces se inicia la lógica principal del algoritmo, que consiste en hacer 3 pasos muy sencillos: 7/27
  • 8. 1. Broadcasting (MPI_Bcast) desde Pjj a los procesos de la misma fila Pj* para enviar a todos el jth grupo de columnas de A, como se muestra en la Figura 22. 2. One to all personalized Broadcast (MPI_Scatter) de los subbloques de tamaño N N del jth grupo de filas de B, desde Pjj . De esta manera, cada proceso  ×  P P Pj* se encarga de computar el producto externo de las columnas de A y las filas de B inicialmente almacenadas en pjj. 3. All to One Reduce (MPI_Reduce) desde cada proceso al proceso diagonal correspondiente a su columna, a través de la operación de suma. El término personalizado del paso 2, se refiere a que solo la porción del grupo de filas de B (Bik) que es necesario para computar una columna i del producto externo de la jth columna de A por la jth fila de B, se le pasa al procesador Pkj La ultima etapa reduce el resultado por adición a lo largo de la dirección y. La matriz final C se obtiene a lo largo de los procesadores diagonales. Cada procesador, envía su producto externo a la diagonal principal que se encarga de procesar C*,i Figura 2. Esquema general del algoritmo 2D Diagonal. De esta manera, a lo largo de la diagonal principal se encuentra el resultado final de la multiplicación. A continuación se muestra el bloque de código principal del algoritmo. Es notable la simplicidad del mismo. ... remains[0] = 0; remains[1] = 1; 2 Las figuras fueron extraídas directamente de [5] para extender y clarificar las explicaciones. 8/27
  • 9. MPI_Cart_sub(Comm2d,remains,&commF); remains[0] = 1; remains[1] = 0; MPI_Cart_sub(Comm2d,remains,&commC); ... int rrank = mycoords[0]; MPI_Bcast(IthGrupoA,GrupSize*N,MPI_FLOAT,rrank,commF); if (mycoords[0] == mycoords[1] && mycoords[0] ) { cargar_blocks(BloquesB,IthGrupoB,N,GrupSize,GrupSize); } MPI_Scatter( BloquesB, GrupSize*GrupSize, MPI_FLOAT, BloqueB,GrupSize*GrupSize, MPI_FLOAT, mycoords[0], commF); calcular_producto_externo(); MPI_Reduce( IProduct,IProductReduced,GrupSize*N, MPI_FLOAT,MPI_SUM,mycoords[1],commC); ... 3.2.1 Costo Asintótico. El gasto de comunicación realizado en este algoritmo, se resume en la suma de los gastos en las tres operaciones fundamentales que realiza el algoritmo: 1.  P operaciones de Broadcasting, una en cada proceso diagonal, enviando N palabras correspondientes a las filas de A.  × N P 2. Una operación de Scatter en la que se distribuyen N N palabras a a cada  ×  P P proceso de una fila de la malla. 3. Una operación de Reduce a los largo de las columnas que reduce bloques de N palabras.  × N P Teniendo en cuenta estos parámetros, y en base a los costos de las primitivas de comunicación presentadas y analizadas con profundidad en el capítulo 4 de [1], nuestro tiempo de ejecución estaría definido por los siguientes componentes: Broadcasting entre P procesos: N t st w × ×N ×log  P  P Scatter entre P procesos: N N t s×log  P t w × × ×  P−1 P P Reduce entre P procesos (mismo costo que el Broadcast): 9/27
  • 10. N t st w × ×N ×log   P  P La suma final de estos tres componentes es la siguientes: N2 3×t s×log   P t w × × 2×log   P P−1 P 3.3 Algoritmo de Cannon El algoritmo es una versión de uso eficiente de memoria, comparada con el algoritmo simple. Utiliza una malla de procesadores virtuales y la partición de los datos son de entrada inicialmente para las matrices A y B, aunque a nivel de mapeamiento de tareas, tenemos un mapeamiento de salidas, ya que cada proceso computa un bloque de la matriz de salida. Para comenzar se crea la topología cartesiana de 2 dimensiones, y en cada dimensión se tienen  P procesos. Entonces quedan identificados los procesos desde P 0,0 hasta P  P −1 ,  P −1 . N Las matrices A y B se particionan en bloques de tamaño Tam= quedando en cada P procesador en cada momento un bloque de tamaño Tam de A y otro de B. Luego el Proceso P0,0 es el encargado de pasar al resto de los procesos el bloque que le corresponde. El algoritmo propone una alineación inicial de los bloques de A y B en cada proceso. En la implementación presentada el proceso P0,0 es el encargado de enviar al Proceso P(i,j) el bloque de A y B ya alineado quedando en el proceso P(i, j) el bloque A(i, j+i) y el bloque B(i+j , j). En el caso de que i j  P  , hacemos i j−  P  para simular una estructura toroidal (circular). Una vez que cada procesador ya tiene los bloques A y B que le corresponden, los multiplica y almacena su resultado en un bloque para C con las coordenadas del mismo proceso. Luego se hacen   P −1 corrimientos circulares en cada procesador, de las filas de A por la izquierda y las columnas B por arriba. Las figuras siguientes, ilustran el proceso de manera gráfica. Luego se muestra el código principal del algoritmo implementado3. 3 Las imágenes presentadas en esta sección fueron extraídas de [1] para aclarar mejor el algoritmo implementado. 10/27
  • 11. Figure 3. Alineación inicial de A y B. Figure 4. A y B luego de la alineación inicial y luego del primer corrimiento. Figure 5. Alineación de las submatrices luego del tercer y cuarto corrimiento. for(pasos=1; pasos< raiz_p; pasos++){ // Desplazamiento Para Matriz A MPI_Cart_shift(malla, 1, -1, &origen, &destino); MPI_Sendrecv_replace(buffA, tam_bloq * tam_bloq, MPI_FLOAT, destino, 0 , origen, 0, malla, &estado_msg ); // Desplazamiento Para Matriz B MPI_Cart_shift(malla, 0, -1, &origen, &destino); MPI_Sendrecv_replace(buffB, tam_bloq * tam_bloq, MPI_FLOAT, destino, 0 , origen, 0, malla, &estado_msg ); //Pasamos del buffer al bloque local buff2Bloque(bloqueA, tamanho_bloque, buffA); buff2Bloque(bloqueB, tamanho_bloque, buffB); //Multiplicación acumular_multiplicar(bloqueA, bloqueB, bloqueC); } 11/27
  • 12. En cada paso, cada procesador multiplica su bloque de A por su bloque de B, y le suma al bloque de C que tiene. Finaliza el algoritmo y cada procesador P(i, j) tiene el bloque C(i, j) de la matriz resultado. 3.3.1 Diferencias, Mejoras El alineamiento inicial que se propone en el artículo [4], el algoritmo asume que en cada procesador P(i,j) se encuentra el bloque A(i,j) y B(i,j) y luego realiza i corrimientos a la izquierda para A y j corrimientos arriba para B. En nuestra implementación, sin embargo, el proceso P(0,0) calcula que bloque de A y de B es el que corresponde a los demás procesos después de la alineación inicial. Pensamos que esto podría mejorar el tiempo de ejecución en cada proceso evitando los corrimientos iniciales, pero esta mejora solo se dará en el caso de que efectivamente el proceso P(0,0) sea el encargado de distribuir los bloques, caso contrario no sería una mejora. 3.3.2 Limitaciones Las limitaciones y verificaciones de la implementación presentada son las siguientes: • La cantidad de procesos debe ser un cuadrado perfecto. Para la distribución equitativa de los bloques a los procesos en cada dimensión. • La cantidad de elementos (N) debe ser divisible entre la raíz cuadrada de la cantidad de procesos (P). Para que todos los bloques tengan el mismo tamaño, haciendo mas sencilla la implementación. 3.3.3 Análisis Asintótico Considerando solamente los corrimientos de a uno y la multiplicación de cada bloque en los procesos, tenemos que en cada corrimiento se pasan tam_bloque * tam_bloque elementos, N N N2 que es  × = , que seria para cada proceso, tanto para A y B, por lo cual P P P multiplicamos este término por 2. Si consideramos la comunicación y el tiempo de inicialización, tenemos que el gasto de comunicación es el siguientes: N2 2×t st w ×  P Por su parte, el procesamiento en sí de la multiplicación, asumiendo que esta y la suma toman una unidad de tiempo, entonces tendríamos un costo de tam_bloq * tam_bloq *tam_bloq es decir: N N N N3  × × =  P  P  P  P ×  P  Entonces el tiempo total de ejecución paralelo sería: N3 N T p= 2×t s t w ×  P P 12/27
  • 13. 3.4 Algoritmo DNS (Dekel, Nassimi, Sahni) El DNS es un algoritmo para la multiplicación de matrices densas, que lleva las siglas de sus creadores (Dekel, Nassimi, Sahni). Está basado en particionamiento de datos intermedios y está diseñado para usar una topología de procesadores en tres dimensiones. El algoritmo asume que en cada procesador se realiza una simple multiplicación escalar o de matrices en bloques más pequeños. Para la descripción se tienen P procesadores y el tamaño de bloques entonces es q= P . Generalizamos para que el algoritmo resuelva por bloques. 3 En la implementación realizada, se crea la topología en 3 dimensiones, luego el proceso P(0,0,0) realiza la distribución de los bloques de A y B en los procesos del plano 0. Después de este paso, todos los procesos P(i,j0) tienen el bloque A(i,j) y el bloque B(i,j). Este paso de comunicación inicial en el plano cero no se especifica como parte del algoritmo en su definición, sin embargo, para la implementación de este trabajo se ha decidido hacerlo. Luego cada proceso del plano 0 (Pi,j,0), envía las columnas j de A(*,j) y las filas i de B(i,*) a los pla0nos k=i para el bloque de A y k=j para el bloque de B. En los demás planos cada proceso recibe su parte de A y B. A continuación, cada proceso que está en el plano k=j y tiene la columna j debe replicar su bloque de A a los demás procesos que comparten su plano, para lo cual se utiliza la primitiva MPI_Bcast. Lo mismo para los procesos de k=i y que tienen la fila i, caso en el que se replica el bloque de B a los de su mismo plano y fila. A continuación se muestra la parte del código que realiza dicha acción. int remainA[3]={0,1,0}; MPI_Comm comm_1d_A; MPI_Cart_sub(comm_3d, remainA, &comm_1d_A ); MPI_Bcast(buffA, tamanho_bloque * tamanho_bloque, MPI_FLOAT, micoord[2], comm_1d_A); int remainB[3]={1,0,0}; MPI_Comm comm_1d_B; MPI_Cart_sub(comm_3d, remainB, &comm_1d_B ); MPI_Bcast(buffB, tamanho_bloque * tamanho_bloque, MPI_FLOAT, micoord[2], comm_1d_B); Luego cada uno de los P procesadores ya tiene el bloque de A y de B que le corresponde, es decir, el procesador P(i,j,k) tiene el bloque A(i,k) y el bloque B(k,j). Después de eso cada proceso realiza una simple multiplicación entre el bloque de A y B que tiene, y utilizando la función MPI_Reduce se realiza un all_to_one_reduce entre los elementos P(i,j,*) a través de la operación de suma. A continuación se resume el código para el paso final. acumular_multiplicar(bloqueA, bloqueB, bloqueC); bloque2Buff(bloqueC, tamanho_bloque, buffC); //Creamos un comunicador vertical MPI_Comm comm_vertical; int comm_vertical_id; int remain[3]={0,0,1}; MPI_Cart_sub(comm_3d, remain, 13/27
  • 14. &comm_vertical); MPI_Comm_rank(comm_vertical, &comm_vertical_id); MPI_Reduce( buffC , bufferFinal, tamanho_bloque * tamanho_bloque, MPI_FLOAT, MPI_SUM, 0, comm_vertical); buff2Bloque(bloqueFinal, tamanho_bloque, bufferFinal); Las siguientes dos imágenes, ilustran el algoritmo visualmente. Figure 6. La distribución inicial de A y B, y luego de realizar el envío de Aij desde Pij0 a Pijj 14/27
  • 15. Figure 7. Distribución luego del los Broadcastings de A y B 3.4.1 Diferencias con la propuesta original. En la implementación presentada el proceso (0,0,0) es el que lee toda la matriz A y B y empieza a distribuir a los procesos del plano cero. Esto hace que este proceso se pueda constituir en un cuello de botella al inicio del algoritmo, sobre todo para el caso de matrices grandes, en el que se puede producir la saturación del socket de envío de este proceso. Por otro lado, los elementos se tratan por bloques, en lugar de elementos como se muestra en [1]. Además, para el paso final del Reduce, todos los procesos P(i,j,k) suman su bloque de C entre los P(i,j,*) y estos se almacenan en los procesos del plano cero. Entonces al finalizar el algoritmo, la matriz C está distribuida entre los procesos P(0,0,0) a P(q,q,0), siendo q= P 3 3.4.2 Limitaciones: Las limitaciones y verificaciones de la implementación presentada son las siguientes: • La cantidad de procesos debe ser un cubo perfecto. Para la distribución equitativa de los bloques a los procesos en cada una de las 3 dimensiones. • La cantidad de elementos (N) debe ser divisible entre la raíz cúbica de la cantidad de procesos (P). Para que todos los bloques tengan el mismo tamaño, haciendo mas sencilla la implementación. 3.4.3 Tiempo de ejecución Toma un paso para multiplicar y q pasos para sumar, con costo Θ (log q), siempre teniendo q= P . 3 En cuanto a la comunicación, el primer paso de comunicación uno a uno se ejecuta en A y en n 2 B y toma un tiempo para cada matriz de tstw×  tw×log q  . El segundo q 15/27
  • 16. paso es un broadcast de uno a todos que se ejecuta en A y en B y toma un tiempo para cada n 2 matriz de ts×logqtw×  ×log q q La acumulación de nodo simple final se ejecuta una sola vez (para la matriz C) y toma un 2 n tiempo tslogqtw×  ×log q q 4 Plan de Pruebas. A continuación se describen los detalles de las pruebas, desde las configuraciones y entorno de ejecución paralelo hasta los cálculos de los datos de prueba y como éstos fueron ejecutados. 4.1 Datos de prueba Los parámetros de ejecución de los algoritmos paralelos son los siguientes: • N = Tamaño de la matrices de entrada y resultado • P = Cantidad de procesos. • C = Cantidad de máquinas. Atendiendo las limitaciones de N y P descritas en cada algoritmo en la sección 3, a continuación se presenta una tabla que resume el plan de ejecución de las pruebas. La cantidad de máquinas (C ) fue constante e igual 4 (7 procesadores= 3 dual core + 1 single core), luego se detallan totalmente las especificaciones de las mismas. Para que la comparación pueda ser hecha, agrupamos los valores en 3 tamaños de N y 3 de P, en cada caso, cada algoritmo puede tener una pequeña . La idea de las pruebas era lo siguiente: como se tenían 4 máquinas y 7 procesadores, entonces probar con P menor a 4 Resumen agrupado de las pruebas. N= 400 ~500 N= 900 N = 1200~1800 P=4 Cannon Cannon Cannon 2D 2D 2D 2DD 2DD 2DD(N=1800) P= 8 ~9 Cannon Cannon Cannon DNS (P=8) DNS (P=8) DNS (P=8) 2D (N= 441) 2D 2D (N =1764) 2DD 2DD 2DD P=16~27 Cannon Cannon Cannon DNS (P=27) DNS (P=27) DNS (P=27) 2D 2D 2D 2DD 2DD 2DD 16/27
  • 17. 4.2 Entorno Para la ejecución se usaron 4 máquinas con sistema operativo Linux Fedora Core 9, kernel 2.6.25.x. Se instaló y configuró la librería OPEN-MPI 1.2.2 y se uso el compilador mpicc, para las ejecuciones se usó mpirun. También se configuró la red y los servidores SSH de cada host para que se pueda ejecutar. Además se configuró la autentificación DSA, para eso en el host maestro donde se lanza la ejecución se generó la clave pública con ssh-keygen y se le pasó a cada una de las demás máquinas para que pueda interactuar vía ssh con esa autentificación. El usuario común usado en cada host uno fue mpiuser. Máquina Procesador Memoria RAM S.O cparra-portatil Intel Core Duo1,6 1,5 GB Linux Fedora Core 9. Ghz. Cache L2 4MB Kernel 2.6.25.xx liz Intel Core Duo. 1,46 1,0 GB Linux Fedora Core 9. Ghz. Cache L2 2MB. Kernel 2.6.25.xx fmanciahome Intel Core Duo. 3,00 1,0 GB Linux Fedora Core 9. Ghz. Cache L2 4MB Kernel 2.6.25.xx familia Intel Pentium IV 1,8 512 MB Linux Fedora Core 9. Ghz (single core) Kernel 2.6.25.xx 5 Resultados Obtenidos Se presentan en esta sección, los gráficos más importantes que resumen los principales resultados obtenidos en las pruebas. 5.1 Métricas Por cada prueba, se extrajeron los valores de las siguientes métricas: ✔ Tiempo de Ejecución en paralelo, obtenido como el tiempo de ejecución de un proceso paralelo en particular. Los procesos de nuestras implementaciones medían sus tiempos y estas medidas eran enviadas al proceso cero que se encargaba de guardarlas para su posterior análisis. De los tiempos de ejecución de los P procesos, se marca al mayor como el tiempo de ejecución paralelo de todo el algoritmo. ✔ Aceleración, que es el ratio entre el mejor tiempo secuencial y el tiempo de ejecución paralelo. Para este propósito, ejecutamos un algoritmo secuencial en una sola máquina para cada tamaño de N utilizado en las pruebas. ✔ Sobre Costo, definido como la diferencia entre el producto del tiempo paralelo por P y el tiempo secuencial. ✔ Eficiencia: definido como la relación entre la aceleración y la cantidad de procesos lanzados. De estas métricas, presentamos los resultados obtenidos para las dos primeras y la eficiencia. 17/27
  • 18. 5.2 Tiempos de ejecución: P=4;N=600 P=4;N=900 6.0000 18.0000 16.0000 5.0000 14.0000 4.0000 12.0000 10.0000 3.0000 8.0000 2.0000 6.0000 1.0000 4.0000 2.0000 0.0000 0.0000 2D CANNON 2DDIAGONAL 2D CANNON 2DDIAGONAL P=4;N=1200 45.0000 40.0000 35.0000 30.0000 25.0000 20.0000 15.0000 10.0000 5.0000 0.0000 2D CANNON 2DDIAGONAL Figure 8. Tiempos de ejecución de los algoritmos para la ejecución con 4 procesos La Figure 8 muestra los tiempos de ejecución paralela de cada algoritmo cuando se ejecutan en cuatro procesos y distintos tamaños de N. En general, se nota el bajo rendimiento del algoritmo 2D cíclico debido a que el proceso cero distribuye y realiza mucho cómputo. Esto no variará en ninguna de los resultados que se presentarán en esta sección. Además, se puede notar que el aumento en los tamaños de la entrada no afectan el rendimiento relativo de los algoritmos. Esta tendencia se mantuvo en casi todas las pruebas salvo algunas excepciones. Cannon se muestra más rápido que el algoritmo 2D diagonal, aunque el algoritmo 2D diagonal presenta tiempos de ejecución mínimos en los procesos no diagonales, lo cual es un dato muy interesante. Esto no se muestra en los gráficos, pero forma parte de los resultados obtenidos. El cuello de botella precisamente del 2D diagonal está en los procesos diagonales, que realizan un trabajo de cómputo adicional de empaquetamiento de mensajes y recepción de resultados. Dicho de otro modo, el 2D diagonal presenta una mayor eficiencia de comunicación, pero tiene problemas en el desbalanceo del trabajo existente, poniendo mayor carga de trabajo en los procesos diagonales. Con 4 procesos no se realizaron pruebas de DNS, que requiere un número cúbico de procesos. 18/27
  • 19. P=9;N=600 P=9;N=1200 5.0000 4 0.00 00 4.5000 3 5.00 00 4.0000 3.5000 3 0.00 00 3.0000 2 5.00 00 2.5000 2 0.00 00 2.0000 1 5.00 00 1.5000 1 0.00 00 1.0000 0.5000 5 .0 00 0 0.0000 0 .0 00 0 2D DNS CANNON 2DDIAGONAL 2D DNS C AN N ON 2 D D IAGON AL P=9;N=900 16.0000 14.0000 12.0000 10.0000 8.0000 6.0000 4.0000 2.0000 0.0000 2D DNS CANNON 2DDIAGONAL Figure 9. Tiempos de ejecución de los algoritmos para la ejecución con 9 procesos Con nueve procesos, ya se incluye en el análisis al algoritmo DNS, que muestra tiempos de ejecución muy similares al de Cannon. Sin embargo, las tendencias que se manifestaron en los primeros resultados con 4 procesos, se mantienen y sigue siendo Cannon el algoritmo con menor tiempo de ejecución, seguido del DNS y del 2D Diagonal. El 2D cíclico, como siempre, se mantiene en la última posición por los problemas que ya explicábamos más arriba. P=16;N=600 P=16;N=900 5.0000 25.0000 4.5000 4.0000 20.0000 3.5000 3.0000 15.0000 2.5000 10.0000 2.0000 1.5000 5.0000 1.0000 0.5000 0.0000 0.0000 2D DNS CANNON 2DDIAGONAL 2D DNS CANNON 2DDIAGONAL 19/27
  • 20. P=16;N=1200 45.0000 40.0000 35.0000 30.0000 25.0000 20.0000 15.0000 10.0000 5.0000 0.0000 2D DNS CANNON 2DDIAG- ONAL Figure 10. Tiempos de ejecución de los algoritmos para la ejecución con 16 procesos Para la ejecución de los algoritmos en 16 procesos, como se muestra en la Figure 10 se presentan excepciones. Para matrices pequeñas, la tendencia se mantiene, pero a medida que aumentamos el número de matrices llega el caso en el que DNS llega a un tiempo de ejecución inferior al de Cannon. En realidad, mirando los tres conjuntos de gráficos, podemos ver que DNS presenta mejoras en su tiempo de ejecución a medida que aumenta el tamaño de las matrices, fenómeno que no es tan notable en los demás algoritmos. 5.3 Aceleración y Eficiencia. En esta sección, se presentan los resultados de la aceleración y la eficiencia de los algoritmos implementados. La aceleración y la eficiencia de los algoritmos siguen en el mismo patrón relativo que los gráficos de tiempo de ejecución, lo cual era de esperarse. Lo notable en estos trabajos es que en ciertos casos, el 2D Cíclico tiene peor rendimiento que el algoritmo secuencial óptimo, lo que permite reafirmar la necesidad de separar a un proceso dedicado para que se comporte como maestro. P=4;N=400 P=4;N=600 3.5000 3.5000 3.0000 3.0000 2.5000 2.0000 2.5000 1.5000 2.0000 1.0000 1.5000 0.5000 1.0000 0.0000 0.5000 2D CANNON 2DDIAG- ONAL 0.0000 2D CANNON 2DDIAGONAL 20/27
  • 21. P=4;N=1200 3.5000 3.0000 2.5000 2.0000 1.5000 1.0000 0.5000 0.0000 2D CANNON 2DDIAGONAL Figure 11. Aceleración y Eficiencia (en menor escala) de los algoritmos para la ejecución con 4 procesos Además, otra cosa notable es que ninguno de los algoritmos tiene una eficiencia mayor al 70%, lo que habla de que las sobrecargas por comunicación y otros cómputos están aproximadamente entre el 50% y el 70%. P=9;N=600 P=9;N=900 1.6000 4.0000 1.4000 3.5000 1.2000 3.0000 1.0000 2.5000 0.8000 2.0000 0.6000 1.5000 0.4000 1.0000 0.2000 0.5000 0.0000 0.0000 2D DNS CAN 2DDI- 2D DNS CANNON 2DDIAG- NON AGONAL ONAL P=9; N=1200 4.5000 4.0000 3.5000 3.0000 2.5000 2.0000 1.5000 1.0000 0.5000 0.0000 2D DNS CANNON 2DDIAGONAL Figure 12. Aceleración y Eficiencia (en menor escala) de los algoritmos para la ejecución con 8 y 9 procesos 21/27
  • 22. Al aumentar el número de procesos a 9, podemos incluir a DNS en el análisis y se confirma lo que se puede notar con los tiempos de ejecución: DNS aumenta notablemente a medida que se procesan tamaños mayores de la entrada. Para N=600, DNS tiene un rendimiento inferior al algoritmo secuencial, mientras que al llegar a tamaños superiores al 1000, llega a alcanzar una eficiencia cercana al 70%. Otra cosa notable de estos resultados es el rendimiento superescalar de Cannon cuando la N llega a 1200. Por una lado, el entorno de ejecución paralelo de las pruebas no era totalmente homogéneo, y las pruebas secuenciales se ejecutaron en uno de los nodos que no necesariamente podría obtener los mejores resultados. Por otra parte, algunos de los nodos del entorno estaban equipados con procesadores de dos núcleos, lo cual pudo haber incrementado el nivel de paralelismo. Cualquiera de estos motivos puede explicar la superescalabilidad. O tal vez esta superescalabilidad se debe a alguna de las razones tradicionales explicadas en [1]: los algoritmos paralelos efectivamente realizan menos trabajo en proporción que el algoritmo secuencial, o la división de los datos hace que para los bloques más pequeños de datos, se aproveche mejor las capacidades de la cache de cada nodo. P=16;N=600 P=16;N=900 5.0000 1.4000 4.5000 1.2000 4.0000 1.0000 3.5000 3.0000 0.8000 2.5000 0.6000 2.0000 0.4000 1.5000 1.0000 0.2000 0.5000 0.0000 0.0000 2D DNS CANNON 2DDIAG- 2D DNS CANNO N 2DDIAGO NAL ONAL P=16;N=1200 4.0000 3.5000 3.0000 2.5000 2.0000 1.5000 1.0000 0.5000 0.0000 2D DNS CANNON 2DDIAGONAL Figure 13. Aceleración y Eficiencia (en menor escala) de los algoritmos para la ejecución con 16 y 27 procesos 22/27
  • 23. Por otro lado, debido a la presencia de nodos con procesadores doble núcleo, teóricamente la aceleración debería dispararse entre los resultados con 4 procesos y aquellos obtenidos con 8 o 9. Sin embargo esto no sucede lo que nos lleva a la conclusión de que la implementación MPI utilizada no aprovecha al máximo las posibilidades de multiprocesamiento en los nodos. Los tres últimos gráficos de aceleración y eficiencia sencillamente confirman las tendencias presentadas en los demás resultados. Para tamaños grandes de matrices, la aceleración de DNS es superior a la de Cannon, probablemente por su menos sobrecarga de comunicación. Por otro lado, aunque esto no se nota en los gráficos, de los resultados extraídos en las pruebas, también pudimos notar al revisar los tiempos de ejecución de cada proceso ejecutado por un algoritmo, que el DNS es el que presenta mayor estabilidad. Por su parte, Cannon es el que presenta mayores variaciones entre los tiempos de ejecución de los distintos procesos. 2D Diagonal por su parte, presenta la misma inestabilidad que Cannon y bajos tiempos de ejecución en los procesos no diagonales, mientras que el tiempo de ejecución se dispara en la diagonal de la topología. 6 Conclusiones ✔ Se alcanzaron los objetivos de profundizar los conceptos de programación paralela a través de la implementación de algoritmos paralelos. ✔ Se pudo comprobar que la paralización de la solución efectivamente disminuye el tiempo de solución del mismo. ✔ En el caso particular de la multiplicación de matrices, casi todos los algoritmos aceleraron la solución, con excepción del algoritmo 2D cíclico. ✔ A partir de tamaños de matrices superiores a 1000, ninguno de los algoritmos paralelos tiene aceleración inferior a 1, y a medida que aumenta el tamaño, algunos algoritmos mejoran su rendimiento. ✔ Cannon ofrece, entre todos los algoritmos paralelos implementados, las mejores prestaciones en cuánto a tiempo de ejecución se refiere. ✔ DNS sin embargo, aumenta su rendimiento a medida que aumenta el tamaño de las matrices de entrada. ✔ En cuánto a la variabilidad de los algoritmos, entendiendo variabilidad como variación entre los tiempos de ejecución de cada proceso, DNS ha probado ser el algoritmo más estable. ✔ Cannon, sin embargo, es el más inestable en este sentido. ✔ 2D diagonal tiene una variabilidad similar a la de Cannon, con el agregado de que los procesos diagonales presentan tiempos de ejecución muy superiores que los que no son diagonales. 7 Trabajos Futuros • Mejorar el modelo maestro-esclavo del algoritmo 2D cíclico: el problema fundamental en la implementación del algoritmo 2D cíclico, es que el proceso maestro se convierte en un cuello de botella cuando se procesan matrices grandes. Una solución interesante que puede aumentar dramáticamente el rendimiento de este algoritmo es dedicar uno de los procesos a la tarea exclusiva de ser maestro y distribuidor de tareas. 23/27
  • 24. Esto podría permitir que efectivamente se optimice el solapamiento del cómputo con las comunicaciones, y se reduciría al mínimo el Idling time gracias a que tan pronto un proceso quede libre, seriá asignado a una nueva tareas. Otra mejora en este modelo consiste en reducir la restricción de asignación cíclica, y permitir que la asignación de tareas se realice directamente al procesador que quedó libre primero. Esto se puede implementar fácilmente reemplazando la asignación circular, por un mecanismo de cola de procesos a la que se irán agregando los procesos por orden de llegada a medida que quedan libres. Finalmente, una mejora más que se le podría realizar al algoritmo 2D consiste en implementar un mecanismo de pre-empaquetamiento de datos a enviar. Es decir, una vez que el proceso maestro termino de asignar una ráfaga de tareas, que comience inmediatamente a empaquetar los próximos mensajes para que cuando llegue el momento, estos estén listos y se minimice el tiempo de ociosidad del proceso maestro. • Aprovechamiento de las capacidades multi-hilos de los procesadores con múltiples núcleos: MPI no aprovecha las capacidades de los procesadores de manejar hilos. El resultado es que cada proceso es lanzado en cada procesador como un proceso pesado. Un trabajo interesante seriá realizar una implementación de estos algoritmos sobre una implementación de MPI que aproveche la capacidad de multihilado de los procesadores, como la que se propone en [8], y lance las tareas como hilos en cada nodo y no como procesos pesados. En los resultados obtenidos por este trabajo se notó que la utilización de procesadores doble-núcleo en la ejecución de los procesos por medio de MPI, no generaba mejoras muy notables en la aceleración. • Otro trabajo interesante, sería analizar el rendimiento de estos algoritmos para matrices no densas, en busca de posibles optimizaciones particulares a los mismos aplicables a distintos tipos de matrices especiales. 8 Referencias [1] Ananth Grama, Anshul Gupta, George Karypis, Vipin Kumar: Introduction to Parallel Computing, Second Edition. Addison Wesley. 2003. [2] MatrixMarket - Mathematical and Computational Sciences Division NIST (National Institute Standars and Technology) - http://math.nist.gov/MatrixMarket/ [3] http://en.wikipedia.org/wiki/Matrix_(mathematics) [4] Generalized Cannon's algorithm for parallel matrix multiplication. Hyuk-Jae Lee, James P. Robertson, José A. B. Fortes. [5] Communication Efficient Matrix Multiplication on Hypercubes. Himanshu Gupta, P. Sadayappan. [6] Rendimiento de Algoritmos Paralelos de Multiplicación de Matrices implementados con Hilos. Cristhian Parra, Fernando Mancía. Facultad Politécnica de la Universidad de Asunción, 2008. [7] www.open-mpi.org [8] F. García, A. Calderón, J. Carretero, MiMPI: a multithread-safe implementation of MPI, in: Recent Advances in Parallel Virtual Machine and Message-Passing Interface, Proceedings of the Sixth European PVM/MPI Users' Group Meeting, Lecture Notes in Computer Science 1697, Springer, September 1999, pp. 207-214. 24/27
  • 25. 9 Anexo: Tablas de Resultados. Re sultados obte nidos con 4 proc e sos Tie mpo Tie mpo Ac ele rac Sobre Efic ie nci Eficie n Efic ie nc Alg oritmo Tamaño Costo Parale lo Se c ue nc ial ión C osto a c ia* ia** 2D 40 0 2,08 4 6 1,0727 0,514 6 7,2657 0,128 6 8 ,338 4 0,128 6 0,0735 CANNON 40 0 0,4 4 8 4 1,0727 2,3924 0,7208 0,598 1 1,7934 0,598 1 0,34 18 2DDIAG ONAL 40 0 0,7767 1,0727 1,38 10 2,034 2 0,34 53 3,1069 0,34 53 0,1973 2D 576 5,29 80 1,4811 0 ,279 6 19 ,710 9 0 ,0 6 9 9 -- -- -- CANNON 600 1,7351 1,4 8 11 0,8 536 5,4 591 0,2134 6,94 03 0,2134 0,1219 2DDIAG ONAL 600 3,0172 1,4 8 11 0,4 909 10,58 76 0,1227 12,068 7 0,1227 0,0701 2D 900 15,7728 16,8 34 0 1,0673 4 6,2572 0,2668 63,0913 0,2668 0,1525 CANNON 900 5,6179 16,8 34 0 2,9965 5,6375 0,74 91 22,4 715 0,74 91 0,4 28 1 2DDIAG ONAL 900 8 ,5221 16,8 34 0 1,9753 17,254 2 0,4 938 34 ,08 8 2 0,4 938 0,28 22 2D 129 6 40 ,2125 -- -- -- -- -- -- -- CANNON 120 0 13,3522 4 0,568 7 3,038 3 12,8 4 02 0,7596 53,4 08 8 0,7596 0,4 34 0 2DDIAG ONAL 120 0 20,8 328 4 0,568 7 1,94 73 4 2,7626 0,4 8 68 8 3,3313 0,4 8 68 0,278 2 2D 16 0 0 69,5011 8 7,1772 1,254 3 190,8 274 0,3136 278 ,004 5 0,3136 0,1792 CANNON 150 0 30,7217 -- -- -- -- -- -- -- 2DDIAG ONAL 150 0 4 1,9274 79,5236 1,8 967 8 8 ,18 61 0,4 74 2 167,7097 0,4 74 2 0,2710 2D 180 0 -- -- -- -- -- -- -- -- CANNON 180 0 -- -- -- -- -- -- -- -- 2DDIAG ONAL 180 0 73,3709 137,5139 1,8 74 2 155,9695 0,4 68 6 293,4 8 34 0,4 68 6 0,2677 2D 250 0 223,4 08 8 377,6175 1,6903 516,0178 0,4 226 8 93,6353 0,4 226 0,24 15 CANNON 250 0 -- -- -- -- -- -- -- -- Tabla 1. Resultados en la ejecución de los algoritmos con 4 procesos. 25/27
  • 26. Re sultados obte nidos c on 9 proc e sos (8 para DNS) Tie mpo Tam Tie mpo Ac e le ra Sobre Efic ie n Efic ie n Efic ie n Alg oritmo Se c ue nc ia C osto año Parale lo c ión C osto c ia c ia* c ia** l 2D 441 2,3232 1,4 8 11 0,6375 19,4 273 0,0708 20,908 4 0,1594 0,0911 DNS 40 0 0,4 220 1,0727 2,54 16 2,3037 0,3177 3,3764 0,6354 0,3631 CANNO N 40 0 -- -- -- -- -- -- -- -- 2DDIAG O NAL 40 0 -- -- -- -- -- -- -- -- 2D 576 4,4131 1,4811 -- -- -- -- -- -- DNS 600 1,8514 1,4811 0 ,80 0 0 13,330 3 0 ,10 0 0 14,8114 0 ,20 0 0 0 ,1143 CANNO N 600 1,04 11 1,4 8 11 1,4 227 7,8 8 8 4 0,158 1 9,3695 0,3557 0,2032 2DDIAG O NAL 6 0 0 2,138 7 1,4 8 11 0,6925 17,7671 0,0769 19,24 8 2 0,1731 0,098 9 2D 900 13,6772 16,8 34 0 1,2308 106,2608 0,1368 123,094 9 0,3077 0,1758 DNS 900 5,7700 16,8 34 0 2,9175 29,3256 0,364 7 4 6,1596 0,7294 0,4 168 CANNO N 900 5,0051 16,8 34 0 3,3634 28 ,2121 0,3737 4 5,04 61 0,8 4 08 0,4 8 05 2DDIAG O NAL 9 0 0 7,5669 16,8 34 0 2,224 7 51,268 2 0,24 72 68 ,1023 0,5562 0,3178 2D 129 6 35,2415 -- -- -- -- -- -- -- DNS 120 0 14,176 2 40 ,56 87 2,86 17 72,840 7 0 ,3577 113,40 9 4 0 ,7154 0 ,40 88 CANNO N 120 0 10,0516 4 0,568 7 4 ,0361 4 9,8 953 0,4 4 8 5 90,4 64 0 1,0090 0,5766 2DDIAG O NAL 120 0 17,3277 4 0,568 7 2,34 13 115,38 07 0,2601 155,94 94 0,58 53 0,334 5 2D 176 4 79,54 51 129,7509 1,6312 58 6,154 9 0,18 12 715,9058 0,4 078 0,2330 DNS 16 0 0 -- -- -- -- -- -- -- -- CANNO N 150 0 22,6051 79,5236 3,5179 123,9226 0,3909 203,4 4 63 0,8 795 0,5026 2DDIAG O NAL 150 0 34 ,8 575 79,5236 2,28 14 234 ,1936 0,2535 313,7172 0,5703 0,3259 2D 176 4 79 ,5451 129 ,750 9 1,6 312 586 ,1549 0 ,1812 715,9 0 58 0 ,40 78 0 ,2330 DNS 180 0 -- -- -- -- -- -- -- -- CANNO N 180 0 -- -- -- -- -- -- -- -- 2DDIAG O NAL 180 0 62,4 08 9 137,5139 2,2034 4 24 ,1659 0,24 4 8 561,6798 0,5509 0,314 8 2D 250 0 -- -- -- -- -- -- -- -- DNS 250 0 -- -- -- -- -- -- -- -- CANNO N 250 0 -- -- -- -- -- -- -- -- 2DDIAG O NAL 270 0 231,6767 4 93,714 2 2,1310 1591,3765 0,2368 208 5,0907 0,5328 0,304 4 Tabla 2. Resultados en la ejecución de los algoritmos con 9 procesos. 26/27
  • 27. Re sultados obte nidos c on 16 proc e sos (27 proc e sos para DNS) Tie mpo Tam Tie mpo Ac e le ra Sobre Efic ie n Efic ie n Efic ie n Alg oritmo Se c ue nc ia C osto año Parale lo c ión C osto c ia c ia* c ia** l 2D 40 0 1,8 58 8 1,0727 0,5771 28 ,668 1 0,0361 29,74 07 0,14 4 3 0,08 24 DNS 40 0 -- -- -- -- -- -- -- -- CANNO N 40 0 0,398 7 1,0727 2,6905 5,3062 0,168 2 6,378 9 0,6726 0,38 4 4 2DDIAG O NAL 40 0 0,718 8 1,0727 1,4 924 10,4 277 0,0933 11,5004 0,3731 0,2132 2D 576 4,6 245 1,4811 -- -- -- -- -- -- DNS 600 1,49 31 1,4811 0 ,9 9 20 38,8323 0 ,0 36 7 40 ,3134 0 ,2480 0 ,1417 CANNO N 600 1,238 7 1,4 8 11 1,1958 18 ,3373 0,074 7 19,8 18 4 0,298 9 0,1708 2DDIAG O NAL 6 0 0 2,3018 1,4 8 11 0,64 35 35,34 8 3 0,04 02 36,8 294 0,1609 0,0919 2D 10 24 71,1670 78 ,6965 1,1058 1059,9755 0,0691 1138 ,6720 0,2765 0,158 0 DNS 900 8 ,64 99 16,8 34 0 1,94 61 216,714 0 0,0721 233,54 8 1 0,4 8 65 0,278 0 CANNO N 900 3,7332 16,8 34 0 4 ,5093 4 2,8 971 0,28 18 59,7312 1,1273 0,64 4 2 2DDIAG O NAL 80 0 5,5556 10,9094 1,9637 77,98 03 0,1227 8 8 ,8 8 96 0,4 909 0,28 05 2D 129 6 39 ,6 770 -- -- -- -- -- -- -- DNS 120 0 11,4744 40 ,56 87 3,5356 26 9 ,239 9 0 ,130 9 30 9 ,80 85 0 ,8839 0 ,50 51 CANNO N 120 0 12,7215 4 0,568 7 3,18 90 162,9753 0,1993 203,54 4 0 0,7972 0,4 556 2DDIAG O NAL 120 0 21,0735 4 0,568 7 1,9251 296,6076 0,1203 337,1763 0,4 8 13 0,2750 2D 16 0 0 69,0511 8 7,1772 1,2625 1017,6399 0,078 9 ### 0,3156 0,18 04 DNS 150 0 25,1913 79,5236 3,1568 600,64 25 0,1169 68 0,1661 0,78 92 0,4 510 CANNO N 150 0 24 ,5998 79,5236 3,2327 314 ,0730 0,2020 393,5967 0,8 08 2 0,4 618 2DDIAG O NAL 150 0 39,2616 79,5236 2,0255 54 8 ,6622 0,1266 628 ,18 58 0,5064 0,28 94 2D 180 0 -- -- -- -- -- -- -- -- DNS 180 0 43,30 0 1 137,5139 3,1758 10 31,5883 0 ,1176 116 9 ,10 22 0 ,79 40 0 ,4537 CANNO N 180 0 -- -- -- -- -- -- -- -- 2DDIAG O NAL 180 0 73,7756 137,5139 1,8 639 104 2,8 94 9 0,1165 ### 0,4 660 0,2663 2D 270 0 -- -- -- -- -- -- -- -- DNS 270 0 -- -- -- -- -- -- -- -- CANNO N 270 0 -- -- -- -- -- -- -- -- 2DDIAG O NAL 270 0 236,38 50 4 93,714 2 2,08 8 6 328 8 ,4 4 57 0,1305 378 2,1599 0,5222 0,298 4 Tabla 3. Resultados en la ejecución de los algoritmos con 16 y 27 procesos. 27/27