混合openmp mpi mandelbrot代码

时间:2015-07-02 09:16:06

标签: mpi openmp hybrid mandelbrot

我面临一个问题:香港专业教育学院完成了mandelbrot的mpi版本,它完美无缺。然后我必须使用openmp实现混合版本。我已经在循环中将openmp并行化与所有计算(在函数calculoMandelbrot中)。如果我删除omp指令(omp for parallel和omp barrier),它的工作完美(这是我的mpi实现)。应该工作,但我不能猜测我迷路的地方。

我有一个IMAGEHEIGHT * IMAGEWIDTH的图像,每个过程都成为它的一部分(例如:如果我有一个100高度的图像,4个过程,每个过程计算25行,在calculoMandelbrot函数中完成)。然后我向主人发送一条消息,其中包含计算每个过程的部分结果。

结果的ppm是一团糟。不知道为什么......任何帮助都会被贬低......

/
//  mandelbrot.c
//
//
//  The Mandelbrot calculation is to iterate the equation
//  z = z*z + c, where z and c are complex numbers, z is initially
//  zero, and c is the coordinate of the point being tested. If
//  the magnitude of z remains less than 2 for ever, then the point
//  c is in the Mandelbrot set. In this code We write out the number of iterations
//  before the magnitude of z exceeds 2, or UCHAR_MAX, whichever is
//  smaller.//
//
//

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <omp.h>
#include <math.h>


#define TAG_ENVIO 3

int IMAGEWIDTH = 600;
int IMAGEHEIGHT = 400;
int ITERATIONS = 100000;
int CHUNK = 1;
int SIZE;


void escribirfichero(char* pixels) {

    int i;
    FILE *fp;
    fp = fopen("MandelbrotSet.ppm", "w");

    if (fp == NULL) {
        perror ( "Unable to open file" );
        exit (EXIT_FAILURE);
    }

    //printf("Empezamos a escribir en el fichero");

    fprintf(fp, "P6\n# CREATOR: mandel program\n");
    fprintf(fp, "%d %d\n255\n", IMAGEWIDTH, IMAGEHEIGHT);

    for (i = 0; i < (IMAGEWIDTH*3*IMAGEHEIGHT); i++)
        fputc((char) pixels[i],fp);

    fclose(fp);
}

void calculoMandelbrot(char *destino, int iproc, int height)
{
    int posInici = iproc * height;
    int xactual, yactual;
    int posLocal = 0;
    int chunkSize = height * IMAGEWIDTH * 3;

    omp_set_dynamic(1);

    //each iteration, it calculates: newz = oldz*oldz + p, where p is the current pixel, and oldz stars at the origin
    double pr, pi;                              //real and imaginary part of the pixel p
    double newRe, newIm, oldRe, oldIm;          //real and imaginary parts of new and old z
    double zoom = 1, moveX = -0.5, moveY = 0;   //you can change these to zoom and change position

    int numcpu = omp_get_num_procs();
    omp_set_num_threads(numcpu);

    if(iproc != 0)
        destino = (char *)malloc(sizeof(char) * chunkSize);

#pragma omp parallel //shared(moveX, moveY, zoom) private(xactual, yactual, pr, pi, newRe, newIm)  if (numcpu>1)
    {
#pragma omp for schedule(dynamic) //, CHUNK
        for(yactual = posInici; yactual < posInici + height; yactual++)
        {
            for(xactual = 0; xactual < IMAGEWIDTH; xactual++)
            {
                //calculate the initial real and imaginary part of z, based on the pixel location and zoom and position values
                pr = 1.5 * (xactual - IMAGEWIDTH / 2) / (0.5 * zoom * IMAGEWIDTH) + moveX;
                pi = (yactual - IMAGEHEIGHT / 2) / (0.5 * zoom * IMAGEHEIGHT) + moveY;
                newRe = newIm = oldRe = oldIm = 0; //these should start at 0,0
                //"i" will represent the number of iterations
                int i;
                //start the iteration process
                for(i = 0; i < ITERATIONS; i++)
                {
                    //remember value of previous iteration
                    oldRe = newRe;
                    oldIm = newIm;
                    //the actual iteration, the real and imaginary part are calculated
                    newRe = oldRe * oldRe - oldIm * oldIm + pr;
                    newIm = 2 * oldRe * oldIm + pi;
                    //if the point is outside the circle with radius 2: stop
                    if((newRe * newRe + newIm * newIm) > 4) break;
                }

                if(i == ITERATIONS)
                {
                    //escribirArray(destino, posLocal, 0, 0, 0);
                    destino[posLocal] = 0;
                    destino[++posLocal] = 0;
                    destino[++posLocal] = 0;
                    ++posLocal;                     //me preparo para colocar siguiente.
                }
                else
                {
                    double z = sqrt(newRe * newRe + newIm * newIm);
                    int brightness = 256 * log2(1.75 + i - log2(log2(z))) / log2((double)ITERATIONS);

                    //escribirArray(envioArr, xactual, yactual, brightness, brightness, 255);
                    destino[posLocal] = brightness;
                    destino[++posLocal] = brightness;
                    destino[++posLocal] = 255;
                    ++posLocal;                     //me preparo para colocar siguiente
                }
            }
        }
    }
    #pragma omp barrier

    if(iproc != 0)
    {
        MPI_Send(destino, chunkSize, MPI_CHAR, 0, TAG_ENVIO, MPI_COMM_WORLD);
        free(destino);
    }
}


