I'm trying to implement Matrix-Vector multiplication using MPI (i.e. nxn
matrix multiplied by nx1
vector).
Originally, I decided to use multiple MPI_Bcast
calls (before I noticed MPI_AllGather
...) and I stumbled upon some strange behaviour. Apparently, data can be received no matter what rank is passed to MPI_Bcast
call.
Part of the code used (the functions are called right after each other, so sending broadcast is before receiving broadcasts). Prints are just for debugging purposes, where I know testing data is of length 2:
class Processor
{
public:
Processor(int rank, int communicatorSize);
private:
void broadcastOwnVectorToOtherRanks();
void receiveBroadcastsFromOtherRanks();
//...
int ownRank;
int communicatorSize;
std::vector<int> ownVectorPart;
std::vector<int> totalVector;
//...
};
void Processor::broadcastOwnVectorToOtherRanks()
{
//ownVectorPart is correctly filled before this function call
std::printf("Own data in vector %d %d\n", ownVectorPart[0], ownVectorPart[1]);
MPI_Bcast(ownVectorPart.data(), ownVectorPart.size(), MPI_INT, ownRank, MPI_COMM_WORLD);
}
void Processor::receiveBroadcastsFromOtherCommunicators()
{
for (int rank = 0; rank < communicatorSize; ++rank)
{
if (rank == ownRank)
{
totalVector.insert(totalVector.end(), ownVectorPart.begin(), ownVectorPart.end());
}
else
{
std::vector<int> buffer(ownVectorPart.size());
MPI_Bcast(buffer.data(), ownVectorPart.size(), MPI_INT, rank, MPI_COMM_WORLD);
std::printf("Received from process with rank %d: %d %d\n", rank, buffer[0], buffer[1]);
totalVector.insert(totalVector.end(), buffer.begin(), buffer.end());
}
}
}
Outcome (sorted by rank):
[0] Own data in vector 0 1
[0] Received from communicator 1: 6 7
[0] Received from communicator 2: 4 5
[0] Received from communicator 3: 2 3
[1] Own data in vector 2 3
[1] Received from communicator 0: 0 1
[1] Received from communicator 2: 4 5
[1] Received from communicator 3: 6 7
[2] Own data in vector 4 5
[2] Received from communicator 0: 0 1
[2] Received from communicator 1: 2 3
[2] Received from communicator 3: 6 7
[3] Own data in vector 6 7
[3] Received from communicator 0: 4 5
[3] Received from communicator 1: 2 3
[3] Received from communicator 2: 0 1
As you can see, in process with rank 0 and 3 data received is different than data sent. For example, process with rank 0
received data from rank 3
, even though it is expecting data from process 1
.
It seems to me that rank is disregarded when receiving broadcast data, and MPI assigns data as it comes, whether it was from expected rank or not.
Why does MPI_Bcast
receive data from process with rank 3
, when rank passed as argument is 1
? Is calling MPI_Bcast
multiple times at the same time an undefined behaviour? Or is there a bug in my code?
MPI_COMM_WORLD
. All the ranks of the communicator must invokeMPI_Bcast()
with the same root rank, and I suspect that is not the case in your program, and hence the undefined behavior. Please upload a minimal reproducible example if you need more help. - Gilles GouaillardetbroadcastOwnVectorToOtherCommunicators()
), secondly every rank tries to receive broadcasts from all other ranks (receiveBroadcastsFromOtherCommunicators()
). Multiple brodcasts are being exchanged at the same time. I'll edit the question to try and clear it up. - Yksisarvinen3
will send one broadcast and receive total of 3 broadcasts from0
,1
and2
. But the received data is mixed up, as if therank
argument inMPI_Bcast
was ignored. - YksisarvinenMPI_Bcast()
. All the ranks of the communicator must invoke the collective subroutine with the sameroot
argument. I can only confirm it if you edit your question with a minimal reproducible example - Gilles Gouaillardetmain()
? PBS file forqsub
? I could refactor it to avoid classes to try to simplify it? I'm trying to explain that all processes will callMPI_Bcast
with the givenroot
eventually. All processes will at some point call it withroot == 0
, withroot == 1
, etc. If this is not allowed, that's all I'm asking about. - Yksisarvinen