Você está na página 1de 21

UNIVERSIDADE FEDERAL DO R IO G RANDE DO S UL INSTITUTO DE INFORMTICA PROGRAMA DE PS -GRADUAO EM CINCIA DA COMPUTAO INTRODUO AO PROCESSAMENTO PARALELO E DISTRIBUDO PROF.

NAVAUX

Algoritmo para resoluo do problema do Caixeiro Viajante

por Alexandre Cervieri Mnica Py

Porto Alegre, Julho de 2000.

Sumrio
1. Introduo ________________________________________________________________ 3 2. Modelagem Inicial __________________________________________________________ 4 3. Implementao distribuda com troca de mensagens _______________________________ 6 4. Medida de Desempenho ______________________________________________________ 8 5. Dificuldades & Comentrios __________________________________________________ 9 6. Referncias Bibliogrficas___________________________________________________ 10 7. Anexo ___________________________________________________________________ 10

1. Introduo
O Problema do Caixeiro Viajante um dos mais clssicos problemas de Complexidade. Se caracteriza por, dado um conjunto de n cidades e uma matriz de distncias distancias[1..n,1..n], fazer com que seja encontrado um caminho que tenha a menor distncia a ser percorrida para que sejam visitadas todas as cidades passando exatamente uma nica vez em cada cidade e retornando a cidade de origem. O problema do caixeiro viajante considerado um problema do otimizao, alm de exibir uma soluo requerida uma certa qualidade tima da soluo. Esse problema NP-completo pois no tem soluo determinstica polinomial. Para solucionar o problema do Caixeiro Viajante, no cluster da sala 207 do Instituto de Informtica da UFRGS, foi utilizada a biblioteca para programao distribuda MPI. MPI uma biblioteca de troca de mensagens desenvolvida para ambientes de memria distribuda, mquinas paralelas massivas, NOWs (network of workstations) e redes heterogneas. Cluster uma mquina de alto desempenho que possui uma arquitetura baseada na reunio de um conjunto de estaes de trabalho independentes, interconectadas por uma rede de comunicao, formando uma plataforma de execuo de aplicaes paralelas de alto desempenho. O Grupo de Processamento Paralelo e Distribudo da UFRGS possui uma

plataforma de execuo para aplicaes paralelas um cluster formado por 4 nodos. Cada nodo um Dual Pentium Pro, com 64 M de memria RAM e clock de 200Mhz. Estes nodos esto interconectados por duas redes de comunicao: uma rede Fast Ethernet e outra rede Myrinet. O sistema operacional Linux, com kernel 2.2.1 e compilador C++ (gcc). Uma caracterstica marcante do MPI que no existem processos, existe um nico processo que pode ser rodado em vrias mquinas (chamadas de nodos) j previamente montadas na mquina virtual e no modificvel em tempo de execuo. MPI define um conjunto de rotinas para facilitar a comunicao (troca de dados e sincronizao) entre processos paralelos. A biblioteca MPI portvel para qualquer arquitetura, tem aproximadamente 125 funes para programao e ferramentas para analisar o desempenho. A biblioteca MPI permite que os programas possam ser escritos nas linguagens Fortran, C e C++. Alguns dos principais objetivos do MPI: Confiabilidade e facilidade de uso so os objetivos principais do MPI. Esfora-se para definir uma interface de troca de mensagens que seja possvel de ser implementada eficientemente. A semntica da interface MPI foi escrita para ser independente da linguagem.

Todo paralelismo explcito, ou seja, o programador responsvel por identificar o paralelismo e implementar o algoritmo utilizando chamadas aos comandos da biblioteca MPI. No segundo captulo apresenta-se a modelagem inicial do algoritmo utilizado. O terceiro captulo descrito como feita a implementao distribuda com troca de mensagens. Na seo seguinte mostra-se medidas de desempenho do algoritmo sequencial comparado a implementao feita em MPI. Nos captulos cinco e seis so feitos comentrios do trabalho, juntamente com o cdigo fonte desenvolvido, e as concluses, respectivamente.