void stringCopy(char *pixels, char *reciboArr, int sender, int height)
{
    int posInici = sender * height * IMAGEWIDTH*3;
    int pos;

    for (pos = 0; pos < height * IMAGEWIDTH*3; pos++, posInici++) {
        pixels[posInici] = reciboArr[pos];
    }
}


int main(int argc, char** argv) {

    // mandelbrot
    char* pixels;

    // mpi
    int nproc, iproc;

    // calculos tiempo
    double begin;
    double end_calc;
    double end_total;


    if(argc >= 3)
    {
        // se supone que la línia de ejecucion sera del tipo
        // -n 4 ${workspace_loc:MPI}/Debug/MPI${build_files} 100 200
        // FALTA PROVAR EN MOORE

        IMAGEWIDTH = atoi(argv[1]);
        IMAGEHEIGHT = atoi(argv[2]);
    }

    if(argc == 4)
    {
        ITERATIONS = atoi(argv[3]);
    }

    if(argc == 5)
    {
        CHUNK = atoi(argv[4]);
    }

    SIZE = IMAGEHEIGHT * IMAGEWIDTH * 3;



    if (MPI_Init(&argc, &argv) != MPI_SUCCESS) {
        fprintf(stderr, "Error al inicializar MPI.\n");
        return 100;
    }

    begin = MPI_Wtime();

    if (MPI_Comm_size(MPI_COMM_WORLD, &nproc) != MPI_SUCCESS) {
        fprintf(stderr, "No se puede obtener el contador de procesos.\n");
        MPI_Finalize();
        return 101;
    } else if (nproc < 2) {
        fprintf(stderr, "Se necesitan almenos 2 procesos (se usan %d)\n", nproc);
        MPI_Finalize();
        return 102;
    }

    if (MPI_Comm_rank(MPI_COMM_WORLD, &iproc) != MPI_SUCCESS) {
        fprintf(stderr, "No se puede obtener el rango para el proceso.\n");
        MPI_Finalize();
        return 103;
    }

    if ((IMAGEHEIGHT % nproc) != 0)
    {
        printf("Incompatable number of processes requested\nExiting...\n");
        exit(EXIT_FAILURE);
    }


    int height = IMAGEHEIGHT/nproc;
    int chunkSize = height * IMAGEWIDTH * 3;

    if (iproc != 0) {
        char *envioArr = (char *)malloc(sizeof(char) * chunkSize);
        calculoMandelbrot(envioArr, iproc, height);
    }

    else if(iproc == 0) {
        printf("Empezando los calculos de Mandelbrot...\n");
        printf("IMAGEWIDTH %d IMAGEHEIGHT %d ITERATIONS %d num procesos %d CHUNK %d\n", IMAGEWIDTH, IMAGEHEIGHT, ITERATIONS, nproc, CHUNK);

        pixels = (char *)malloc(SIZE * sizeof(char));
        calculoMandelbrot(pixels, iproc, height);


        //inicio recibir el resto de mensajes
        char *reciboArr = (char *)malloc(sizeof(char)*chunkSize);
        int i;
        MPI_Status status;

        for (i = 1; i<nproc; i++)
        {
            MPI_Recv(reciboArr, height*IMAGEWIDTH*3, MPI_CHAR, MPI_ANY_SOURCE, TAG_ENVIO, MPI_COMM_WORLD, &status);
            stringCopy(pixels, reciboArr, status.MPI_SOURCE, height);
        }
        free(reciboArr);
        //final de recibir resto de mensajes

        end_calc = MPI_Wtime() - begin;
        printf("Tiempo en calculos: %.10lf segundos \n", end_calc);
        //MPI_Barrier(MPI_COMM_WORLD);

        //printf("Escribiendo la imagen\n");
        escribirfichero(pixels);
        end_total = MPI_Wtime() - begin;
        printf("Tiempo en total: %.10lf segundos \n", end_total);

        free(pixels);
    }

    MPI_Finalize();
    return 0;
}

