Badanie wydajności przesyłania komunikatów pomiędzy procesami
-- Sebastian Pawlak, 2000.
Kod źródłowy pliku "serial.c":
/* Program bada wydajnosc przesylania message`ow pomiedzy procesami.
* s1222, 2000.03.25
* Oto schemat ilustrujacy w jaki sposob przesylane sa message
*
* +-----+ ----> +-----+ ----> +-----+ ----> +-----+
* | A + | B | | B | | C |
* +-----+ <---- +-----+ <---- +-----+ <---- +-----+
*
* Program przyjmuje parametry:
* [1] - liczba iteracji (1 iteracja to cykl: A,B,..,B,C,B,..,B,A
* [2] - liczba bajtow message`a
*/
#include <stdio.h>
#include "mpi.h"
/*#define debug
*/
int showWhatProcessDid(char *text, int x, int y);
void doSth(void)
{
int i, j;
for(i = 0; i < 100000 ; i++)
for(j = 0; j < 500 ; j++)
;
}
int main(int argc, char **argv)
{
int rank, size, messageLength, liczbaIteracji, i;
int tag = 55;
char *bufor;
MPI_Status status;
double startTime, time;
void *sendBufor; /* bufor dla MPI_Bsend */
int sendBuforSize;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(size < 2) {
printf("ten program musi miec przydzielone co najmniej 2 procesy !\n");
MPI_Abort(MPI_COMM_WORLD, -1);
MPI_Finalize();
return -1;
}
if(argc < 3 && rank == 0) {
printf("nalezy podac parametry: [liczbaIteracji] [dlugoscMessage`a]\n");
MPI_Abort(MPI_COMM_WORLD, -1);
MPI_Finalize();
return -1;
}
liczbaIteracji = atoi(argv[1]);
if((bufor = (char *)malloc(messageLength = atoi(argv[2]))) == NULL) {
printf("za malo dostepnej pamieci aby zainicjalizowac bufor message`a !\n");
MPI_Abort(MPI_COMM_WORLD, -1);
MPI_Finalize();
return -1;
}
/* inicjalizowanie bufora dla MPI_Bsend */
MPI_Pack_size(messageLength, MPI_CHAR, MPI_COMM_WORLD, &i);
sendBuforSize = i + MPI_BSEND_OVERHEAD;
sendBufor = (void *)malloc(sendBuforSize);
MPI_Buffer_attach(sendBufor, sendBuforSize);
MPI_Barrier(MPI_COMM_WORLD); /* synchronizacja procesow */
if(rank == 0) { /**** A ****/
startTime = MPI_Wtime();
for(i = 0; i < liczbaIteracji ; i++) {
#ifdef debug
showWhatDidProcessDo("* cykl nr %d\n", i, 0);
#endif
doSth();
MPI_Bsend(bufor, messageLength, MPI_CHAR, 1, tag, MPI_COMM_WORLD);
#ifdef debug
showWhatDidProcessDo("A: nr %d wyslal do %d\n", 0, 1);
#endif
MPI_Recv(bufor, messageLength, MPI_CHAR, 1, tag, MPI_COMM_WORLD, &status);
#ifdef debug
showWhatDidProcessDo("A: nr %d odebral od %d\n", 0, 1);
#endif
}
time = MPI_Wtime() - startTime;
printf("%f\n", time);
} else if(rank == size - 1) /**** C ****/
for(i = 0; i < liczbaIteracji ; i++) {
MPI_Recv(bufor, messageLength, MPI_CHAR, size - 2, tag, MPI_COMM_WORLD, &status);
#ifdef debug
showWhatDidProcessDo("C: nr %d odebral od %d\n", rank, size - 2);
#endif
doSth();
MPI_Bsend(bufor, messageLength, MPI_CHAR, size - 2, tag, MPI_COMM_WORLD);
#ifdef debug
showWhatDidProcessDo("C: nr %d wyslal do %d\n", rank, size - 2);
#endif
}
else /**** B ****/
for(i = 0; i < liczbaIteracji ; i++) {
MPI_Recv(bufor, messageLength, MPI_CHAR, rank - 1, tag, MPI_COMM_WORLD, &status);
#ifdef debug
showWhatDidProcessDo("B: nr %d odebral od %d\n", rank, rank - 1);
#endif
doSth();
MPI_Bsend(bufor, messageLength, MPI_CHAR, rank + 1, tag, MPI_COMM_WORLD);
#ifdef debug
showWhatDidProcessDo("B: nr %d wyslal do %d\n", rank, rank + 1);
#endif
MPI_Recv(bufor, messageLength, MPI_CHAR, rank + 1, tag, MPI_COMM_WORLD, &status);
#ifdef debug
showWhatDidProcessDo("B: nr %d odebral od %d\n", rank, rank + 1);
#endif
doSth();
MPI_Bsend(bufor, messageLength, MPI_CHAR, rank - 1, tag, MPI_COMM_WORLD);
#ifdef debug
showWhatDidProcessDo("B: nr %d wyslal do %d\n", rank, rank - 1);
#endif
}
free(bufor);
MPI_Finalize();
return 0;
}
int showWhatProcessDid(char *text, int x, int y)
{
printf(text, x, y);
return 0;
}
Kod źródłowy pliku "parallel.c":
/* Program przesyla message`e pomiedzy poszczegolnymi procesami.
* Dla 3 procesow przeslanie pojedynczego message: 0 -> 1, 1 -> 2,
* 2 -> 1, 1 -> 0. Przesylanie odbywa sie potokowo - jednoczesnie,
* przesylane jest kilka message`ow.
* s1222, 2000.04.05
* Oto schemat ilustrujacy w jaki sposob przesylane sa message
* (3 procesy i 2 message - przypadek ten nie ilustruje zlozonosci
* algorytmu, ktora wystepuje dla wiekszej liczby message`ow)
*
* 0 1 2
* | | | # - message nr 1
* # | |
* # ---_ | | % - message nr 2
* % ---> # |
* % ---_ # ---_ | |
* | ---> % ---> # | C
* | % ---__--- # | z
* | # <-- --> % | a
* | _--- # _--- % | s
* x # <--- % <--- | \|/
* # _--- % |
* x % <--- | |
* % | |
* | | |
*
* Program przyjmuje parametry:
* [1] - liczba message`ow do przeslania
* [2] - liczba bajtow message`a
*/
#include <stdio.h>
#include "mpi.h"
/*#define debug
*/
/* funkcja symuluje obciazenie procesu */
void doSth(void)
{
int i, j;
for(i = 0; i < 100000 ; i++)
for(j = 0; j < 500 ; j++)
;
}
int main(int argc, char **argv)
{
int rank, size, messageLength, liczbaMessageow, i;
int tag = 55;
char *bufor;
MPI_Status status;
double startTime, time;
char strona; /* flaga - z ktorej strony odebrac message */
void *sendBufor; /* bufor dla MPI_Bsend */
int sendBuforSize;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(size < 2) {
printf("ten program musi miec przydzielone co najmniej 2 procesy !\n");
MPI_Abort(MPI_COMM_WORLD, -1);
MPI_Finalize();
return -1;
}
if(argc < 3 && rank == 0) {
printf("nalezy podac parametry: [liczbaMessage`ow] [dlugoscMessage`a]\n");
MPI_Abort(MPI_COMM_WORLD, -1);
MPI_Finalize();
return -1;
}
liczbaMessageow = atoi(argv[1]);
if((bufor = (char *)malloc(messageLength = atoi(argv[2]))) == NULL) {
printf("za malo dostepnej pamieci aby zainicjalizowac bufor message`a !\n");
MPI_Abort(MPI_COMM_WORLD, -1);
MPI_Finalize();
return -1;
}
/* inicjalizowanie bufora dla MPI_BSend */
MPI_Pack_size(messageLength, MPI_CHAR, MPI_COMM_WORLD, &i);
sendBuforSize = size * i + size * MPI_BSEND_OVERHEAD;
sendBufor = (void *)malloc(sendBuforSize);
MPI_Buffer_attach(sendBufor, sendBuforSize);
MPI_Barrier(MPI_COMM_WORLD); /* synchronizacja procesow */
if(rank == 0) { /**** A ****/
startTime = MPI_Wtime();
for(i = 0; i < (liczbaMessageow < size ? liczbaMessageow : size) ; i++) {
doSth();
MPI_Bsend(bufor, messageLength, MPI_CHAR, 1, tag, MPI_COMM_WORLD);
#ifdef debug
printf("A: nr %d wyslal do %d\n", 0, 1);
#endif
}
for(i = 0; i < liczbaMessageow ; i++) {
MPI_Recv(bufor, messageLength, MPI_CHAR, 1, tag, MPI_COMM_WORLD, &status);
#ifdef debug
printf("A: nr %d odebral od %d\n", 0, 1);
#endif
if(i < liczbaMessageow - size) { /* czy mam jeszcze wysylac paczki */
doSth();
MPI_Bsend(bufor, messageLength, MPI_CHAR, 1, tag, MPI_COMM_WORLD);
#ifdef debug
printf("A: nr %d wyslal do %d\n", 0, 1);
#endif
}
}
time = MPI_Wtime() - startTime;
printf("%f\n", time);
} else if(rank == size - 1) /**** C ****/
for(i = 0; i < liczbaMessageow ; i++) {
MPI_Recv(bufor, messageLength, MPI_CHAR, size - 2, tag, MPI_COMM_WORLD, &status);
#ifdef debug
printf("C: nr %d odebral od %d\n", rank, size - 2);
#endif
doSth();
MPI_Bsend(bufor, messageLength, MPI_CHAR, size - 2, tag, MPI_COMM_WORLD);
#ifdef debug
printf("C: nr %d wyslal do %d\n", rank, size - 2);
#endif
}
else { /**** B ****/
for(i = 0; i < (liczbaMessageow < size ? liczbaMessageow : size - rank) ; i++) {
MPI_Recv(bufor, messageLength, MPI_CHAR, rank - 1, tag, MPI_COMM_WORLD, &status);
#ifdef debug
printf("B: nr %d odebral od %d\n", rank, rank - 1);
#endif
doSth();
MPI_Send(bufor, messageLength, MPI_CHAR, rank + 1, tag, MPI_COMM_WORLD);
#ifdef debug
printf("B: nr %d wyslal do %d\n", rank, rank + 1);
#endif
}
strona = 1; /* 1 prawa, -1 lewa */
for(i = 0; i < liczbaMessageow * 2 - (liczbaMessageow <
size ? liczbaMessageow : size - rank); i++) {
if(i >= liczbaMessageow * 2 - (liczbaMessageow <
size ? 2 * liczbaMessageow : 2*(size - rank)))
strona = 1;
MPI_Recv(bufor, messageLength, MPI_CHAR, rank + strona, tag, MPI_COMM_WORLD, &status);
#ifdef debug
showWhatDidProcessDo("B: nr %d odebral od %d\n", rank, rank + strona);
#endif
doSth();
MPI_Send(bufor, messageLength, MPI_CHAR, rank + (strona == 1 ? -1 : 1),
tag, MPI_COMM_WORLD);
#ifdef debug
showWhatDidProcessDo("B: nr %d wyslal do %d\n", rank,
rank + (strona == 1 ? -1 : 1));
#endif
strona == 1 ? (strona = -1) : (strona = 1);
}
}
MPI_Buffer_detach(&sendBufor, &sendBuforSize);
free(sendBufor);
free(bufor);
MPI_Finalize();
return 0;
}
Kod źródłowy pliku "show.c":
/* Program demonstruje otwarcie okienka i kreslenie w nim.
* s1222, 2000.03.28
*/
#include <stdio.h>
#include <stdlib.h>
#include "Xlib.h"
#include "Xutil.h"
struct wezel {
int nrNode;
double serialTime;
double parallelTime;
};
int main(int argc, char **argv)
{
Display *displayHandle;
Window win;
GC gc;
int i;
FILE *plik;
char text[200], text2[20];
int liczbaPomiarow;
int nrNode;
double serialTime, parallelTime;
struct wezel pomiary[100];
double maxSpeedup;
int xOld, yOld, x, y;
const char napis[] = "SPEEDUP (czas sekwencyjny / czas rownolegly)";
if((plik = fopen("wynik.txt", "r")) == NULL ) {
printf("brak pliku wynik.txt !\n");
return -1;
}
fscanf(plik, "%s", text);
strcpy(text2, &text[6]);
liczbaPomiarow = atoi(text2);
text[6] = '\0';
if(strcmp(text, "wyniki")) {
printf("plik wynik.txt ma zly format !\n");
return -1;
}
/* laczy sie z domyslnym serwerem X */
displayHandle = XOpenDisplay((char *)NULL);
if(displayHandle == NULL) {
printf("blad otwarcia display`a\n");
exit(-1);
}
/* tworzy okienko na display`u */
win = XCreateSimpleWindow(displayHandle, RootWindow(displayHandle, 0),
0, 0, 800, 630, 2, BlackPixel(displayHandle, 0),
WhitePixel(displayHandle, 0));
gc = XCreateGC(displayHandle, win, 0, 0);
XMapWindow(displayHandle, win);
XFlush(displayHandle);
sleep(1);
XSetForeground(displayHandle, gc, BlackPixel(displayHandle, 0));
XDrawLine(displayHandle, win, gc, 50, 20, 50, 570);
XDrawLine(displayHandle, win, gc, 50, 570, 770, 570);
XDrawString(displayHandle, win, gc, 400 - 7 * 7, 610, "Liczba procesow", 15);
for(i = 0; i < strlen(napis) ; i++)
XDrawString(displayHandle, win, gc, 4,
315 - strlen(napis) * 11 / 2 + i * 11, &napis[i], 1);
XFlush(displayHandle);
for(i = 0; i < liczbaPomiarow ; i++) {
fscanf(plik, "%s", text);
strcpy(text, &text[1]);
nrNode = atoi(text);
fscanf(plik, "%s", text);
strcpy(text, &text[1]);
serialTime = atof(text);
fscanf(plik, "%s", text);
strcpy(text, &text[1]);
parallelTime = atof(text);
pomiary[i].nrNode = nrNode;
pomiary[i].serialTime = serialTime;
pomiary[i].parallelTime = parallelTime;
if(serialTime / parallelTime > maxSpeedup)
maxSpeedup = serialTime / parallelTime;
printf("node: %d, serialTime: %f, parallelTime: %f\n",
nrNode, serialTime, parallelTime);
}
xOld = 50 + 720 / (liczbaPomiarow - 1) * 0;
yOld = 570 - 550 / maxSpeedup * (pomiary[0].serialTime / pomiary[0].parallelTime);
for(i = 0; i < liczbaPomiarow ; i++) {
XDrawLine(displayHandle, win, gc, xOld, yOld,
x = 50 + 720 / (liczbaPomiarow - 1) * i,
y = 570 - 550 / maxSpeedup *
(pomiary[i].serialTime / pomiary[i].parallelTime));
xOld = x;
yOld = y;
XDrawLine(displayHandle, win, gc, 48, 570 - 550 / maxSpeedup *
(pomiary[i].serialTime / pomiary[i].parallelTime),
52, 570 - 550 / maxSpeedup *
(pomiary[i].serialTime / pomiary[i].parallelTime));
sprintf(text, "%.1f", pomiary[i].serialTime / pomiary[i].parallelTime);
XDrawString(displayHandle, win, gc, 44 - strlen(text) * 7,
570 - 550 / maxSpeedup *
(pomiary[i].serialTime / pomiary[i].parallelTime) + 4,
text, strlen(text));
XDrawLine(displayHandle, win, gc, 50 + 720 / (liczbaPomiarow - 1) * i, 568,
50 + 720 / (liczbaPomiarow - 1) * i, 572);
sprintf(text, "%d", pomiary[i].nrNode);
XDrawString(displayHandle, win, gc,
50 + 720 / (liczbaPomiarow - 1) * i - strlen(text) * 7 / 2,
586, text, strlen(text));
}
XFlush(displayHandle);
getchar();
XCloseDisplay(displayHandle);
fclose(plik);
return 0;
}





