Escolar Documentos
Profissional Documentos
Cultura Documentos
MATRICES
Guido Casco
guiancs82@gmail.com
Claudio Lezcano
claudiogmi@gmail.com
1 Introducción
En este trabajo se tiene por objetivo implementar y comparar dos versiones de algoritmos de
multiplicación de matrices con diferentes mecanismos de mapeo y particionamiento de tareas, en
particular los algoritmos de cannon y de multiplicación con mapeo por bloque circular. Además
se desea comparar el comportamiento de los mismos con diferentes cargas de trabajo y comparar
su desempeño con la versión mono-proceso mas comúnmente utilizada.
Para el desarrollo de las versiones en paralelo se ha utilizado la librería de paso de mensajes
MPICH con el compilador gcc.
A continuación se describe cada una de las implementaciones desarrolladas.
2 Descripción del Hardware y de la Red utilizada
Características de la Red
Velocidad de Transmisión: 1Gbps
Cable de Red: Giganet 5E UTP 4x2x2
Descripción
Este algoritmo es particularmente apropiado para sistemas de paso de mensajes, además de
ajustarse de manera muy sencilla al mapeo por bloques
Utiliza una malla con conexiones entre los elementos de cada lado (toro) para desplazar los
elementos de A hacia la izquierda y los de B hacia arriba.
El algoritmo sigue los siguientes pasos:
1. El procesador Pij tiene los elementos aij y bij.
2. La fila i-ésima de A se desplaza i posiciones a la izquierda, y la columna j-ésima de B se
desplaza j posiciones hacia arriba, ambos desplazamientos se realizan de forma circular.
3. Cada procesador multiplica su par de elementos.
4. Cada fila de A se desplaza una posición a la izquierda, y cada columna de B una posición
hacia arriba.
5. Cada procesador multiplica su nuevo par de elementos, y suma el resultado al anterior.
6. Se repiten los pasos 4 y 5 hasta terminar, es decir n – 1 desplazamientos.
Esta implementación recibe como entrada dos matrices cuadradas de dimensiones NxN y el
mapeo utilizado fue el de bloques de una dimensión (1D), de la siguiente forma. Se distribuyen
las filas de ambas matrices de entrada A y B entre cada uno de los P procesos, de modo que
cada proceso posee N/P filas de A y de B. Antes de asignar las filas a cada proceso, el proceso
P0 se encarga de realizar la preparación inicial de ambas matrices (paso 2 del algoritmo descrito
anteriormente).
De este modo, cada proceso procede a multiplicar y acumular los productos de los elementos de
A y B.
Para efectuar el paso 6 del algoritmo descrito, cada proceso efectúa una rotación con su copia
local de las filas contiguas de A y una rotación con su copia de las filas de la matriz B mediante
paso de mensajes, de modo que el proceso Pi envía una celda de su porción de B al proceso Pi-1
como se muestra en la siguiente figura:
Implementación
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Status stat;
row_end_cond = M/size;
if(rank == 0) {
row_cnt = M_cnt = M/size;
mat_A = crear_matriz (row_cnt, M);
mat_B = crear_matriz (row_cnt, M);
mat_c = crear_matriz (row_end_cond , M);
cannon_shift(matrizA, M, N, 'L');
cannon_shift(matrizB, M, N, 'U');
if(rank==0) {
for(j=0 ; j<row_end_cond ; j++) {
matrizC[j] = mat_c[j];
}
M_cnt = row_end_cond;
for(i = 1 ; i<size ; i++) {
if(i==size-1 && M % (size)!=0) {
row_end_cond = M % (size)+ 1;
}
void shift(int** array, int step, int row_shift, char side, int rows,int cols)
{
int k,j;
int i = step;//%(size-1);
int aux;
for(k=0;k<step;k++) {
if(side == 'L')
aux = array[row_shift][0];
else
aux = array[0][row_shift];
void MPI_shift(int** arr, int rows,int cols, int rank, int MPI_size, int comm) {
int stat;
int k,j;
int i = 0;
int aux=0;
int aux1=0;
int reciver;
int sender;
reciver = rank-1;
if(reciver<0)
reciver= MPI_size-1;
sender = (rank+1);
if(sender == MPI_size)
sender = 0;
Descripción
Una de las características de la distribución por particionamiento por bloque circular es que se
reduce la cantidad de ociosidad, todos los procesos tienen una muestra de tareas desde todas las
partes de la matriz. Como resultado, aunque si las partes diferentes de la matriz requieren
diferentes cantidades de trabajo, el trabajo general sobre cada proceso se balancea. También, ya
que las tareas asignadas a un proceso pertenecen a diferentes partes de la matriz, hay una buena
oportunidad para que al menos algunos de ellos estén listos para ejecutarse en un tiempo dado.
/**
Existe 2 Procesos Especiales que tienen funciones específicas, y son las siguientes:
1- Un Proceso MASTER que tiene rank igual a 1, que tiene la función de distribuir los bloques para
cada proceso utilizando la técnica de distribución circular.
2- Otro proceso DESTINO que tiene rank igual a 0, que recibe todos los resultado de los procesos a
las cuales se les distribuyo los bloques para que pueda realizar las multiplicaciones.
Los demás procesos reciben sus bloques desde el proceso MASTER y realizan las multiplicaciones debidas con
sus bloques asignados y retornan sus resultados al proceso DESTINO con el fin de que pueda agrupar en una
matriz RESULTADO_TOTAL.
*/
int block_cyclic_matrix_multiplication (
int A [ROW_SIZE_MATRIX_A][COLUMN_SIZE_MATRIX_A_ROW_SIZE_MATRIX_B],
int B [COLUMN_SIZE_MATRIX_A_ROW_SIZE_MATRIX_B][COLUMN_SIZE_MATRIX_B],
int C[ROW_SIZE_MATRIX_A][COLUMN_SIZE_MATRIX_B],
MPI_Datatype datatype, int source, MPI_Comm comm) {
MPI_Status stat;
int rs, rr, tag=0;
int cyclic = 0;
for(cyclic = 0; cyclic <(ROW_SIZE_MATRIX_A/(PROCESS_AMOUNT * BLOCK_SIZE)); cyclic++) {
int filaInicial = 0;
rr = MPI_Recv(&filaInicial, 1, MPI_INT, MASTER, 0, comm, &stat);
int cyclic = 0;
for(cyclic = 0; cyclic <(ROW_SIZE_MATRIX_A/(PROCESS_AMOUNT * BLOCK_SIZE)); cyclic++) {
int source = 2;
for( source = 2; source<PROCESS_AMOUNT+2; source++ ) {
rr = MPI_Recv(RESULTADO_PARCIAL, BUFFER_SIZE, MPI_INT, source, 0, comm, &stat);
int i=0;
int j=0;
for(i=0; i<ROW_SIZE_MATRIX_A; i++){
for(j=0; j<COLUMN_SIZE_MATRIX_B; j++){
if(RESULTADO_PARCIAL[i][j] != 0) {
RESULTADO_TOTAL[i][j]=RESULTADO_PARCIAL[i][j];
}
}
}
}
}
}
else if(rank_actual == MASTER) {
int cyclic = 0;
for(cyclic = 0; cyclic <(ROW_SIZE_MATRIX_A/(PROCESS_AMOUNT * BLOCK_SIZE)); cyclic++) {
int destinatario = 0;
int *inicio = (int *)malloc(sizeof(int));
for(destinatario = 2; destinatario < PROCESS_AMOUNT+2; destinatario++) {
if(destinatario == 2) {
inicio[0] = cyclic*BLOCK_SIZE*PROCESS_AMOUNT;
}
else {
inicio[0] = inicio[0] + BLOCK_SIZE;
}
A continuación se muestra la tabla de resultados de los tiempos de ejecución para cada algoritmo
con diferentes cargas de trabajo:
Las matrices utilizadas para cada una de las comparaciones fueron las mismas, con valores
generados aleatoriamente.
En la tabla anterior los resultados de las pruebas fueron realizadas con matrices cuadradas de
dimensiones especificadas en la misma. Los valores “NOWORK” implican que la aplicación no
ha podido efectuar el cómputo con los parámetros especificados.
En la tabla de resultados, se observa claramente una gran diferencia entre los tiempos de
ejecución de los algoritmos paralelos y el algoritmo serial, siendo los tiempos de ejecución del
algoritmo serial sensiblemente menor que los de sus contrapartes paralelas, esto es debido a que
existe un sobrecosto elevado en la ejecución de los algoritmos paralelos utilizando la librería
MPI, ya que la misma efectúa una serie de operaciones e inicialización de variables externas al
algoritmo propiamente dicho que incrementan enormemente el overhead del mismo. Esto
sumado al costo de gestión de los diferentes procesos lanzados en las versiones paralelas así
como el costo de las comunicaciones entre procesos a través de la red, tanto en término de
cómputo como de tiempo de transmisión.
Con este trabajo pudimos visualizar las diferencias en tiempo de ejecución entre los algoritmos
paralelos de multiplicación de matrices (Cannon y Distribución por Bloque Circular) y el
algoritmo serial de multiplicación de matrices, el tiempo de ejecución de los algoritmos paralelos
tienen un tiempo de sobrecarga asociada, el tiempo de comunicación interprocesos y las
comunicaciones a través de la red.
Con este trabajo también se puede concluir que los Algoritmos Paralelos tienden a administrar
mejor los recursos como procesadores multi-núcleos.
6 Referencias
Conclusiones .................................................................................................................................. 9
Referencias..................................................................................................................................... 9