2015-07-02 3 views
1

Im сталкивается с одной проблемой: ive сделал версию mpi mandelbrot и работает отлично. Затем мне нужно реализовать гибридную версию с помощью openmp. Ive ставит openmp-распараллеливание в цикле со всеми вычислениями (внутри функции calculoMandelbrot). Если я удалю команду omp (omp для параллельного и omp-барьера), она отлично работает (это была моя реализация mpi). Должен работать, но я не могу догадаться, где я заблудился.Hybrid openmp mpi mandelbrot code

У меня есть изображение IMAGEHEIGHT * IMAGEWIDTH, и каждый процесс обрабатывает его часть (например: если у меня есть изображение 100 высоты и 4 процесса, каждый процесс вычисляет 25 строк, выполненных в функции calculoMandelbrot). Затем я отправляю сообщение для освоения результатов расчета его части каждого процесса.

ppm, что приводит к беспорядку. Не знаю, почему ... любая помощь будет apreciated ...

/ 
// 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; 
} 
+0

Можете ли вы рассказать нам, как ppm при использовании одного процесса mpi с одним из двух потоков OpenMP? (избавьтесь от if numcpu> 1, чтобы увидеть, может ли серийная версия работать). – coincoin

+0

Спасибо, здесь вы идете http://imagebin.ca/v/27F20XTw8jpx, вам нужно скачать и открыть, поскольку imagebin может показывать файлы изображений ppm. Единственное, что вместо зеленого должно быть синим ... главное, что мандельброт прекрасно работает, это черная зона. Версия mpi работала для меня идеально, если вы удаляете предложения omp в calculoMandelbrot ... есть только два или три (множество num cpu, omp parallel for и барьер .... Надеюсь, это поможет –

+0

, к сожалению, я не могу получить доступ к вашей ссылке, Я один из них. Можете ли вы описать, что работает? Для одного процесса mpi и двух потоков OpenMP? Для одного процесса mpi и одного потока OpenMP (избавиться от предложения if numcpu> 1)? – coincoin

ответ

0

Просто если кто-то возглавляет такую ​​же или подобную проблему, решение было:

Дело начале был, как говорится в вопросе, что Версия mpi работала нормально (без предложений openmp). Переменная posLocal изменяется от 0 до 180000 (ImageWidth * 3 * высота) в случае им debuggint: - ImageWidth значения 600 - высота 100 (был ImageHeight 400 разделена между 4 процесса)

Поэтому, когда я ввести в OpenMP предложения не знают точно, почему althoug с использованием открытого барьера mp, окончательное значение posLocal было зафиксировано на уровне 175000 или около. После многих тестов я смог, чтобы posLocal прибыл в 180000, делая destino и posLocal shared, и xactual и yactual private. Возможно, другие комбинации работают, но это работает для меня.

Благодаря совпадению интересов.

#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); 
    } 
+0

Обязательно принимайте свой собственный ответ на свой вопрос. – NoseKnowsAll

Смежные вопросы