Obliczanie całki oznaczonej, program równoległy
-- Sebastian Pawlak
Kod źródłowy pliku "makefile":
a.out: main.c mpicc main.c -I/usr/share/mpich-1.2.0/include\\ -L/usr/local/lib -L/usr/share/mpich-1.2.0/lib -lm -lmpi
Kod źródłowy pliku "main.c":
/* Program liczy calke oznaczona danej funkcji. Przedzial calkowania dzielony * jest na paczki (tak aby kazdy procesor liczyl kilka paczek - dynamiczne * obciazenie procesorow). * s1222, 2000.05.24 * * f(x)^ f(x)^ , , * | . . . . . . . | , / , * | . _.--.--. . . . | , / | , * | / . . . \. . . | , / | , * |/ . . . . .\ . . | , / | , * | . . . . . \ . | , / | , * | . . . . . . -.___ | ,,/ | , * | .p1.p2.p1.p2.p1.p2. \ |,, | | , * +--|-----------------|--------> +---|----------|-------------> * x0 x1 x <- dx -> x * Korzystam z trapezu prostokatnego */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "mpi.h" #define PACZKI_NA_PROCES 10 /* liczba paczek teoretycznie * liczona przez kazdy proces */ /* funkcja, ktora calkujemy */ double funkcja(double x) { return x; } int main(int argc, char **argv) { int rank, size, i, tag = 100 , j = 0, k = 0; MPI_Status status; MPI_Request request; double x0, x1, dx; double y0, y1; double pp; double pole = 0, poleTmp; int liczbaKrokow, nrPaczki = 0; struct { double x0, x1, dx; char z; } dane; void *sendBuffer; /* bufor dla MPI_Bsend */ int sendBufferSize; char z; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (argc != 4) { printf("nalezy podac parametry: x0 x1 dx\n"); printf(" gdzie: x0 - poczatek przedzialu calkowania\n"); printf(" x1 - koniec przedzialu calkowania\n"); printf(" dx - szerokosc podstawy trapezu\n"); MPI_Abort(MPI_COMM_WORLD, -1); } /* obsluga parametrow uzytkownika */ x0 = atof(argv[1]); if ((x1 = atof(argv[2])) <= x0) { printf("podales ujemny albo pusty przedzial !\n"); MPI_Abort(MPI_COMM_WORLD, -1); } if ((dx = atof(argv[3])) > x1 - x0) { printf("podana szerokosc podstawy trapezu wieksza niz przedzial !\n"); MPI_Abort(MPI_COMM_WORLD, -1); } /* Inicjalizowanie bufora dla MPI_Bsend */ MPI_Pack_size(1, MPI_CHAR, MPI_COMM_WORLD, &i); sendBufferSize = size * (i + MPI_BSEND_OVERHEAD); sendBuffer = (void *)malloc(sendBufferSize); MPI_Buffer_attach(sendBuffer, sendBufferSize); if (rank == 0) { /* MASTER */ dane.x1 = x0; dane.dx = dx; dane.z = '1'; while (j < (size - 1) * PACZKI_NA_PROCES || k < (size - 1) * PACZKI_NA_PROCES) { MPI_Recv(&z, 1, MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); if (z == '1' && dane.x1 < x1) { /* zatrudnij wolnego slave`a */ dane.x0 = x0 + (x1 - x0) * j / ((size - 1) * PACZKI_NA_PROCES); dane.x1 = x0 + (x1 - x0) * ++j / ((size - 1) * PACZKI_NA_PROCES); if (dane.x1 > x1) dane.x1 = x1; MPI_Send(&dane, sizeof(dane), MPI_BYTE, status.MPI_SOURCE, 0, MPI_COMM_WORLD); } else if (z == '2') { /* odbierz dane od slave`a */ MPI_Recv(&poleTmp, 1, MPI_DOUBLE, status.MPI_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); pole += poleTmp; k++; } } printf("calkowite pole pod funkcja = %f\n", pole); /* zwolnij SLAVE`ow */ dane.z = '0'; for (i = 1; i < size ; i++) MPI_Send(&dane, sizeof (dane), MPI_BYTE, i, 0, MPI_COMM_WORLD); } else { /* SLAVE */ do { MPI_Bsend("1", 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD); /* jestem wolny */ MPI_Recv(&dane, sizeof (dane), MPI_BYTE, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status); if (dane.z == '1') { pole = 0; liczbaKrokow = (dane.x1 - dane.x0) / dane.dx; y0 = funkcja(dane.x0); for (i = 0; i < liczbaKrokow ; i++) { y1 = funkcja(dane.x0 += dane.dx); pole += (y0 + y1) * dane.dx / 2; y0 = y1; } if (dane.x0 < dane.x1) pole += (funkcja(dane.x1) + y0) * (dane.x1 - dane.x0) / 2; MPI_Send("2", 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD); /* chce nadac dane */ MPI_Send(&pole, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); printf("rank: %d, przedzial: <%f,%f> dx=%f pole=%f kroki:%d nrPaczki:%d\n", rank, dane.x0, dane.x1, dane.dx, pole, liczbaKrokow, ++nrPaczki); } } while (dane.z == '1'); } MPI_Buffer_detach(&sendBuffer, &sendBufferSize); free(sendBuffer); MPI_Finalize(); return 0; }