Reputation: 143
My program start with each process doing some work, and in the end one should gather the result and compute the final result. For now, everybody send the data to the proc 0, and it is the one that does the final computational task. I would like to find a to do this on the first process that finishes its local task.
Is there a trick on finding out this proc and tell to all the other procs asynchronously? I was thinking of using asynchronous collective operation but can't find a way to do it.
Thanks, Stole
Upvotes: 2
Views: 148
Reputation: 333
As Gilles said, you can use a one sided operation (useful docs) to set a variable which will contain the rank of process which have finished first. You set the variable to -1, when a process have finished, it read that variable using one sided (first think about blocking the access of other processes to avoid races) if it is -1, the process set this variable to his rank and become the "master" if it is a number >=0 then the process become a slave (of that number).
(As gilles noted: With version >3.0 one can use MPI_Compare_and_swap to perform the Get and Put by once (which is probably faster that a Get followed by a Put))
This method works fine only if you have a real difference of execution time between processes and a small number of processes. So one should be careful when losing time on implementing such solution. If you have large load imbalance (and cant redesign the parallelization to increase load ballancing) that will make the job! Then if you targeting >10 processes, it is better to first group all processes on a nested subgroups grid. Then perform the trick at each level of groups (that avoid having 100k processes trying to read the same variable and wasting huge time!)
Here is a simple code which does it...
#include <mpi.h>
#include <thread>
#include <chrono>
#include <stdlib.h>
#include <iostream>
#include <time.h>
using namespace std;
int main(int argc, char** argv) {
MPI_Init(NULL, NULL);
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
srand (time(NULL)+rank);
int wt = rand() % 5 + 1;
cout <<"rank: "<< rank<< " sleep: "<< wt<<endl;
//here is the magic...
int * flag;
MPI_Win window;
int master;
int compare = -1;
MPI_Win_allocate(sizeof(int), sizeof(int),MPI_INFO_NULL,
MPI_COMM_WORLD, &flag, &window );
*flag = -1;
this_thread::sleep_for(chrono::seconds(wt));
MPI_Win_lock (MPI_LOCK_EXCLUSIVE, 0, 0, window);
MPI_Compare_and_swap(&rank, &compare, &master, MPI_INT, 0,0, window);
MPI_Win_unlock (0, window);
if(master == -1)
{
cout<< "rank: "<<rank<<". I am the master"<<endl;
}
else
{
cout<< "rank: "<<rank<<". I am the slave of "<<master<<endl;
}
MPI_Win_free( &window );
MPI_Finalize();
}
Outputs:
mpirun --oversubscribe -np 4 ./test
rank: 2 sleep: 4
rank: 3 sleep: 1
rank: 0 sleep: 5
rank: 1 sleep: 2
rank: 3. I am the master
rank: 1. I am the slave of 3
rank: 2. I am the slave of 3
rank: 0. I am the slave of 3
mpirun --oversubscribe -np 4 ./test
rank: 0 sleep: 2
rank: 1 sleep: 4
rank: 2 sleep: 1
rank: 3 sleep: 3
rank: 2. I am the master
rank: 0. I am the slave of 2
rank: 3. I am the slave of 2
rank: 1. I am the slave of 2
Upvotes: 1