1 个答案:

答案 0 :(得分:0)

如果有人遇到相同或类似的问题,解决方案是:

起点如问题所述,mpi版本工作正常(没有openmp条款)。在im debuggint的情况下,变量posLocal从0到180000(图像宽度* 3 *高度)变化: - IMAGEWIDTH值600 - 身高为100(IMAGEHEIGHT 400分为4个过程)

因此,当我介绍openmp条款时,并不确切地知道为什么使用open mp屏障,posLocal最终值被卡在175000或接近。 经过多次测试,我已经能够将posLocal带到180000,使得destino和posLocal共享,并且xactual和yactual是私有的。也许其他组合也可以,但这对我有用。

感谢coincoin的兴趣。

#pragma omp parallel shared ( destino) private ( xactual, yactual)
{
#pragma omp parallel for schedule(static)
        for(yactual = posInici; yactual < posInici + height; yactual++)
        {
            for(xactual = 0; xactual < IMAGEWIDTH; xactual++)
            {
                //calculate the initial real and imaginary part of z, based on the pixel location and zoom and position values
                pr = 1.5 * (xactual - IMAGEWIDTH / 2) / (0.5 * zoom * IMAGEWIDTH) + moveX;
                pi = (yactual - IMAGEHEIGHT / 2) / (0.5 * zoom * IMAGEHEIGHT) + moveY;
                newRe = newIm = oldRe = oldIm = 0; //these should start at 0,0
                //"i" will represent the number of iterations
                int i;
                //start the iteration process
                for(i = 0; i < ITERATIONS; i++)
                {
                    //remember value of previous iteration
                    oldRe = newRe;
                    oldIm = newIm;
                    //the actual iteration, the real and imaginary part are calculated
                    newRe = oldRe * oldRe - oldIm * oldIm + pr;
                    newIm = 2 * oldRe * oldIm + pi;
                    //if the point is outside the circle with radius 2: stop
                    if((newRe * newRe + newIm * newIm) > 4) break;
                }


                //printf("Antes zona paralela: %d process Thread: %d \n", iproc, numcpu);
                if(i == ITERATIONS)
                {
                    //escribirArray(destino, posLocal, 0, 0, 0);
                    destino[posLocal] = 0;
                    destino[++posLocal] = 0;
                    destino[++posLocal] = 0;
                    ++posLocal;                     //me preparo para colocar siguiente.
                }
                else
                {
                    double z = sqrt(newRe * newRe + newIm * newIm);
                    int brightness = 256 * log2(1.75 + i - log2(log2(z))) / log2((double)ITERATIONS);

                    //escribirArray(envioArr, xactual, yactual, brightness, brightness, 255);
                    destino[posLocal] = brightness;
                    destino[++posLocal] = brightness;
                    destino[++posLocal] = 255;
                    ++posLocal;                     //me preparo para colocar siguiente
                }
            }

        }

}

    #pragma omp barrier
    printf("Despuess zona paralela: %d process Thread: %d y posLocal %d \n", iproc, numcpu, posLocal);
    if(iproc != 0)
    {
        MPI_Send(destino, chunkSize, MPI_CHAR, 0, TAG_ENVIO, MPI_COMM_WORLD);
        printf("Estoy enviando en el proceso: %d y la posLocal es %d \n", iproc, posLocal);

        free(destino);
    }