views:

135

answers:

1

First time using MPI outside some simple practice apps, and something's not going right.

I have a class defined with the following members (methods omitted for the sake of readability and conserving screen space):

class particle
{
    public:
     double _lastUpdate;
 float _x, _y, _xvel, _yvel;
 bool _isStatic;
     bool _isForeign;
     float _size;

    private:
     int _isStaticInt;   // integer copy of _isStatic to be sent over MPI ( since there's no MPI_BOOL :C )
};

I want to send sets of particles between processes by sending the values of some key members of each particle, and replicating the others on the spot. For that purpose, I define an MPI datatype as such; as you can see, members _lastUpdate, _isStatic and _isForeign are not included:

MPI_Datatype types[] = { MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_INTEGER, MPI_FLOAT };
std::vector<int> len(6, 1);
std::vector<MPI_Aint> disp(6, 0);
particle temp;
MPI_Aint base;
MPI_Address(&temp, &base);
MPI_Address(&temp._x, &disp[0]);
MPI_Address(&temp._y, &disp[1]);
MPI_Address(&temp._xvel, &disp[2]);
MPI_Address(&temp._yvel, &disp[3]);
MPI_Address(&temp._isStaticInt, &disp[4]);
MPI_Address(&temp._size, &disp[5]);
for (int i=0; i<6; ++i)
{
 disp[i] = disp[i] - base;
}
MPI_Type_struct(6, &len[0], &disp[0], types, &_particleType);
MPI_Type_commit(&_particleType);

This is how I send the particles; 'parts' is a vector of particle* that contains pointers to the particle objects I want to send, and 'size' is parts.size().

std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base);       // datatype begins at the first selected object
for (int select = 1; select < size; ++select)
{
    MPI_Address(parts[select], &disp[select]);
    disp[select] = disp[select] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_sendType);
MPI_Type_commit(&_sendType);

MPI_Request payload_req;
MPI_Isend(parts[0], 1, _sendType, ngb, 0, _cartesian_comm, &payload_req);

Receiving happens similarly, only in this case, 'parts' is a vector of particle* that points to previously created "blank" particle objects, whose members are to be filled with the data we receive:

std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base);      // datatype begins at the first newly inserted object
for (int part = 1; part < size; ++part)
{
 MPI_Address(parts[part], &disp[part]);
 disp[part] = disp[part] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_recvType);
MPI_Type_commit(&_recvType);
MPI_Status status;
MPI_Recv(parts[0], size, _particleType, ngb, 0, _cartesian_comm, &status);

The problem is that all the received particles except the first one have the default "blank" values in their members. I wrote a small test app before that did something similar, and that worked flawlessly, although it only transmitted a few simple values. This leads me to beleive that unless there's a coding mistake I'm not noticing here (entirely possible), this sort of datatype trickery is not guaranteed to work, and the little that works does so only by accident.

Can anyone confirm/deny if this type of memory manipulation is safe and should be relied upon?

+1  A: 

Never mind, it seems that simply typing out the question made me realize what's wrong.

The receive command should be:

MPI_Recv(parts[0], 1, _recvType, ngb, 0, _cartesian_comm, &status);
suszterpatt