2. Modelagem Inicial
O algoritmo utilizado, Replicated Workers with a Bag of Tasks, se baseia em um conjunto de trabalhadores que buscam tarefas em uma sacola compartilhada. Cada tarefa consiste em um caminho parcial das cidades contidas na matriz original. Essas tarefas so processadas pelos trabalhadores de modo que seja acrescentada mais uma cidade, at que seja encontrado um caminho que passe por todas as cidades do problema. Quando o primeiro caminho encontrado, ele designado como mnimo. Assim que novos caminhos completos so encontrados, eles substituem o primeiro como o caminho mnimo, caso a sua distncia seja realmente menor. Os dados iniciais necessrios para o algoritmo so o nmero de trabalhadores, o nmero de cidades e o conjunto de distncias que separam cada cidade. Neste caso, as cidades so supostamente totalmente conectadas. Na figura 1 se v um exemplo de uma configurao com 4 cidades e a matriz gerada. possvel representar um cenrio onde as cidades no sejam totalmente conectadas indicando a distncia entre elas como um valor extremamente alto para sua distncia, dessa forma, esse caminho sempre ser ignorado pelo algoritmo.

54

2 76 79 3 46

1
38 4

0 54 79 38

54 0 46 76

79 46 0 71

38 76 71 0

71

Matriz representando o cenrio de ligao entre cidades mostrado ao lado.

Uma primeira implementao do algoritmo descrito acima foi feita na linguagem Java com a utilizao de memria compartilhada e threads para o paralelismo dos trabalhadores.

Cada trabalhador foi implementado como uma thread com fluxo prprio de execuo, tendo acesso a um conjunto de dados compartilhados representado por uma instncia de uma classe Java. Como essa instncia acessvel por todos os processos trabalhadores ela exige um controle de sincronismo. Os mtodos de acesso aos dados compartilhados foram definidos como synchronized, primitiva da linguagem Java que garante a execuo do mtodo como uma sesso crtica. Esta implementao est baseada em 3 classes bsicas: classe Task: representa uma tarefa que ir ser processada por um dos trabalhadores. Cada tarefa consiste no nmero de cidades visitadas, pelo conjunto de cidades deste caminho e pela distncia percorrida. classe Shared: a classe responsvel pela obteno dos dados iniciais do problema (nmero de cidades e matriz de distncias) bem como pelo armazenamento desses dados. Cada trabalhador tem acesso a instncia dessa classe de modo a poder obter a distncia entre duas cidades especficas, obter tarefas para serem processadas, inserir novas tarefas na sacola, e finalmente atualizar o caminho mnimo quando a distncia encontrada for menor. classe Worker: classe derivada da classe Thread, a responsvel pelo processamento das tarefas, e pode te quantas instncias quanto o usurio que dispara o programa desejar. A condio de parada dos trabalhadores no existir mais nenhuma tarefa a ser processada bem como no existir mais nenhum trabalhador processando outra tarefa. Alm das classes acima descritas, uma classe adicional, representando o programa princ ipal a responsvel pelo disparo das instncias das classes Shared, Worker. Na figura 2 pode ser visto um diagrama com a representao da comunicao entre cada classe. As setas indicam a invocao de um mtodo na outra classe.

SalesMan

instanciao

instanciao

RecvTask

Shared

Worker

SendTask Update getDistancia Final Bag :

Task

3. Implementao distribuda com troca de mensagens


A passagem de uma implementao com memria compartilhada para um modelo distribudo com comunicao feita atravs de troca de mensagens implica em um esquema de sincronismo e passagem de dados mais complexo. O nmero de mensagens tambm alto.

Shared
Entrada de dados

distncias

Workers
SEND distncias

Distribui distncias

Recebe distncias

SENDRECV recvtask

Recebe comandos

SEND notask SEND task SEND task SEND update SEND stop SEND nowork SEND work

Processamento

Resultad o

Na figura acima pode ser visto um diagrama contendo o fluxo de troca de mensagens entre os processos. De modo a simular o comportamento das classes acima descrito, estabeleceu-se um protocolo de troca de mensagens entre os processos, onde, a classe que anteriormente era

compartilhada passou a ser representada por um objeto servidor que se tornou o centro de comunicao para os demais processos. A programao foi feita utilizando-se ANSI C, com uso da biblioteca (middleware) de troca de mensagens MPI.

