0

I'm a newby in MPI and I'm trying to learn how to use MPI_Type_create_subarray in order to apply it in my projects. I've spent lots of time searching for a tutorial which could fits my needing, but without success.

So I've tried to generalize the concept in How to use MPI_Type_create_subarray to 3D arrays, but something is still missing.

In particular my code return a Segmentation Fault error or shows wrong data when I try to see results. I can't understand where I made a mistake

This is my code:

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

void printarr(int ***data, int nx, int ny, int nz, char *str);
int ***allocarray(int nx, int ny, int nz);

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

/* array sizes */
const int bigsize =10;
const int subsize_x =2;      const int subsize_y =2;     const int subsize_z =2;

/* communications parameters */
const int sender  =0;
const int receiver=1;
const int ourtag  =2;

int rank, size;

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

if (size < receiver+1) {
    if (rank == 0)
        fprintf(stderr,"%s: Needs at least %d  processors.\n", argv[0], receiver+1);
    MPI_Finalize();
    return 1;
}


MPI_Datatype mysubarray;

int starts[3] = {0,0,0};
int subsizes[3]  = {subsize_x,subsize_y,subsize_z};
int bigsizes[3]  = {bigsize, bigsize, 3};
MPI_Type_create_subarray(3, bigsizes, subsizes, starts, MPI_ORDER_C, MPI_INT, &mysubarray);
MPI_Type_commit(&mysubarray);

if (rank == sender) {
    int ***bigarray = allocarray(bigsize,bigsize,3);
    for (int k=0; k<3; k++)
        for (int j=0; j<bigsize; j++)
            for(int i=0; i< bigsize; i++) {
                bigarray[k][j][i] = k*(bigsize*bigsize)+j*bigsize+i;
            }

    printarr(bigarray, bigsize, bigsize, 3, " Sender: Big array ");

    MPI_Send(&(bigarray[0][0][0]), 1, mysubarray, receiver, ourtag, MPI_COMM_WORLD);
    MPI_Type_free(&mysubarray);

    free(bigarray);

} else if (rank == receiver) {

    int ***subarray = allocarray(subsize_x,subsize_y,subsize_z);
    MPI_Recv(&(subarray[0][0][0]), subsizes[0]*subsizes[1]*subsizes[2], MPI_INT, sender, ourtag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

    printarr(subarray, subsize_x, subsize_y, subsize_z, " Receiver: Subarray -- after receive");

    free(subarray);
}

MPI_Finalize();
return 0;
}

void printarr(int ***data, int nx, int ny, int nz, char *str) {
printf("-- %s --\n", str);
for(int k=0; k<nz; k++) {
    printf("\n\n-----%d------\n",k);
    for (int j=0; j<ny;j++) {
        for (int i=0; i<nx; i++) {
            printf("%3d ", data[k][j][i]);
        }
    printf("\n");
    }
}
}

int ***allocarray(int nx, int ny, int nz) {

int*** arr = (int***)malloc(sizeof(int**)*nz);
for(int k = 0; k < nz; k++) {
    arr[k]= (int**)malloc(sizeof(int*)*ny);
    for(int j = 0; j< ny; j++){
        arr[k][j] = (int*)malloc(sizeof(int)*nx);
        for(int i = 0; i < nx; i++){
            arr[k][j][i] = 0;
        }
    }
}
return arr;
}
Mirco
  • 165
  • 2
  • 13
  • What you call a 3D-array in fact is one 1D-array of `nz` `int**` elements plus `nz` 1D-arrays of `ny` `int*` elements plus `nz*ny` `int` arrays of `nx` `int` elements. All in all `1+nz+nz*ny` 1D arrays, each being an *isolated* single chunk of memory on its own, as opposed to a real 3D-array which would be one array, that is *one chunk of continuous* memory. – alk Jan 26 '19 at 12:45
  • Ok, I've understood my fault. Anyway the `bigarray` of my application (the real ones, not the one in this example) is `256*512*1024*2 double` entries wide, so it's mandatory for me to allocate it dynamically. Can you suggest me a declaration which could fits my needing? Or another way to scatter the data properly among all my processors ? – Mirco Jan 26 '19 at 13:26
  • Understand the difference between your `allocarray` and analogue function given by the [example you linked](https://stackoverflow.com/q/13345147/694576). The example in fact allocates ***one*** chunk of memory holding *all* `int`s: `int *data = malloc(n*n*sizeof(int));` – alk Jan 26 '19 at 13:32
  • "*`256*512*1024*2`*" a 4D-array? – alk Jan 26 '19 at 13:34
  • @alk Thank you for the explanation, anyway the `2` is to account the fact that are `complex` numbers. I must use it because, later in my code, I employ a library which can handle complex just in this way – Mirco Jan 26 '19 at 13:50
  • You are aware that C knows data type `_Complex`, although optional. (http://port70.net/~nsz/c/c11/n1570.html#6.2.5p11) – alk Jan 26 '19 at 13:51
  • So I think that is impossible to use `MPI_Type_create_subarray` to do what I want, am I right? I should move the question to "How can I scatter chunks of 3D array, declared as a 1D array?" – Mirco Jan 26 '19 at 13:56
  • You very well can allocate all in one chunk: `int * pall = malloc(256*512*1024*2 * sizeof *pall);` Just you need to add some pointer-arrays and set its elements in a smart way/manner/order to emulate the 4D-effect. – alk Jan 26 '19 at 13:59
  • Best start with small numbers (3*5*7*2 for example) and a piece of paper. :-) – alk Jan 26 '19 at 14:01

0 Answers0