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;
}
Можете ли вы рассказать нам, как ppm при использовании одного процесса mpi с одним из двух потоков OpenMP? (избавьтесь от if numcpu> 1, чтобы увидеть, может ли серийная версия работать). – coincoin
Спасибо, здесь вы идете http://imagebin.ca/v/27F20XTw8jpx, вам нужно скачать и открыть, поскольку imagebin может показывать файлы изображений ppm. Единственное, что вместо зеленого должно быть синим ... главное, что мандельброт прекрасно работает, это черная зона. Версия mpi работала для меня идеально, если вы удаляете предложения omp в calculoMandelbrot ... есть только два или три (множество num cpu, omp parallel for и барьер .... Надеюсь, это поможет –
, к сожалению, я не могу получить доступ к вашей ссылке, Я один из них. Можете ли вы описать, что работает? Для одного процесса mpi и двух потоков OpenMP? Для одного процесса mpi и одного потока OpenMP (избавиться от предложения if numcpu> 1)? – coincoin