4. Medida de Desempenho
Para realizar os testes, foi criado arquivos contendo matrizes de distancias para as cidades. Cada arquivo desenvolvido contm os valores apresentados no texto a seguir. Na realizao dos testes, primeiramente foi executado a verso sequencial do programa, e consequentemente a verso paralela. Os resultados obtidos esto considerados nas tabelas. Em cada tabela encontra-se o nmero de cidades, tempo necessrio para a execuo do programa sequencial e o tempo de execuo em paralelo. O nmero de cidades inicialmente testadas foram 4. Contatamos que para 10 cidades, a soluo do algoritmo em JAVA, obteve tempo de processamento 12826619 ms que equivale a 3h33m46s, com resultado 261 unidades, sendo o caminho encontrado 0 1 6 2 7 4 5 8 9 3. (isso em ambiente Linux, pois em Windows NT a Mquina JAVA no suportou a carga). Segue as tabelas com as matrizes e os resultados obtidos em cada execuo.

Arquivo: distancias_4.txt Matriz de distncias 0 77 12 70 77 0 49 57 12 49 0 1 70 57 1 0

Nmero de Cidades 4

Matriz Cidades Tempo Seqencial (ms) 930 Tabela 1

Tempo Paralelo (s) 0s

Arquivo: distancias_5.txt Matriz de distncias 0 21 61 80 3 21 0 4 71 7 61 4 0 97 60 80 71 97 0 57 3 7 60 57 0

Nmero de Cidades 5

Matriz Cidades Tempo Seqencial (s) 1s21 Tabela 2

Tempo Paralelo (s) 0.2s

Arquivo: distancias_6.txt Matriz de distncias 0 2 40 4 96 46 2 0 56 92 82 19 40 56 0 47 48 95 4 92 47 0 73 0 96 82 48 73 0 33 46 19 95 0 33 0

Nmero de Cidades 6

Matriz Cidades Tempo Seqencial (s) 2s42 Tabela 3

Tempo Paralelo (s) 0.4s

5. Dificuldades & Comentrios


O trabalho desenvolvido incentiva a utilizao de arquiteturas paralelas e distribudas para a resoluo de aplicaes que necessitam de grande capacidade de processamento. Assim conclui-se que os resultados de desempenho alcanados compensam o trabalho de adaptar o cdigo seqencial para paralelo. Em anexo encontra-se o cdigo fonte do trabalho.

6. Referncias Bibliogrficas
[BUB97] BUBAK, M.; DONGARRA, J.J.;WASNIEWSKI, J. Recent Advances in Parallel Virtual Machine and Message Passing Interface. EUROPEAN PVM/MPI USERS GROUP MEETING (4). Berlin; Springer Verlag, 1997. 518 p. [MPI00] MPI/Pro Help On-line . MPI Software Technology, Inc. Disponvel por WWW em http://www.mpi-softtech.com/docs/mpipro/index.html (29 jun de 2000). [MPI00] The Message Passing Interface (MPI) standard. Disponvel por WWW em http://www-unix.mcs.anl.gov/mpi (01 jul de 2000). [PAC97] PACHECO, P.Parallel Programming with MPI. San Francisco: Morgan Kaufman, 1997. 418 p. [RIG99] RIGONI, Eduardo H.; VILA, R. B.; BARRETO, M. E.; SCHLEMER, E.; DE ROSE, C. A. F.; DIVERIO, T. A.; NAVAUX, P. O. A. Introduo programao em clusters de alto desempenho. RP 305 Outubro / 1999. UFRGS-PPGC. [TER90] TERADA, R. Introduo complexidade de algoritmos paralelos. In: ESCOLA DE COMPUTAO, VII 1990, So Paulo, Curso, So Paulo, IME-USP, 1990. 104p.

