Putting everything in namespace eo::mpi
This commit is contained in:
parent
b9a2246f82
commit
b291e56e03
12 changed files with 492 additions and 466 deletions
|
|
@ -13,7 +13,7 @@ SET(EOMPI_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
|
||||||
SET(LIBRARY_OUTPUT_PATH ${EOMPI_LIB_OUTPUT_PATH})
|
SET(LIBRARY_OUTPUT_PATH ${EOMPI_LIB_OUTPUT_PATH})
|
||||||
|
|
||||||
SET(EOMPI_SOURCES
|
SET(EOMPI_SOURCES
|
||||||
eompi.cpp
|
eoMpi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_LIBRARY(eompi STATIC ${EOMPI_SOURCES})
|
ADD_LIBRARY(eompi STATIC ${EOMPI_SOURCES})
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
# ifndef __MPI_NODE_H__
|
|
||||||
# define __MPI_NODE_H__
|
|
||||||
|
|
||||||
# include <boost/mpi.hpp>
|
|
||||||
namespace mpi = boost::mpi;
|
|
||||||
|
|
||||||
class MpiNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
static void init( int argc, char** argv )
|
|
||||||
{
|
|
||||||
static mpi::environment env( argc, argv );
|
|
||||||
}
|
|
||||||
|
|
||||||
static mpi::communicator& comm()
|
|
||||||
{
|
|
||||||
return _comm;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static mpi::communicator _comm;
|
|
||||||
};
|
|
||||||
|
|
||||||
# endif // __MPI_NODE_H__
|
|
||||||
|
|
@ -1,207 +0,0 @@
|
||||||
# ifndef __ASSIGNMENT_ALGORITHM_H__
|
|
||||||
# define __ASSIGNMENT_ALGORITHM_H__
|
|
||||||
|
|
||||||
# include <vector>
|
|
||||||
# include "MpiNode.h"
|
|
||||||
|
|
||||||
namespace eo
|
|
||||||
{
|
|
||||||
const int REST_OF_THE_WORLD = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AssignmentAlgorithm
|
|
||||||
{
|
|
||||||
virtual int get( ) = 0;
|
|
||||||
virtual int availableWorkers( ) = 0;
|
|
||||||
virtual void confirm( int wrkRank ) = 0;
|
|
||||||
virtual std::vector<int> idles( ) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
DynamicAssignmentAlgorithm( )
|
|
||||||
{
|
|
||||||
for(int i = 1; i < MpiNode::comm().size(); ++i)
|
|
||||||
{
|
|
||||||
availableWrk.push_back( i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicAssignmentAlgorithm( int unique )
|
|
||||||
{
|
|
||||||
availableWrk.push_back( unique );
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicAssignmentAlgorithm( const std::vector<int> & workers )
|
|
||||||
{
|
|
||||||
availableWrk = workers;
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicAssignmentAlgorithm( int first, int last )
|
|
||||||
{
|
|
||||||
if( last == eo::REST_OF_THE_WORLD )
|
|
||||||
{
|
|
||||||
last = MpiNode::comm().size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( int i = first; i <= last; ++i)
|
|
||||||
{
|
|
||||||
availableWrk.push_back( i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int get( )
|
|
||||||
{
|
|
||||||
int assignee = -1;
|
|
||||||
if (! availableWrk.empty() )
|
|
||||||
{
|
|
||||||
assignee = availableWrk.back();
|
|
||||||
availableWrk.pop_back();
|
|
||||||
}
|
|
||||||
return assignee;
|
|
||||||
}
|
|
||||||
|
|
||||||
int availableWorkers()
|
|
||||||
{
|
|
||||||
return availableWrk.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void confirm( int rank )
|
|
||||||
{
|
|
||||||
availableWrk.push_back( rank );
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> idles( )
|
|
||||||
{
|
|
||||||
return availableWrk;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::vector< int > availableWrk;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StaticAssignmentAlgorithm : public AssignmentAlgorithm
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StaticAssignmentAlgorithm( std::vector<int>& workers, int runs )
|
|
||||||
{
|
|
||||||
init( workers, runs );
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticAssignmentAlgorithm( int first, int last, int runs )
|
|
||||||
{
|
|
||||||
std::vector<int> workers;
|
|
||||||
|
|
||||||
if( last == eo::REST_OF_THE_WORLD )
|
|
||||||
{
|
|
||||||
last = MpiNode::comm().size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = first; i <= last; ++i)
|
|
||||||
{
|
|
||||||
workers.push_back( i );
|
|
||||||
}
|
|
||||||
init( workers, runs );
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticAssignmentAlgorithm( int runs )
|
|
||||||
{
|
|
||||||
std::vector<int> workers;
|
|
||||||
for(int i = 1; i < MpiNode::comm().size(); ++i)
|
|
||||||
{
|
|
||||||
workers.push_back( i );
|
|
||||||
}
|
|
||||||
init( workers, runs );
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticAssignmentAlgorithm( int unique, int runs )
|
|
||||||
{
|
|
||||||
std::vector<int> workers;
|
|
||||||
workers.push_back( unique );
|
|
||||||
init( workers, runs );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void init( std::vector<int> & workers, int runs )
|
|
||||||
{
|
|
||||||
unsigned int nbWorkers = workers.size();
|
|
||||||
freeWorkers = nbWorkers;
|
|
||||||
attributions.reserve( nbWorkers );
|
|
||||||
busy.resize( nbWorkers, false );
|
|
||||||
|
|
||||||
// Let be the euclidean division of runs by nbWorkers :
|
|
||||||
// runs == q * nbWorkers + r, 0 <= r < nbWorkers
|
|
||||||
// This one liner affects q requests to each worker
|
|
||||||
for (unsigned int i = 0; i < nbWorkers; attributions[i++] = runs / nbWorkers) ;
|
|
||||||
// The first line computes r and the one liner affects the remaining
|
|
||||||
// r requests to workers, in ascending order
|
|
||||||
unsigned int diff = runs - (runs / nbWorkers) * nbWorkers;
|
|
||||||
for (unsigned int i = 0; i < diff; ++attributions[i++]);
|
|
||||||
|
|
||||||
realRank = workers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
int get( )
|
|
||||||
{
|
|
||||||
int assignee = -1;
|
|
||||||
for( unsigned i = 0; i < busy.size(); ++i )
|
|
||||||
{
|
|
||||||
if( !busy[i] && attributions[i] > 0 )
|
|
||||||
{
|
|
||||||
busy[i] = true;
|
|
||||||
--freeWorkers;
|
|
||||||
assignee = realRank[ i ];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return assignee;
|
|
||||||
}
|
|
||||||
|
|
||||||
int availableWorkers( )
|
|
||||||
{
|
|
||||||
return freeWorkers;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> idles()
|
|
||||||
{
|
|
||||||
std::vector<int> ret;
|
|
||||||
for(unsigned int i = 0; i < busy.size(); ++i)
|
|
||||||
{
|
|
||||||
if( !busy[i] )
|
|
||||||
{
|
|
||||||
eo::log << "Idle : " << realRank[i] <<
|
|
||||||
" / attributions : " << attributions[i] << std::endl;
|
|
||||||
ret.push_back( realRank[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void confirm( int rank )
|
|
||||||
{
|
|
||||||
int i = -1;
|
|
||||||
for( int j = 0; j < realRank.size(); ++j )
|
|
||||||
{
|
|
||||||
if( realRank[j] == rank )
|
|
||||||
{
|
|
||||||
i = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--attributions[ i ];
|
|
||||||
busy[ i ] = false;
|
|
||||||
++freeWorkers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<int> attributions;
|
|
||||||
std::vector<int> realRank;
|
|
||||||
std::vector<bool> busy;
|
|
||||||
unsigned int freeWorkers;
|
|
||||||
};
|
|
||||||
|
|
||||||
# endif // __ASSIGNMENT_ALGORITHM_H__
|
|
||||||
11
eo/src/mpi/eoMpi.cpp
Normal file
11
eo/src/mpi/eoMpi.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# include "eoMpi.h"
|
||||||
|
|
||||||
|
// MpiNode* MpiNodeStore::singleton;
|
||||||
|
namespace eo
|
||||||
|
{
|
||||||
|
namespace mpi
|
||||||
|
{
|
||||||
|
bmpi::communicator Node::_comm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
132
eo/src/mpi/eoMpi.h
Normal file
132
eo/src/mpi/eoMpi.h
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
# ifndef __EO_MPI_H__
|
||||||
|
# define __EO_MPI_H__
|
||||||
|
|
||||||
|
# include <vector>
|
||||||
|
# include <map>
|
||||||
|
# include <utils/eoLogger.h>
|
||||||
|
|
||||||
|
# include "eoMpiNode.h"
|
||||||
|
# include "eoMpiAssignmentAlgorithm.h"
|
||||||
|
// TODO TODOB comment!
|
||||||
|
|
||||||
|
namespace eo
|
||||||
|
{
|
||||||
|
namespace mpi
|
||||||
|
{
|
||||||
|
namespace Channel
|
||||||
|
{
|
||||||
|
const int Commands = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Message
|
||||||
|
{
|
||||||
|
const int Continue = 0;
|
||||||
|
const int Finish = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Job
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Job( AssignmentAlgorithm& _algo, int _masterRank ) :
|
||||||
|
assignmentAlgo( _algo ),
|
||||||
|
comm( Node::comm() ),
|
||||||
|
masterRank( _masterRank )
|
||||||
|
{
|
||||||
|
_isMaster = Node::comm().rank() == _masterRank;
|
||||||
|
}
|
||||||
|
|
||||||
|
// master
|
||||||
|
virtual bool isFinished() = 0;
|
||||||
|
virtual void sendTask( int wrkRank ) = 0;
|
||||||
|
virtual void handleResponse( int wrkRank ) = 0;
|
||||||
|
// worker
|
||||||
|
virtual void processTask( ) = 0;
|
||||||
|
|
||||||
|
void master( )
|
||||||
|
{
|
||||||
|
int totalWorkers = assignmentAlgo.availableWorkers();
|
||||||
|
eo::log << eo::debug;
|
||||||
|
eo::log << "[M" << comm.rank() << "] Have " << totalWorkers << " workers." << std::endl;
|
||||||
|
|
||||||
|
while( ! isFinished() )
|
||||||
|
{
|
||||||
|
int assignee = assignmentAlgo.get( );
|
||||||
|
while( assignee <= 0 )
|
||||||
|
{
|
||||||
|
eo::log << "[M" << comm.rank() << "] Waitin' for node..." << std::endl;
|
||||||
|
bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag );
|
||||||
|
int wrkRank = status.source();
|
||||||
|
eo::log << "[M" << comm.rank() << "] Node " << wrkRank << " just terminated." << std::endl;
|
||||||
|
handleResponse( wrkRank );
|
||||||
|
assignmentAlgo.confirm( wrkRank );
|
||||||
|
assignee = assignmentAlgo.get( );
|
||||||
|
}
|
||||||
|
eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl;
|
||||||
|
comm.send( assignee, Channel::Commands, Message::Continue );
|
||||||
|
sendTask( assignee );
|
||||||
|
}
|
||||||
|
|
||||||
|
eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl;
|
||||||
|
// frees all the idle workers
|
||||||
|
std::vector<int> idles = assignmentAlgo.idles();
|
||||||
|
for(unsigned int i = 0; i < idles.size(); ++i)
|
||||||
|
{
|
||||||
|
comm.send( idles[i], Channel::Commands, Message::Finish );
|
||||||
|
}
|
||||||
|
|
||||||
|
eo::log << "[M" << comm.rank() << "] Waits for all responses." << std::endl;
|
||||||
|
// wait for all responses
|
||||||
|
while( assignmentAlgo.availableWorkers() != totalWorkers )
|
||||||
|
{
|
||||||
|
bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag );
|
||||||
|
int wrkRank = status.source();
|
||||||
|
handleResponse( wrkRank );
|
||||||
|
comm.send( wrkRank, Channel::Commands, Message::Finish );
|
||||||
|
assignmentAlgo.confirm( wrkRank );
|
||||||
|
}
|
||||||
|
|
||||||
|
eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worker( )
|
||||||
|
{
|
||||||
|
int order;
|
||||||
|
eo::log << eo::debug;
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl;
|
||||||
|
comm.recv( masterRank, Channel::Commands, order );
|
||||||
|
if ( order == Message::Finish )
|
||||||
|
{
|
||||||
|
eo::log << "[W" << comm.rank() << "] Leaving worker task." << std::endl;
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
eo::log << "[W" << comm.rank() << "] Processing task..." << std::endl;
|
||||||
|
processTask( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run( )
|
||||||
|
{
|
||||||
|
( _isMaster ) ? master( ) : worker( );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMaster( )
|
||||||
|
{
|
||||||
|
return _isMaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AssignmentAlgorithm& assignmentAlgo;
|
||||||
|
bmpi::communicator& comm;
|
||||||
|
int masterRank;
|
||||||
|
bool _isMaster;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // __EO_MPI_H__
|
||||||
|
|
||||||
207
eo/src/mpi/eoMpiAssignmentAlgorithm.h
Normal file
207
eo/src/mpi/eoMpiAssignmentAlgorithm.h
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
# ifndef __MPI_ASSIGNMENT_ALGORITHM_H__
|
||||||
|
# define __MPI_ASSIGNMENT_ALGORITHM_H__
|
||||||
|
|
||||||
|
# include <vector>
|
||||||
|
# include "eoMpiNode.h"
|
||||||
|
|
||||||
|
namespace eo
|
||||||
|
{
|
||||||
|
namespace mpi
|
||||||
|
{
|
||||||
|
const int REST_OF_THE_WORLD = -1;
|
||||||
|
|
||||||
|
struct AssignmentAlgorithm
|
||||||
|
{
|
||||||
|
virtual int get( ) = 0;
|
||||||
|
virtual int availableWorkers( ) = 0;
|
||||||
|
virtual void confirm( int wrkRank ) = 0;
|
||||||
|
virtual std::vector<int> idles( ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
DynamicAssignmentAlgorithm( )
|
||||||
|
{
|
||||||
|
for(int i = 1; i < Node::comm().size(); ++i)
|
||||||
|
{
|
||||||
|
availableWrk.push_back( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicAssignmentAlgorithm( int unique )
|
||||||
|
{
|
||||||
|
availableWrk.push_back( unique );
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicAssignmentAlgorithm( const std::vector<int> & workers )
|
||||||
|
{
|
||||||
|
availableWrk = workers;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicAssignmentAlgorithm( int first, int last )
|
||||||
|
{
|
||||||
|
if( last == REST_OF_THE_WORLD )
|
||||||
|
{
|
||||||
|
last = Node::comm().size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = first; i <= last; ++i)
|
||||||
|
{
|
||||||
|
availableWrk.push_back( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int get( )
|
||||||
|
{
|
||||||
|
int assignee = -1;
|
||||||
|
if (! availableWrk.empty() )
|
||||||
|
{
|
||||||
|
assignee = availableWrk.back();
|
||||||
|
availableWrk.pop_back();
|
||||||
|
}
|
||||||
|
return assignee;
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableWorkers()
|
||||||
|
{
|
||||||
|
return availableWrk.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void confirm( int rank )
|
||||||
|
{
|
||||||
|
availableWrk.push_back( rank );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> idles( )
|
||||||
|
{
|
||||||
|
return availableWrk;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector< int > availableWrk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StaticAssignmentAlgorithm : public AssignmentAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StaticAssignmentAlgorithm( std::vector<int>& workers, int runs )
|
||||||
|
{
|
||||||
|
init( workers, runs );
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticAssignmentAlgorithm( int first, int last, int runs )
|
||||||
|
{
|
||||||
|
std::vector<int> workers;
|
||||||
|
|
||||||
|
if( last == REST_OF_THE_WORLD )
|
||||||
|
{
|
||||||
|
last = Node::comm().size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = first; i <= last; ++i)
|
||||||
|
{
|
||||||
|
workers.push_back( i );
|
||||||
|
}
|
||||||
|
init( workers, runs );
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticAssignmentAlgorithm( int runs )
|
||||||
|
{
|
||||||
|
std::vector<int> workers;
|
||||||
|
for(int i = 1; i < Node::comm().size(); ++i)
|
||||||
|
{
|
||||||
|
workers.push_back( i );
|
||||||
|
}
|
||||||
|
init( workers, runs );
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticAssignmentAlgorithm( int unique, int runs )
|
||||||
|
{
|
||||||
|
std::vector<int> workers;
|
||||||
|
workers.push_back( unique );
|
||||||
|
init( workers, runs );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init( std::vector<int> & workers, int runs )
|
||||||
|
{
|
||||||
|
unsigned int nbWorkers = workers.size();
|
||||||
|
freeWorkers = nbWorkers;
|
||||||
|
attributions.reserve( nbWorkers );
|
||||||
|
busy.resize( nbWorkers, false );
|
||||||
|
|
||||||
|
// Let be the euclidean division of runs by nbWorkers :
|
||||||
|
// runs == q * nbWorkers + r, 0 <= r < nbWorkers
|
||||||
|
// This one liner affects q requests to each worker
|
||||||
|
for (unsigned int i = 0; i < nbWorkers; attributions[i++] = runs / nbWorkers) ;
|
||||||
|
// The first line computes r and the one liner affects the remaining
|
||||||
|
// r requests to workers, in ascending order
|
||||||
|
unsigned int diff = runs - (runs / nbWorkers) * nbWorkers;
|
||||||
|
for (unsigned int i = 0; i < diff; ++attributions[i++]);
|
||||||
|
|
||||||
|
realRank = workers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int get( )
|
||||||
|
{
|
||||||
|
int assignee = -1;
|
||||||
|
for( unsigned i = 0; i < busy.size(); ++i )
|
||||||
|
{
|
||||||
|
if( !busy[i] && attributions[i] > 0 )
|
||||||
|
{
|
||||||
|
busy[i] = true;
|
||||||
|
--freeWorkers;
|
||||||
|
assignee = realRank[ i ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assignee;
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableWorkers( )
|
||||||
|
{
|
||||||
|
return freeWorkers;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> idles()
|
||||||
|
{
|
||||||
|
std::vector<int> ret;
|
||||||
|
for(unsigned int i = 0; i < busy.size(); ++i)
|
||||||
|
{
|
||||||
|
if( !busy[i] )
|
||||||
|
{
|
||||||
|
ret.push_back( realRank[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void confirm( int rank )
|
||||||
|
{
|
||||||
|
int i = -1;
|
||||||
|
for( unsigned int j = 0; j < realRank.size(); ++j )
|
||||||
|
{
|
||||||
|
if( realRank[j] == rank )
|
||||||
|
{
|
||||||
|
i = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--attributions[ i ];
|
||||||
|
busy[ i ] = false;
|
||||||
|
++freeWorkers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<int> attributions;
|
||||||
|
std::vector<int> realRank;
|
||||||
|
std::vector<bool> busy;
|
||||||
|
unsigned int freeWorkers;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif // __MPI_ASSIGNMENT_ALGORITHM_H__
|
||||||
31
eo/src/mpi/eoMpiNode.h
Normal file
31
eo/src/mpi/eoMpiNode.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# ifndef __MPI_NODE_H__
|
||||||
|
# define __MPI_NODE_H__
|
||||||
|
|
||||||
|
# include <boost/mpi.hpp>
|
||||||
|
namespace bmpi = boost::mpi;
|
||||||
|
|
||||||
|
namespace eo
|
||||||
|
{
|
||||||
|
namespace mpi
|
||||||
|
{
|
||||||
|
class Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void init( int argc, char** argv )
|
||||||
|
{
|
||||||
|
static bmpi::environment env( argc, argv );
|
||||||
|
}
|
||||||
|
|
||||||
|
static bmpi::communicator& comm()
|
||||||
|
{
|
||||||
|
return _comm;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static bmpi::communicator _comm;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif // __MPI_NODE_H__
|
||||||
|
|
||||||
|
|
@ -1,102 +1,107 @@
|
||||||
# ifndef __EO_PARALLEL_APPLY_H__
|
# ifndef __EO_PARALLEL_APPLY_H__
|
||||||
# define __EO_PARALLEL_APPLY_H__
|
# define __EO_PARALLEL_APPLY_H__
|
||||||
|
|
||||||
# include "eompi.h"
|
# include "eoMpi.h"
|
||||||
|
|
||||||
# include <eoFunctor.h>
|
# include <eoFunctor.h>
|
||||||
# include <vector>
|
# include <vector>
|
||||||
|
|
||||||
template< typename EOT >
|
namespace eo
|
||||||
class ParallelApply : public MpiJob
|
|
||||||
{
|
{
|
||||||
private:
|
namespace mpi
|
||||||
struct ParallelApplyAssignment
|
{
|
||||||
|
template< typename EOT >
|
||||||
|
class ParallelApply : public Job
|
||||||
{
|
{
|
||||||
int index;
|
private:
|
||||||
int size;
|
struct ParallelApplyAssignment
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int size;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
|
||||||
|
ParallelApply(
|
||||||
|
eoUF<EOT&, void> & _proc,
|
||||||
|
std::vector<EOT>& _pop,
|
||||||
|
AssignmentAlgorithm & algo,
|
||||||
|
int _masterRank,
|
||||||
|
int _packetSize = 1
|
||||||
|
) :
|
||||||
|
Job( algo, _masterRank ),
|
||||||
|
func( _proc ),
|
||||||
|
index( 0 ),
|
||||||
|
size( _pop.size() ),
|
||||||
|
data( _pop ),
|
||||||
|
packetSize( _packetSize )
|
||||||
|
{
|
||||||
|
if ( _packetSize <= 0 )
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Packet size should not be negative.");
|
||||||
|
}
|
||||||
|
tempArray = new EOT[ packetSize ];
|
||||||
|
}
|
||||||
|
|
||||||
|
~ParallelApply()
|
||||||
|
{
|
||||||
|
delete [] tempArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void sendTask( int wrkRank )
|
||||||
|
{
|
||||||
|
int futureIndex;
|
||||||
|
|
||||||
|
if( index + packetSize < size )
|
||||||
|
{
|
||||||
|
futureIndex = index + packetSize;
|
||||||
|
} else {
|
||||||
|
futureIndex = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sentSize = futureIndex - index ;
|
||||||
|
comm.send( wrkRank, 1, sentSize );
|
||||||
|
|
||||||
|
assignedTasks[ wrkRank ].index = index;
|
||||||
|
assignedTasks[ wrkRank ].size = sentSize;
|
||||||
|
|
||||||
|
comm.send( wrkRank, 1, &data[ index ] , sentSize );
|
||||||
|
index = futureIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handleResponse( int wrkRank )
|
||||||
|
{
|
||||||
|
comm.recv( wrkRank, 1, &data[ assignedTasks[wrkRank].index ], assignedTasks[wrkRank].size );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void processTask( )
|
||||||
|
{
|
||||||
|
int recvSize;
|
||||||
|
comm.recv( masterRank, 1, recvSize );
|
||||||
|
comm.recv( masterRank, 1, tempArray, recvSize );
|
||||||
|
for( int i = 0; i < recvSize ; ++i )
|
||||||
|
{
|
||||||
|
func( tempArray[ i ] );
|
||||||
|
}
|
||||||
|
comm.send( masterRank, 1, tempArray, recvSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFinished()
|
||||||
|
{
|
||||||
|
return index == size;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<EOT> & data;
|
||||||
|
eoUF<EOT&, void>& func;
|
||||||
|
int index;
|
||||||
|
int size;
|
||||||
|
std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks;
|
||||||
|
|
||||||
|
int packetSize;
|
||||||
|
EOT* tempArray;
|
||||||
};
|
};
|
||||||
public:
|
}
|
||||||
|
}
|
||||||
ParallelApply(
|
|
||||||
eoUF<EOT&, void> & _proc,
|
|
||||||
std::vector<EOT>& _pop,
|
|
||||||
AssignmentAlgorithm & algo,
|
|
||||||
int _masterRank,
|
|
||||||
int _packetSize = 1
|
|
||||||
) :
|
|
||||||
MpiJob( algo, _masterRank ),
|
|
||||||
func( _proc ),
|
|
||||||
index( 0 ),
|
|
||||||
size( _pop.size() ),
|
|
||||||
data( _pop ),
|
|
||||||
packetSize( _packetSize )
|
|
||||||
{
|
|
||||||
if ( _packetSize <= 0 )
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Packet size should not be negative.");
|
|
||||||
}
|
|
||||||
tempArray = new EOT[ packetSize ];
|
|
||||||
}
|
|
||||||
|
|
||||||
~ParallelApply()
|
|
||||||
{
|
|
||||||
delete [] tempArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void sendTask( int wrkRank )
|
|
||||||
{
|
|
||||||
int futureIndex;
|
|
||||||
|
|
||||||
if( index + packetSize < size )
|
|
||||||
{
|
|
||||||
futureIndex = index + packetSize;
|
|
||||||
} else {
|
|
||||||
futureIndex = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sentSize = futureIndex - index ;
|
|
||||||
comm.send( wrkRank, 1, sentSize );
|
|
||||||
|
|
||||||
assignedTasks[ wrkRank ].index = index;
|
|
||||||
assignedTasks[ wrkRank ].size = sentSize;
|
|
||||||
|
|
||||||
comm.send( wrkRank, 1, &data[ index ] , sentSize );
|
|
||||||
index = futureIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void handleResponse( int wrkRank )
|
|
||||||
{
|
|
||||||
comm.recv( wrkRank, 1, &data[ assignedTasks[wrkRank].index ], assignedTasks[wrkRank].size );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void processTask( )
|
|
||||||
{
|
|
||||||
int recvSize;
|
|
||||||
comm.recv( masterRank, 1, recvSize );
|
|
||||||
comm.recv( masterRank, 1, tempArray, recvSize );
|
|
||||||
for( int i = 0; i < recvSize ; ++i )
|
|
||||||
{
|
|
||||||
func( tempArray[ i ] );
|
|
||||||
}
|
|
||||||
comm.send( masterRank, 1, tempArray, recvSize );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFinished()
|
|
||||||
{
|
|
||||||
return index == size;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::vector<EOT> & data;
|
|
||||||
eoUF<EOT&, void>& func;
|
|
||||||
int index;
|
|
||||||
int size;
|
|
||||||
std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks;
|
|
||||||
|
|
||||||
int packetSize;
|
|
||||||
EOT* tempArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
# endif // __EO_PARALLEL_APPLY_H__
|
# endif // __EO_PARALLEL_APPLY_H__
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# include "eompi.h"
|
|
||||||
|
|
||||||
// MpiNode* MpiNodeStore::singleton;
|
|
||||||
mpi::communicator MpiNode::_comm;
|
|
||||||
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
# ifndef __EO_MPI_H__
|
|
||||||
# define __EO_MPI_H__
|
|
||||||
|
|
||||||
# include <vector>
|
|
||||||
# include <map>
|
|
||||||
# include <utils/eoLogger.h>
|
|
||||||
|
|
||||||
# include "MpiNode.h"
|
|
||||||
# include "assignmentAlgorithm.h"
|
|
||||||
// TODO TODOB comment!
|
|
||||||
|
|
||||||
namespace EoMpi
|
|
||||||
{
|
|
||||||
namespace Channel
|
|
||||||
{
|
|
||||||
const int Commands = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Message
|
|
||||||
{
|
|
||||||
const int Continue = 0;
|
|
||||||
const int Finish = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class MpiJob
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
MpiJob( AssignmentAlgorithm& _algo, int _masterRank ) :
|
|
||||||
assignmentAlgo( _algo ),
|
|
||||||
comm( MpiNode::comm() ),
|
|
||||||
masterRank( _masterRank )
|
|
||||||
{
|
|
||||||
_isMaster = MpiNode::comm().rank() == _masterRank;
|
|
||||||
}
|
|
||||||
|
|
||||||
// master
|
|
||||||
virtual bool isFinished() = 0;
|
|
||||||
virtual void sendTask( int wrkRank ) = 0;
|
|
||||||
virtual void handleResponse( int wrkRank ) = 0;
|
|
||||||
// worker
|
|
||||||
virtual void processTask( ) = 0;
|
|
||||||
|
|
||||||
void master( )
|
|
||||||
{
|
|
||||||
int totalWorkers = assignmentAlgo.availableWorkers();
|
|
||||||
eo::log << eo::debug;
|
|
||||||
eo::log << "[M] Have " << totalWorkers << " workers." << std::endl;
|
|
||||||
|
|
||||||
while( ! isFinished() )
|
|
||||||
{
|
|
||||||
int assignee = assignmentAlgo.get( );
|
|
||||||
while( assignee <= 0 )
|
|
||||||
{
|
|
||||||
eo::log << "[M] Waitin' for node..." << std::endl;
|
|
||||||
mpi::status status = comm.probe( mpi::any_source, mpi::any_tag );
|
|
||||||
int wrkRank = status.source();
|
|
||||||
eo::log << "[M] Node " << wrkRank << " just terminated." << std::endl;
|
|
||||||
handleResponse( wrkRank );
|
|
||||||
assignmentAlgo.confirm( wrkRank );
|
|
||||||
assignee = assignmentAlgo.get( );
|
|
||||||
}
|
|
||||||
eo::log << "[M] Assignee : " << assignee << std::endl;
|
|
||||||
comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue );
|
|
||||||
sendTask( assignee );
|
|
||||||
}
|
|
||||||
|
|
||||||
eo::log << "[M] Frees all the idle." << std::endl;
|
|
||||||
// frees all the idle workers
|
|
||||||
std::vector<int> idles = assignmentAlgo.idles();
|
|
||||||
for(unsigned int i = 0; i < idles.size(); ++i)
|
|
||||||
{
|
|
||||||
comm.send( idles[i], EoMpi::Channel::Commands, EoMpi::Message::Finish );
|
|
||||||
}
|
|
||||||
|
|
||||||
eo::log << "[M] Waits for all responses." << std::endl;
|
|
||||||
// wait for all responses
|
|
||||||
while( assignmentAlgo.availableWorkers() != totalWorkers )
|
|
||||||
{
|
|
||||||
mpi::status status = comm.probe( mpi::any_source, mpi::any_tag );
|
|
||||||
int wrkRank = status.source();
|
|
||||||
handleResponse( wrkRank );
|
|
||||||
comm.send( wrkRank, EoMpi::Channel::Commands, EoMpi::Message::Finish );
|
|
||||||
assignmentAlgo.confirm( wrkRank );
|
|
||||||
}
|
|
||||||
|
|
||||||
eo::log << "[M] Leaving master task." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void worker( )
|
|
||||||
{
|
|
||||||
int order;
|
|
||||||
eo::log << eo::debug;
|
|
||||||
while( true )
|
|
||||||
{
|
|
||||||
eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl;
|
|
||||||
comm.recv( masterRank, EoMpi::Channel::Commands, order );
|
|
||||||
if ( order == EoMpi::Message::Finish )
|
|
||||||
{
|
|
||||||
eo::log << "[W" << comm.rank() << "] Leaving worker task." << std::endl;
|
|
||||||
return;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
eo::log << "[W" << comm.rank() << "] Processing task..." << std::endl;
|
|
||||||
processTask( );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void run( )
|
|
||||||
{
|
|
||||||
( _isMaster ) ? master( ) : worker( );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isMaster( )
|
|
||||||
{
|
|
||||||
return _isMaster;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
AssignmentAlgorithm& assignmentAlgo;
|
|
||||||
mpi::communicator& comm;
|
|
||||||
int masterRank;
|
|
||||||
bool _isMaster;
|
|
||||||
};
|
|
||||||
# endif // __EO_MPI_H__
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# include <mpi/eompi.h>
|
# include <mpi/eoMpi.h>
|
||||||
# include <mpi/eoParallelApply.h>
|
# include <mpi/eoParallelApply.h>
|
||||||
|
|
||||||
# include <boost/serialization/vector.hpp>
|
# include <boost/serialization/vector.hpp>
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
# include <vector>
|
# include <vector>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
using namespace eo::mpi;
|
||||||
|
|
||||||
// Role map
|
// Role map
|
||||||
// 0 : general master
|
// 0 : general master
|
||||||
// 1, 2 : worker of general job, master of subjob
|
// 1, 2 : worker of general job, master of subjob
|
||||||
|
|
@ -38,7 +40,7 @@ struct Work: public eoUF< vector<int>&, void >
|
||||||
void operator() ( vector<int>& v )
|
void operator() ( vector<int>& v )
|
||||||
{
|
{
|
||||||
cout << "Work phase..." << endl;
|
cout << "Work phase..." << endl;
|
||||||
subtask( v, MpiNode::comm().rank() );
|
subtask( v, Node::comm().rank() );
|
||||||
for( int i = 0; i < v.size(); ++i )
|
for( int i = 0; i < v.size(); ++i )
|
||||||
{
|
{
|
||||||
v[i] *= 2;
|
v[i] *= 2;
|
||||||
|
|
@ -49,7 +51,7 @@ struct Work: public eoUF< vector<int>&, void >
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
// eo::log << eo::setlevel( eo::debug );
|
// eo::log << eo::setlevel( eo::debug );
|
||||||
MpiNode::init( argc, argv );
|
Node::init( argc, argv );
|
||||||
vector<int> v;
|
vector<int> v;
|
||||||
|
|
||||||
v.push_back(1);
|
v.push_back(1);
|
||||||
|
|
@ -62,7 +64,7 @@ int main(int argc, char** argv)
|
||||||
metaV.push_back( v );
|
metaV.push_back( v );
|
||||||
metaV.push_back( v );
|
metaV.push_back( v );
|
||||||
|
|
||||||
switch( MpiNode::comm().rank() )
|
switch( Node::comm().rank() )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
|
|
@ -88,7 +90,7 @@ int main(int argc, char** argv)
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// all the other nodes are sub workers
|
// all the other nodes are sub workers
|
||||||
int rank = MpiNode::comm().rank();
|
int rank = Node::comm().rank();
|
||||||
if ( rank == 3 or rank == 5 )
|
if ( rank == 3 or rank == 5 )
|
||||||
{
|
{
|
||||||
subtask( v, 1 );
|
subtask( v, 1 );
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# include <mpi/eompi.h>
|
# include <mpi/eoMpi.h>
|
||||||
# include <mpi/eoParallelApply.h>
|
# include <mpi/eoParallelApply.h>
|
||||||
|
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
# include <vector>
|
# include <vector>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
using namespace eo::mpi;
|
||||||
|
|
||||||
struct plusOne : public eoUF< int&, void >
|
struct plusOne : public eoUF< int&, void >
|
||||||
{
|
{
|
||||||
void operator() ( int & x )
|
void operator() ( int & x )
|
||||||
|
|
@ -27,7 +29,7 @@ int main(int argc, char** argv)
|
||||||
// eo::log << eo::setlevel( eo::debug );
|
// eo::log << eo::setlevel( eo::debug );
|
||||||
bool launchOnlyOne = false; // Set this to true if you wanna launch only the first test.
|
bool launchOnlyOne = false; // Set this to true if you wanna launch only the first test.
|
||||||
|
|
||||||
MpiNode::init( argc, argv );
|
Node::init( argc, argv );
|
||||||
|
|
||||||
srand( time(0) );
|
srand( time(0) );
|
||||||
vector<int> v;
|
vector<int> v;
|
||||||
|
|
@ -43,10 +45,10 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
vector< Test > tests;
|
vector< Test > tests;
|
||||||
|
|
||||||
const int ALL = MpiNode::comm().size();
|
const int ALL = Node::comm().size();
|
||||||
|
|
||||||
Test tIntervalStatic;
|
Test tIntervalStatic;
|
||||||
tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD, v.size() );
|
tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, REST_OF_THE_WORLD, v.size() );
|
||||||
tIntervalStatic.description = "Correct static assignment with interval.";
|
tIntervalStatic.description = "Correct static assignment with interval.";
|
||||||
tIntervalStatic.requiredNodesNumber = ALL;
|
tIntervalStatic.requiredNodesNumber = ALL;
|
||||||
tests.push_back( tIntervalStatic );
|
tests.push_back( tIntervalStatic );
|
||||||
|
|
@ -81,7 +83,7 @@ int main(int argc, char** argv)
|
||||||
tests.push_back( tVectorStatic );
|
tests.push_back( tVectorStatic );
|
||||||
|
|
||||||
Test tIntervalDynamic;
|
Test tIntervalDynamic;
|
||||||
tIntervalDynamic.assign = new DynamicAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD );
|
tIntervalDynamic.assign = new DynamicAssignmentAlgorithm( 1, REST_OF_THE_WORLD );
|
||||||
tIntervalDynamic.description = "Dynamic assignment with interval.";
|
tIntervalDynamic.description = "Dynamic assignment with interval.";
|
||||||
tIntervalDynamic.requiredNodesNumber = ALL;
|
tIntervalDynamic.requiredNodesNumber = ALL;
|
||||||
tests.push_back( tIntervalDynamic );
|
tests.push_back( tIntervalDynamic );
|
||||||
|
|
@ -114,7 +116,7 @@ int main(int argc, char** argv)
|
||||||
cout << "Test : " << tests[i].description << endl;
|
cout << "Test : " << tests[i].description << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( MpiNode::comm().rank() < tests[i].requiredNodesNumber )
|
if( Node::comm().rank() < tests[i].requiredNodesNumber )
|
||||||
{
|
{
|
||||||
job.run();
|
job.run();
|
||||||
}
|
}
|
||||||
|
|
@ -134,7 +136,7 @@ int main(int argc, char** argv)
|
||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
MpiNode::comm().barrier();
|
Node::comm().barrier();
|
||||||
|
|
||||||
delete tests[i].assign;
|
delete tests[i].assign;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue