Dear OpenMPI community,

Here's a little puzzle for the Christmas holidays (although I would really appreciate a quick solution!).

I'm stuck with the following relatively basic problem: given a local nloc x m matrix X_p in column-major ordering on each MPI process p, perform a single MPI_Gather operation to construct the matrix
X_0
X_1
...

X_nproc

again, in col-major ordering. My approach is to use MPI_Type_vector to define an stype and an rtype, where stype has stride nloc, and rtype has stride nproc*nloc. The observation is that there is an unexpected displacement of (m-1)*n*p in the result array for the part arriving from process p.

The MFE code is attached, and I use OpenMPI 4.0.5 with GCC 11.2 (although other versions and even distributions seem to display the same behavior). Example (nloc=3, nproc=3, m=2, with some additional columns printed for the sake of demonstration):


> mpicxx -o matrix_gather matrix_gather.cpp
mpirun -np 3 ./matrix_gather

v_loc on P0: 3x2
0 9
1 10
2 11

v_loc on P1: 3x2
3 12
4 13
5 14

v_loc on P2: 3x2
6 15
7 16
8 17

v_glob on P0: 9x4
0 9 0 0
1 10 0 0
2 11 0 0
0 3 12 0
0 4 13 0
0 5 14 0
0 0 6 15
0 0 7 16
0 0 8 17

Any ideas?

Thanks,

Jonas


--
*J. Thies*
Assistant Professor

TU Delft
Faculty Electrical Engineering, Mathematics and Computer Science
Institute of Applied Mathematics and High Performance Computing Center
Mekelweg 4
2628 CD Delft

T +31 15 27 XXXX
*j.th...@tudelft.nl*
#include <mpi.h>
#include <iostream>
#include <sstream>
#include <string>

void print(std::string label, int rank, int nloc, int m, int* array)
{
  std::ostringstream oss;
  oss << label << " on P"<<rank<<": "<< nloc << "x" << m << std::endl;

  for (int i=0; i<nloc; i++)
  {
    for (int j=0; j<m; j++)
    {
      oss << array[j*nloc+i] << " ";
    }
    oss << std::endl;
  }
  std::cout << oss.str()<<std::endl;
}

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

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

int nloc=3;
int n=nloc*nproc;
int m=2;

int *v_loc = new int[nloc*m+1000];
int *v_glob = new int[n*m+1000];

for (int j=0; j<m; j++)
for (int i=0; i<nloc; i++)
v_loc[j*nloc+i]=j*n + rank*nloc + i;

for (int r=0; r<nproc; r++)
{
  if (rank==r) print("v_loc", rank, nloc, m, v_loc);
  std::cout << std::flush;
  MPI_Barrier(MPI_COMM_WORLD);
}

MPI_Datatype stype, rtype;

// this data typre represents the local nloc x m matrix,
// which is column-major and has stride nloc.
MPI_Type_vector(m,nloc,nloc,MPI_INT,&stype);
MPI_Type_commit(&stype);

// this represents a block of size nloc x m within a col-major
// matrix of size n x m, hence the stride is n.
MPI_Type_vector(m,nloc,n,MPI_INT,&rtype);
MPI_Type_commit(&rtype);

// these two result in the same thing:
//MPI_Allgather(v_loc,nloc*m,MPI_INT,v_glob,1,rtype,MPI_COMM_WORLD);
MPI_Allgather(v_loc,1,stype,v_glob,1,rtype,MPI_COMM_WORLD);

// note: print an additional column to show the displacement error we get:
if (!rank) print("v_glob", rank, n, m+nproc-1, v_glob);

MPI_Type_free(&stype);
MPI_Type_free(&rtype);

delete [] v_loc;
delete [] v_glob;

MPI_Finalize();
}

Reply via email to