7. Anexo
Cdigo fonte dos arquivos salesman.c e salesman.h salesman.h
#include <time.h> // -// Definies para o sistema #define MAX_MSG_SIZE 256 //tamanho mximo das mensagens #define RANK_SERVER 0 //ndice do processo que servidor #define MSG_UPDATE 0 //msg de worker para atualziar caminho mnimo #define MSG_RECVTASK 1 //msg de worker pedindo por uma tarefa #define MSG_SENDTASK 2 //msg de worker desejando enviar uma tarefa #define MSG_TASK 3 //msg de server respondendo com uma tarefa #define MSG_NOTASK 4 //msg de server respondendo que no tem tarefa #define MSG_INIT 5 //msg de server com os dados iniciais do problema #define MSG_STOP 6 //msg de worker dizendo que terminou #define MSG_HAVEWORK 7 //msg de worker pedindo se ainda deve trabalhar #define MSG_WORK 8 //msg de server dizendo para worker trabalhar #define MSG_NOWORK 9 //server dizendo para worker parar de trabalhar #define MSG_NONE 10 #define MSG_END '#' //marca de final de mensagem // Forward das estruturas e funes do programa void printPacket(char* packet); struct Task{ int hops; //nmero de cidades nessa task int totalhops; //nmero total de cidades do problema int length; //tamanho do caminho dessa tarefa int *path; //lista das cidades que esto nessa tarefa, nesse

10

caminho struct Task *next; }; //funes associadas char *Task_toString(struct Task *task); char *Task_toPacket(struct Task *task); struct Task *Task_toTask(char *packet); void Task_push(struct Task **list,struct Task *task); struct Task *Task_pop(struct Task **list); void Task_clonePath(int **dest,int *source,int size); void Task_free(struct Task *task); //... struct Shared{ int numworkers; //nmro de workers int *endworkers; //indica quais workers esto parados int numliveworkers; //nmero de processos que ainda esto rodando int numcidades; //nmero de cidades do problema int **distancias; //distncia entre as cidades int shortest; //tamanho do caminho mnimo encontrado int *shortestpath; //o menos caminho struct Task *bag; //lista com as tarefas a serem feitas time_t timeInicial; //tempo de incio do algoritmo time_t timeFinal; //tempo de fim do algoritmo }; //funes associadas struct Shared *Shared_init(char *ndistfile,int nworkers); char *Shared_toString(struct Shared *shared); void Shared_finalize(struct Shared **shared); void Shared_update(struct Shared *shared,char *message); void Shared_recvTask(struct Shared *shared,int source); void Shared_sendTask(struct Shared *shared,char *message); void Shared_main(char* ndistfile,int nworkers); void Shared_stop(struct Shared *shared,int source); void Shared_haveWork(struct Shared *shared,int source); //... struct Worker{ int numcidades; //nmero de cidades do problema int **distancias; //matriz das distncias entre as cidades }; //funes associadas char *Worker_toString(struct Worker *worker); char *Worker_toPacket(struct Worker *worker); struct Worker *Worker_toWorker(char *packet); int Worker_visit(struct Worker *worker,int city,struct Task *task); void Worker_main(); // --

salesman.c
// -// Introduo ao Processamento Paralelo e Distribudo // Programa: 'The Salesman Problem: Replicated Workers and a Bag of Tasks' // Implementao utilizando MPI: Messages Passsing Interface // ltima modifcao: 30 de junho de 2000 // -// -#define _MPI //#define _DEBUG // -// --

11

// Biliotecas utilizadas #include "salesman.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #ifdef _MPI #include "mpi.h" #endif // -// -void printPacket(char* packet){ int i=0; printf("# ("); while(packet[i]!=MSG_END){ printf(" %d",packet[i]); i++; } printf(" )\n"); } // Funes associadas a estrutura de dados Task char *Task_toString(struct Task *task){ int i; char *str, *tmp; str = (char*) malloc(4*MAX_MSG_SIZE*sizeof(char)); tmp = (char*) malloc(10*sizeof(char)); strcpy(str,"\tPath:( "); for(i=0;i<task->totalhops;i++){ sprintf(tmp,"%d ",task->path[i]); strcat(str,tmp); } sprintf(tmp,") Hops:[%d] Length:[%d]",task->hops,task->length); strcat(str,tmp); free(tmp); return str; } char* Task_toPacket(struct Task *task){ int i; char *str; str = (char*) malloc(MAX_MSG_SIZE*sizeof(char)); str[0] = (char) MSG_NONE; //vai sempre o tipo da mensagem... str[1] = (char) task->hops; //1: nmero de cidades na task str[2] = (char) task->totalhops; str[3] = (char) ((task->length&0xFF000000)>>24); //3: length[0] ([0][1][2][3]) str[4] = (char) ((task->length&0x00FF0000)>>16); //4: length[1] str[5] = (char) ((task->length&0x0000FF00)>>8); //5: length[2] str[6] = (char) ((task->length&0x000000FF)>>0); //6: length[3] for(i=0;i<task->totalhops;i++) str[7+i] = (char) task->path[i]; str[7+i] = MSG_END; return str; } struct Task *Task_toTask(char* packet){ int i,tmp; struct Task *task; task = (struct Task*) malloc(sizeof(struct Task)); task->hops = (int) packet[1]; task->totalhops = (int) packet[2]; Task_clonePath(&(task->path),NULL,task->totalhops); task->length = 0;

