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;
}
w3cw3c
automatyka przemysłowa