I am trying to render a fractal calculated using MPI. I used the answer to the following question as reference: sending blocks of 2D array in C using MPI
My problem is, that merge of data via MPI_Gatherv
calculated by all the processes does not seem to work properly, because my main process always renders a black screen.
I have the following struct defined:
typedef struct Point {
float r,g,b,x,y;
} Point;
In my main I try to create an MPI_Datatype for the struct:
MPI_Datatype struct_type;
MPI_Datatype struct_members[1] = {MPI_FLOAT};
MPI_Aint offsets[1] = {0};
int struct_blengths[1] = {5};
int struct_items = 1;
MPI_Type_create_struct(struct_items, struct_blengths, offsets, struct_members, &struct_type);
MPI_Type_commit(&struct_type);
I have a global variable for the calculation result:
Point **mandelbrot;
The variable is allocated thusly before each frame is being recalculated:
if (proc_id == root) {
//Just a check if this is the first frame that is being rendered
if (s > 0) {
free(&(mandelbrot[0][0]));
free(mandelbrot);
}
s = W;
Point *p = (Point *) malloc(W * H * sizeof(Point));
mandelbrot = (Point **) malloc(W*sizeof(Point *));
for (int i = 0; i < W; i++) {
mandelbrot[i] = &(p[i*H]);
}
}
Here I try to create an array subtype using the Point
struct (following the referenced answer as best I can):
//Width of the fractal to render
W = width;
//Height of the fractal
H = height;
//Chunk of width each process is responsible for [width / number of processes]
int segmentSize = (int) W / ntasks;
MPI_Datatype type, resizedtype;
int sizes[2] = {W,H}; /* size of global array */
int subsizes[2] = {segmentSize, H}; /* size of sub-region */
int starts[2] = {0,0};
MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, struct_type, &type);
MPI_Type_create_resized(type, 0, H*sizeof(Point), &resizedtype);
MPI_Type_commit(&resizedtype);
Calculate the displacements and counts of blocks to send and allocate memory for the process' subarray:
int sendcounts[segmentSize*H];
int displs[segmentSize*H];
if (proc_id == root) {
for (int i=0; i<segmentSize*H; i++) sendcounts[i] = 1;
int disp = 0;
for (int i=0; i<segmentSize; i++) {
for (int j=0; j<H; j++) {
displs[i*H+j] = disp;
disp += 1;
}
disp += ((W/segmentSize)-1)*H;
}
}
Point *p = (Point *) malloc(segmentSize * H * sizeof(Point));
Point **segment;
segment = (Point **) malloc(segmentSize * sizeof(Point*));
for (int i = 0; i < segmentSize; i++) {
segment[i] = &(p[i*H]);
}
Following that I calculate the color of the Mandelbrot set for each point in the chunk:
int i;
float c[3], dX, dY;
for ( x = 0; x < segmentSize; x++) {
for ( y = 0; y < H; y++) {
//Iterate over the point
i = iterateMandelbrot(rM + x * dR, iM - y * dI);
// Get decimal coordinates for rendering <0,1>
dX = (x + segmentSize * proc_id) / W;
dY = y / H;
//Calculate color using Bernoulli Polynomials
makeColor(i, maxIterations, c);
segment[x][y].x = (float) dX;
segment[x][y].y = (float) dY;
segment[x][y].r = (float) c[0];
segment[x][y].g = (float) c[1];
segment[x][y].b = (float) c[2];
}
}
Lastly I try to gather the chunks into the mandelbort
variable for the root process to render:
int buffsize = (int) segmentSize * H;
MPI_Gatherv(&(segment[0][0]), W*H/(buffsize), struct_type,
&(mandelbrot[0][0]), sendcounts, displs, resizedtype,
root, MPI_COMM_WORLD);
MPI_Type_free(&resizedtype);
Ok so the problem is now that no data seems to be written into the mandelbrot
variable as my main process renders a black screen. Without using MPI the code works so the problem lies somewhere in the MPI_Gatherv
call or maybe the way I am allocating the arrays. I realize there might be some memory leak associated with the mandelbrot set or the local segment
arrays but that is not my main concern at the moment. Can you see what I am doing wrong here? Any help is appreciated!