12

tmp = (int) packet[6]; tmp = (tmp<0)?(256+tmp):tmp; task->length += tmp; tmp = (int) packet[5]; tmp = (tmp<0)?(256+tmp):tmp; task->length += tmp<<8; tmp = (int) packet[4]; tmp = (tmp<0)?(256+tmp):tmp; task->length += tmp<<16; tmp = (int) packet[3]; tmp = (tmp<0)?(256+tmp):tmp; task->length += tmp<<24; for(i=0;i<task->totalhops;i++) task->path[i] = (int) packet[7+i]; return task; } void Task_push(struct Task **list,struct Task *task){ task->next = (*list); (*list) = task; } struct Task *Task_pop(struct Task **list){ struct Task* task; task = (*list); if ((*list)!=NULL) (*list) = (*list)->next; return task; } void Task_clonePath(int **dest, int* source, int size){ int i; (*dest) = (int*) malloc(size*sizeof(int)); if( source!= NULL ) for(i=0;i<size;i++) (*dest)[i] = source[i]; else for(i=0;i<size;i++) (*dest)[i] = 0; } void Task_free(struct Task *task){ free(task->path); free(task); } // -// -// Funes associadas a estrutura de dados Shared struct Shared *Shared_init(char* ndistfile, int nworkers){ int k; struct Shared *shared; shared = (struct Shared*) malloc(sizeof(struct Shared)); shared->numworkers = nworkers; shared->numliveworkers = nworkers; shared->endworkers = (int*) malloc(shared->numworkers*sizeof(int)); for(k=0;k<shared->numworkers;k++) shared->endworkers[k] = 0; { int i=0,j=0; int valor; FILE* handle; if( (handle = fopen(ndistfile,"r"))==NULL ){ printf("@ERRO FATAL: no foi possvel abrir o arquivo.\n"); free(shared);

13

