420 likes | 695 Views
Tres Algoritmos Paralelos para Multiplicación Matriz Vector. Capitulo 8. Los Tres Algoritmos para computar el producto matriz-vector Ab=c. Rowwise block striped Columnwise block striped Checkerboard block. Algoritmo Secuencial (cont).
E N D
Tres Algoritmos Paralelos para Multiplicación Matriz Vector Capitulo 8
Los Tres Algoritmospara computar el producto matriz-vector Ab=c • Rowwise block striped • Columnwise block striped • Checkerboard block
Algoritmo Secuencial (cont) • Entrada: una matríz mXn a[0..m-1][0..n-1] y un vector b[0..n-1] • Salida: El producto a b = c[0..m-1] • for i←0 to m-1 do c[i] ←0 for j←0 to n-1 do c[i] ← c[i] + a[i,j] * b[j] endfor endfor
Algoritmo I (Rowwise block striped matrix) • Descomposición de dominio • Una tarea primitive está asociada con • una fila de la matríz y • el vector b entero
Producto interior b ci Fila i of A b c Fila i de A Comunicación All-gather Un Paso del Algoritmo Paralelo b Fila i de A
Aglomeración y Asignación de Procesos • Aglomerar grupos de filas • Cada proceso tiene un bloque de filas y todo de los vectores b y c • La función read_row_striped_matrix particiona la matriz A en p bloques de filas y distribuye los bloques a los procesos
La idea del algoritmo • Cada proceso computa un bloque de c • La función replicate_block_vector hace uso de MPI_Allgatherv para concatenar los bloques de c y dejar el resultado en cada uno de los procesadores.
MPI_Allgatherv int MPI_Allgatherv ( void *send_buffer, int send_cnt, MPI_Datatype send_type, void *receive_buffer, int *receive_cnt, int *receive_disp, MPI_Datatype receive_type, MPI_Comm communicator)
Algoritmo II (Columnwise block striped matrix) • Descomposición de dominio • Una tarea primitive está asociada con • una columna de la matríz y • un bloque apropiado del vector b
Multiplications b ~c Column i of A All-to-all exchange b c b ~c Column i of A Column i of A Reduction Phases of Parallel Algorithm b Column i of A
Archivo Leer una matriz en forma de bloques de columnas
Aglomeración y Asignación de Procesos • Aglomerar grupos de columnas • Cada proceso tiene un bloque de columnas, un bloque de b y un producto interior y todo de los vectores b y una suma parcial de c • La función read_col_striped_matrix particiona la matriz A en p bloques de columnas y distribuye los bloques a los procesos. Para esto hace uso de la función MPI_Scatterv
MPI_Scatterv int MPI_Scatterv ( void *send_buffer, int *send_cnt, int *send_disp, MPI_Datatype send_type, void *receive_buffer, int receive_cnt, MPI_Datatype receive_type, int root, MPI_Comm communicator)
La fase computacional • Cada proceso multiplica su bloque de columnas por su bloque de b y asi computa una suma parcial de c. • El resultado final será la suma de estas sumas parciales. • Para efectuar la suma de las sumas parciales, se puede aplicar comunicaciones alltoall
All-to-all Exchange (Before) P0 P1 P2 P3 P4
All-to-all Exchange (After) P0 P1 P2 P3 P4
MPI_Alltoallv int MPI_Alltoallv ( void *send_buffer, int *send_cnt, int *send_disp, MPI_Datatype send_type, void *receive_buffer, int *receive_cnt, int *receive_displacement MPI_Datatype receive_type, MPI_Comm communicator)
Algoritmo III Descomposición Checkerboard
Diseño del Algoritmo • Asociar una tarea primitiva con cada elemento de la matríz A • Cada tarea primitive hace una multiplicación • Aglomerar tareas primitivas en bloques rectangulares • Procesos constituyen una parrilla bidimensional • Distribuir el vector b en los procesos de la primera columna de la parrilla
Redistribuir el Vector b • Paso 1: Mover b de la primera columna a la primera fila • Si p es un cuadrado • Procesos en la primera columna envian sus pedazos de b a procesos de la primera fila • Si p no es un cuadrado • Acumula (“gather”) b en el proceso (0, 0) • El process (0,0) distribuye (“scatters” ) los pedazos de b en los procesos en la primera fila • Paso 2: Los procesos de la primera fila emiten los pedazos de b dentro de las columnas
Comunicadores • Comunicaciones colectivas envuelve todos los procesos en un comunicador. • Necesitamos hacer broadcasts y reduciones dentro de subconjuntos de procesos • Necesitamos crear comunicadores para hacer esto • Crearemos comunicadores para procesos en la misma fila o en la misma columna.
Comunicadores Un comunicador consiste de • un grupo de procesos • un contexto • atributos, que incluyen una topología
Para Crear una Parrilla Vitual de Procesos • MPI_Dims_create • parametros de entrada • número de procesos en la parrilla deseada • número de dimensiones • Devuelve el número de procesos en cada dim • MPI_Cart_create • Crea un comunicador con una topología cartesiana
MPI_Dims_create • int MPI_Dims_create( int nodes, /*el número de procesos en la parrilla*/ int dims, /* el número de dimensiones */ int *tamano/* el tamano de cada dimension*/)
Ejemplo de MPI_DIMS_create Supongamos que nos gustaria determinar las dimensiones de una malla bidimensional balanceado que contiene p proocesos. Esto se logra como sigue: int p; int tamano[2]; … tamano[0]=0;tamano[1]=0; MPI_Dims_create [p,2,tamano] Despues de ejecutar este segmento de código, MPI_Dim_create, tamano[0] contendra la cantidad de filas y tamano[1] contendra la cantidad de columnas.
MPI_Cart_create • Crea un comunicador con una topología cartesiana MPI_Cart_create( MPI_Comm com_viejo, int dims, int *size,/*un arreglo de tamaño dims*/ int *periodico, /*un arreglo de tamano dims, periodico[j]=1 si se desea “wraparound” en la dimension j*/ int reordenar, /*0 si rango en el nuevo comunicador es lo mismo como en el viejo*/ MPI_Comm *com_cart)
Ejemplo de MPI_Cart_create • Supongamos que • el comunicador viejo es MPI_COMM_WORLD • la malla tiene 2 dimensiones, que la función MPI_Dims_create ya ha inicializado el arrelgo tamano que contiene los tomaños de cada dimensión • no queremos “wraparounds” • el rango de cada proceso es igual a su rango en el comunicador viejo
Ejemplo de MPI_Cart_create(2) MPI_Comm cart_comm; int p; int periodico[2]; int tamano[2]; … tamano[0]=tamano[0]=0; MPI_Dim_create(p,2,tamano) periodico[0]=periodico[1]=0; MPI_Cart_create(MPI_COMM_WORLD,2,tamano, periodico,0);
Dos Funciones Relacionadas con Parrillas • MPI_Cart_rank • Devuelve el rango del proceso, dada las coordenadas del proceso en un comunicador cartesiano • MPI_Cart_coords • Devuelve las coordenadas cartesianas de un proceso, dado su rango.
MPI_Cart_rank int MPI_Cart_rank ( MPI_Comm com, int *coords, int *rango)
MPI_Cart-coords int MPI_Cart_coords ( MPI_Comm com, /* In - Communicator */ int rango, int dims, int *coords)
Ejemplo #include <stdio.h> #include <mpi.h> int main (int argc, char **argv) { MPI_Comm com_cart; int id; int p; int tamano[2]; int periodo[2]; int coords[2]; MPI_Init (&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &p); tamano[0]=tamano[1]=0; MPI_Dims_create(p,2,tamano); MPI_Cart_create(MPI_COMM_WORLD,2,size,periodo,1,&com_cart); MPI_Comm_rank(com_cart,&id); MPI_Cart_coords(com_cart,id,2,coords); printf("id=%d, (%d,%d)\n",id,coords[0],coords[1]); MPI_Finalize(); return 0}
MPI_Comm_split • MPI_Comm_split(MPI_Comm com_viejo, int particion,int orden_rango, MPI_Comm *com_nuevo) Particiona un comunicador existente com_viejo en una o mas particiones. Se agrupan todos los procesos que tienen el mismo número particion El rango en el nuevo comunicador se da por orden_nuevo
Ejemplo • En el ejemplo anterior, se puede hacer un comunicador de la primera columna de com_cart: • MPI_Comm_split(com_cart,coords[1]==0, coords[0],&com_col)
Leer un vector b de un archivo y distribuirlo en com_col • Hacer uso de read_block_vector en MyMPI.c: read_block_vector(argv[1],(void **) &b, mpitype, &m, com_col);
Analisis de Complexidad(presumiendo que m=n) • Cada proceso hace su parte de la computación: (n2/p) • Redistribuir b: (n / p + log p(n / p )) = (n log p / p) • Reducción de los vectores de resultados parciales: (n log p / p) • La complexidad paralela total: (n2/p + n log p / p)
Analisis de Isoeficiencia • Complexidad Secuencial: (n2) • Complexidad de comunicación:(n log p / p) • La función de Isoeficiencia:n2 Cn p log p n C p log p • M(n)=n2 M(C p log p)/p = C2 log2p