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;
}