return NULL; }else{ fscanf(handle,"%d\n",&valor); shared->numcidades = valor; shared->distancias = (int**) malloc(shared->numcidades*sizeof(int*)); for(i=0;i<shared->numcidades;i++){ shared->distancias[i] = (int*) malloc(shared>numcidades*sizeof(int)); for(j=0;j<shared->numcidades;j++){ fscanf(handle,"%d\n",&valor); shared->distancias[i][j] = valor; } } fclose(handle); } } shared->shortest = 10000; Task_clonePath(&(shared->shortestpath),NULL,shared->numcidades); printf("%s\n",Shared_toString(shared)); return shared; } char* Shared_toString(struct Shared* shared){ int i,j; char *str,*tmp; str = (char*) malloc(2048*sizeof(char)); tmp = (char*) malloc(80*sizeof(char)); sprintf(str,"#Shared\n\t#num. cidades: %d\n",shared->numcidades); sprintf(tmp,"\t#distancias: \n"); strcat(str,tmp); for(i=0;i<shared->numcidades;i++){ sprintf(tmp,"\t\t"); strcat(str,tmp); for(j=0;j<shared->numcidades;j++){ sprintf(tmp,"%d ",shared->distancias[i][j]); strcat(str,tmp); } strcat(str,"\n"); } sprintf(tmp,"\t#shortest: %d\n",shared->shortest); strcat(str,tmp); sprintf(tmp,"\t#shortestpath: ("); strcat(str,tmp); for(i=0;i<shared->numcidades;i++){ sprintf(tmp," %d",shared->shortestpath[i]); strcat(str,tmp); } sprintf(tmp," )\n"); strcat(str,tmp); return str; } void Shared_finalize(struct Shared **shared){ int i=0; { printf("\n#algoritmo finalizado.\n"); printf("#tempo inicial: %d\n",(*shared)->timeInicial); printf("#tempo final: %d\n",(*shared)->timeFinal); printf("#tempo de processamento: %f(us)\n",difftime((*shared)>timeFinal,(*shared)->timeInicial)); printf("%s\n",Shared_toString((*shared))); } for(i=0;i<(*shared)->numcidades;i++) free((*shared)->distancias[i]); free((*shared)->distancias); free(*shared); } void Shared_update(struct Shared *shared,char *message){ int i; struct Task *task;

14

task = Task_toTask(message); #ifdef _DEBUG printf("S_update: %s\n",Task_toString(task)); #endif if( task->length<shared->shortest){ shared->shortest = task->length; for(i=0;i<task->totalhops;i++) shared->shortestpath[i] = task->path[i]; } Task_free(task); } void Shared_recvTask(struct Shared *shared,int source){ struct Task *task; char *message; if ( ( task = Task_pop(&(shared->bag)) ) != NULL ){ message = Task_toPacket(task); message[0] = (char) MSG_TASK; #ifdef _MPI MPI_Send(message,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,source,MSG_NONE,MPI_COMM_WORL D); #ifdef _DEBUG printf("S_recvtask(%d): ",source); printPacket(message); #endif #endif Task_free(task); free(message); }else{ message = (char*) malloc(2*sizeof(char)); message[0] = (char) MSG_NOTASK; message[1] = MSG_END; #ifdef _MPI MPI_Send(message,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,source,MSG_NONE,MPI_COMM_WORL D); #ifdef _DEBUG printf("S_recvtask(%d): ",source); printPacket(message); #endif #endif free(message); } } void Shared_sendTask(struct Shared *shared,char* message){ struct Task *task; task = Task_toTask(message); #ifdef _DEBUG printf("S_sendtask: %s\n",Task_toString(task)); #endif if( task->length<shared->shortest ) Task_push(&(shared->bag),task); else Task_free(task); } void Shared_stop(struct Shared *shared,int source){ shared->endworkers[source] = 1; } void Shared_haveWork(struct Shared *shared,int source){ int i,end=1; char *message;

15

message = (char*) malloc(2*sizeof(char)); for(i=1;i<=shared->numworkers;i++) end &= shared->endworkers[i]; if( end==1 ){ message[0] = (char) MSG_NOWORK; message[1] = MSG_END; #ifdef _MPI MPI_Send(message,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,source,MSG_NONE,MPI_COMM_WORL D); #ifdef _DEBUG printf("S_havework: "); printPacket(message); #endif #endif shared->numliveworkers--; }else{ message[0] = (char) MSG_WORK; message[1] = MSG_END; #ifdef _MPI MPI_Send(message,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,source,MSG_NONE,MPI_COMM_WORL D); #ifdef _DEBUG printf("S_havework: "); printPacket(message); #endif #endif } free(message); } void Shared_main(char* ndistfile,int nworkers){ struct Shared *shared; if ( (shared = Shared_init(ndistfile,nworkers))!=NULL ){ int i,j; struct Task *task; for(i=1;i<shared->numcidades;i++){ task = (struct Task*) malloc(sizeof(struct Task)); task->hops = 2; task->totalhops = shared->numcidades; task->length = shared->distancias[0][i]; Task_clonePath(&(task->path),NULL,shared->numcidades); task->path[0] = 0; task->path[1] = i; Task_push(&(shared->bag),task); } {//Enviando dados iniciais do problema, nmero de cidades e matriz de distncias struct Worker *worker; char *message; int i; worker = (struct Worker*) malloc(sizeof(struct Worker)); worker->numcidades = shared->numcidades; worker->distancias = shared->distancias; message = Worker_toPacket(worker); message[0] = (char) MSG_INIT; shared->timeInicial = time(NULL); for(i=1;i<=shared->numworkers;i++){ #ifdef _MPI MPI_Send(message,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,i,MSG_NONE,MPI_COMM_WORLD);

16

#endif } } {//Iniciando servidor de tarefas, inicialmente fica esperando requisio char *message; int origem=0,tipomsg=0,source=0; #ifdef _MPI MPI_Status status; #endif message = (char*) malloc(MAX_MSG_SIZE*sizeof(char)); while(shared->numliveworkers!=0){ for(i=1;i<=shared->numworkers;i++){ #ifdef _MPI MPI_Recv(message,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,i,MSG_NONE,MPI_COMM_WORLD,&st atus); #ifdef _DEBUG printf("S_main (%d): ",i); printPacket(message); #endif #endif tipomsg = (int) message[0]; switch(tipomsg){ case MSG_UPDATE:{ Shared_update(shared,message); }break; case MSG_RECVTASK:{ Shared_recvTask(shared,i); }break; case MSG_SENDTASK:{ Shared_sendTask(shared,message); }break; case MSG_STOP:{ Shared_stop(shared,i); }break; case MSG_HAVEWORK:{ Shared_haveWork(shared,i); }break; } }//END: for }//END: while }//Fim do algoritmo shared->timeFinal = time(NULL); Shared_finalize(&shared); } } // -// -// Funes associadas a estrutura de dados Worker char *Worker_toString(struct Worker *worker){ int i,j; char *str,*tmp; str = (char*) malloc(2048*sizeof(char)); tmp = (char*) malloc(80*sizeof(char)); sprintf(str,"#Worker\n\t#num. cidades: %d\n",worker->numcidades); sprintf(tmp,"\t#distancias: \n"); strcat(str,tmp); for(i=0;i<worker->numcidades;i++){ sprintf(tmp,"\t\t"); strcat(str,tmp); for(j=0;j<worker->numcidades;j++){ sprintf(tmp,"%d ",worker->distancias[i][j]); strcat(str,tmp);

17

} strcat(str,"\n"); } return str; } char *Worker_toPacket(struct Worker *worker){ int i,j,k=2; char *str = (char*) malloc(MAX_MSG_SIZE*sizeof(char)); str[0] = (char) MSG_NONE; str[1] = (char) worker->numcidades; //0: nmero de cidades for(i=0;i<worker->numcidades;i++) for(j=0;j<worker->numcidades;j++){ str[2+(worker->numcidades*i)+j] = (char) worker->distancias[i][j]; k++; } str[k]=MSG_END; return str; } struct Worker *Worker_toWorker(char *packet){ int i,j; struct Worker *worker; worker = (struct Worker*) malloc(sizeof(struct Worker)); worker->numcidades = (int) packet[1]; worker->distancias = (int**) malloc(worker->numcidades*sizeof(int*)); for(i=0;i<worker->numcidades;i++){ worker->distancias[i] = (int*) malloc(worker->numcidades*sizeof(int)); for(j=0;j<worker->numcidades;j++) worker->distancias[i][j] = (int) packet[2+(worker->numcidades*i)+j]; } return worker; } int Worker_visit(struct Worker *worker,int city,struct Task *task){ int i=0,newlength=0,javisitada=0; for(i=1;i<task->hops;i++){ if(task->path[i]==city){ newlength = 0; javisitada = 1; } } if( javisitada == 0 ){ newlength = task->length + worker->distancias[task->path[task->hops1]][city]; task->path[task->hops] = city; } return newlength; } void Worker_main(){ char *sendbuff, *recvbuff; int i,msgtipo,city,newlength,working=1; time_t inicio; #ifdef _MPI MPI_Status status; #endif struct Task *task,*newTask; struct Worker *worker; sendbuff = (char*) malloc(MAX_MSG_SIZE*sizeof(char)); recvbuff = (char*) malloc(MAX_MSG_SIZE*sizeof(char)); {//Recebendo dados iniciais do problema (instncia de worker) #ifdef _MPI MPI_Recv(recvbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE,MPI_COM

18

M_WORLD,&status); #endif worker = Worker_toWorker(recvbuff); #ifdef _DEBUG printf("%s\n",Worker_toString(worker)); #endif } while(working==1){ sendbuff[0] = (char) MSG_RECVTASK; sendbuff[1] = MSG_END; #ifdef _MPI #ifdef _DEBUG printf("W_main: \n"); printPacket(sendbuff); #endif MPI_Sendrecv(sendbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE, recvbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE,MPI_COMM_WORLD,& status); #ifdef _DEBUG printPacket(recvbuff); #endif #endif msgtipo = (int) recvbuff[0]; if( msgtipo==MSG_TASK){ //tem tarefa para processar task = Task_toTask(recvbuff); #ifdef _DEBUG printf("W_task: %s\n",Task_toString(task)); #endif for(city=1;city<task->totalhops;city++){ newlength = Worker_visit(worker,city,task); if( newlength==0 ){ //no faz nada, cidade j visitada }else{ if( (task->hops+1)<task->totalhops ){ char *l_sendbuff; newTask = (struct Task*) malloc(sizeof(struct Task)); newTask->hops = task->hops+1; newTask->totalhops = task->totalhops; newTask->length = newlength; Task_clonePath(&(newTask->path),task->path,task->totalhops); l_sendbuff = Task_toPacket(newTask); l_sendbuff[0] = (char) MSG_SENDTASK; #ifdef _MPI #ifdef _DEBUG printf("W_sendtask: "); printPacket(l_sendbuff); printf("%s\n",Task_toString(newTask)); #endif MPI_Send(l_sendbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE,MPI_C OMM_WORLD); #ifdef _DEBUG printf("sendtask enviado\n"); #endif #endif }else{ if( (task->hops+1)==task->totalhops ){ char *l_sendbuff; newTask = (struct Task*) malloc(sizeof(struct Task));

19

newTask->hops = task->hops+1; newTask->totalhops = task->totalhops; Task_clonePath(&(newTask->path),task->path,task->totalhops); newTask->length = newlength + worker->distancias[newTask>path[newTask->totalhops-1]][0]; l_sendbuff = Task_toPacket(newTask); l_sendbuff[0] = (char) MSG_UPDATE; #ifdef _MPI #ifdef _DEBUG printf("W_update: "); printPacket(l_sendbuff); #endif MPI_Send(l_sendbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE,MPI_C OMM_WORLD); #ifdef _DEBUG printf("update enviado\n"); #endif #endif } } }//END: else newlength=0 }//END: for city }else{ //no tem nenhuma tarefa no momento para processar sendbuff[0] = (char) MSG_STOP; sendbuff[1] = MSG_END; #ifdef _MPI #ifdef _DEBUG printf("W_stop: "); printPacket(sendbuff); #endif MPI_Send(sendbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE,MPI_COM M_WORLD); #ifdef _DEBUG printf("stop enviado "); #endif #endif inicio = time(NULL); while( time(NULL)-inicio<1 ); sendbuff[0] = (char) MSG_HAVEWORK; sendbuff[1] = MSG_END; #ifdef _MPI #ifdef _DEBUG printf("W_havetask: "); printPacket(sendbuff); #endif MPI_Sendrecv(sendbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE, recvbuff,MAX_MSG_SIZE,MPI_UNSIGNED_CHAR,RANK_SERVER,MSG_NONE,MPI_COMM_WORLD,& status); #ifdef _DEBUG printPacket(recvbuff); #endif #endif msgtipo = (int) recvbuff[0]; if(msgtipo==MSG_WORK) working = 1; else working = 0; } }//END: while

20

} // -// -// Programa principal int main(int argc,char** argv){ int i; printf("-----\n"); for(i=0;i<argc;i++) printf("%d: %s\n",i,argv[i]); printf("-----\n"); { int mpi_myrank; //nmero do processo atual int mpi_numprocess; //nmero de processos rodando #ifdef _MPI MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&mpi_myrank); MPI_Comm_size(MPI_COMM_WORLD,&mpi_numprocess); #endif if( mpi_myrank==RANK_SERVER ){ Shared_main(argv[1],mpi_numprocess-1); }else{ Worker_main(); } #ifdef _MPI MPI_Finalize(); #endif } return 0; } // --

21

Você também pode gostar