Included MPI tests into compilation, if WITH_MPI is defined.

This commit is contained in:
Benjamin Bouvier 2012-07-13 16:47:28 +02:00
commit d2816d530a
6 changed files with 73 additions and 2 deletions

View file

@ -14,12 +14,23 @@ INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/contrib)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/contrib/MGE)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
IF(WITH_MPI)
INCLUDE_DIRECTORIES(${BOOST_DIR}/include)
INCLUDE_DIRECTORIES(${MPI_DIR}/include)
ENDIF()
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
IF(WITH_MPI)
LINK_DIRECTORIES(${BOOST_DIR}/lib)
LINK_DIRECTORIES(${MPI_DIR}/lib)
SET(CMAKE_CXX_COMPILER "${MPI_DIR}/bin/mpicxx")
ENDIF()
######################################################################################
### 3) Define your targets and link the librairies
######################################################################################
@ -65,8 +76,8 @@ SET (TEST_LIST
t-eoExtendedVelocity
t-eoLogger
t-eoIQRStat
t-eoParallel
t-openmp
#t-eoParallel
#t-openmp
#t-eoDualFitness
t-eoParser
)

View file

@ -0,0 +1,55 @@
###############################################################################
##
## CMakeLists file for eo/test/mpi
##
###############################################################################
######################################################################################
### 1) Include the sources
######################################################################################
MESSAGE("EO SOURCE DIR: ${EO_SOURCE_DIR}")
MESSAGE("OMPI: ${MPI_DIR}")
MESSAGE("BOOST: ${BOOST_DIR}")
INCLUDE_DIRECTORIES(${MPI_DIR}/include)
INCLUDE_DIRECTORIES(${BOOST_DIR}/include)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
LINK_DIRECTORIES(${MPI_DIR}/lib)
LINK_DIRECTORIES(${BOOST_DIR}/lib)
######################################################################################
### 3) Define your targets and link the librairies
######################################################################################
SET (TEST_LIST
t-mpi-parallelApply
t-mpi-wrapper
t-mpi-multipleRoles
t-mpi-eval
)
FOREACH (test ${TEST_LIST})
SET ("T_${test}_SOURCES" "${test}.cpp")
ENDFOREACH (test)
SET(CMAKE_CXX_COMPILER "${MPI_DIR}/bin/mpicxx")
ADD_DEFINITIONS(-DWITH_MPI)
IF(ENABLE_CMAKE_TESTING)
FOREACH (test ${TEST_LIST})
ADD_EXECUTABLE(${test} ${T_${test}_SOURCES})
ADD_TEST(${test} ${test})
TARGET_LINK_LIBRARIES(${test} boost_mpi boost_serialization eoutils eompi eoserial eo)
INSTALL(TARGETS ${test} RUNTIME DESTINATION share/eo/test COMPONENT test)
ENDFOREACH (test)
ENDIF()
######################################################################################

168
eo/test/mpi/t-mpi-eval.cpp Normal file
View file

@ -0,0 +1,168 @@
//-----------------------------------------------------------------------------
// t-eoMpiParallel.cpp
//-----------------------------------------------------------------------------
#include <eo>
#include <eoPopEvalFunc.h>
#include <es/make_real.h>
// #include <apply.h>
#include "../real_value.h"
#include <mpi/eoMpi.h>
#include <boost/mpi.hpp>
#include <vector>
using namespace std;
//-----------------------------------------------------------------------------
class eoRealSerializable : public eoReal< eoMinimizingFitness >, public eoserial::Persistent
{
public:
eoRealSerializable(unsigned size = 0, double value = 0.0):
eoReal<eoMinimizingFitness>(size, value) {}
eoserial::Object* pack() const
{
eoserial::Object* obj = new eoserial::Object;
obj->add( "array",
eoserial::makeArray< vector<double>, eoserial::MakeAlgorithm >
( *this )
);
return obj;
}
void unpack( const eoserial::Object* obj )
{
eoserial::unpackArray< vector<double>, eoserial::Array::UnpackAlgorithm >
( *obj, "array", *this );
}
// Gives access to boost serialization
friend class boost::serialization::access;
/**
* Serializes the decomposition in a boost archive (useful for boost::mpi)
*/
template <class Archive>
void save( Archive & ar, const unsigned int version ) const
{
std::stringstream ss;
printOn( ss );
std::string asStr = ss.str();
ar & asStr;
(void) version; // avoid compilation warning
}
/**
* Deserializes the decomposition from a boost archive (useful for boost:mpi)
*/
template <class Archive>
void load( Archive & ar, const unsigned int version )
{
std::string asStr;
ar & asStr;
std::stringstream ss;
ss << asStr;
readFrom( ss );
(void) version; // avoid compilation warning
}
// Indicates that boost save and load operations are not the same.
BOOST_SERIALIZATION_SPLIT_MEMBER()
};
typedef eoRealSerializable EOT;
struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply<EOT>
{
CatBestAnswers()
{
best.fitness( 1000000000. );
}
using eo::mpi::HandleResponseParallelApply<EOT>::_wrapped;
using eo::mpi::HandleResponseParallelApply<EOT>::d;
void operator()(int wrkRank)
{
int index = d->assignedTasks[wrkRank].index;
int size = d->assignedTasks[wrkRank].size;
(*_wrapped)( wrkRank );
for(int i = index; i < index+size; ++i)
{
if( best.fitness() < d->data()[ i ].fitness() )
{
eo::log << eo::quiet << "Better solution found:" << d->data()[i].fitness() << std::endl;
best = d->data()[ i ];
}
}
}
protected:
EOT best;
};
int main(int ac, char** av)
{
eo::mpi::Node::init( ac, av );
eo::log << eo::setlevel( eo::quiet );
eoParser parser(ac, av);
unsigned int popSize = parser.getORcreateParam((unsigned int)100, "popSize", "Population Size", 'P', "Evolution Engine").value();
unsigned int dimSize = parser.getORcreateParam((unsigned int)10, "dimSize", "Dimension Size", 'd', "Evolution Engine").value();
uint32_t seedParam = parser.getORcreateParam((uint32_t)0, "seed", "Random number seed", 0).value();
if (seedParam == 0) { seedParam = time(0); }
make_parallel(parser);
make_help(parser);
rng.reseed( seedParam );
eoUniformGenerator< double > gen(-5, 5);
eoInitFixedLength< EOT > init( dimSize, gen );
eoEvalFuncPtr< EOT, double, const std::vector< double >& > mainEval( real_value );
eoEvalFuncCounter< EOT > eval( mainEval );
int rank = eo::mpi::Node::comm().rank();
eo::mpi::DynamicAssignmentAlgorithm assign;
if( rank == eo::mpi::DEFAULT_MASTER )
{
eoPop< EOT > pop( popSize, init );
eo::log << "Size of population : " << popSize << std::endl;
eo::mpi::ParallelApplyStore< EOT > store( eval, eo::mpi::DEFAULT_MASTER );
store.wrapHandleResponse( new CatBestAnswers );
eoParallelPopLoopEval< EOT > popEval( assign, eo::mpi::DEFAULT_MASTER, &store );
eo::log << eo::quiet << "Before first evaluation." << std::endl;
popEval( pop, pop );
eo::log << eo::quiet << "After first evaluation." << std::endl;
pop = eoPop< EOT >( popSize, init );
popEval( pop, pop );
eo::log << eo::quiet << "After second evaluation." << std::endl;
eo::log << eo::quiet << "DONE!" << std::endl;
} else
{
eoPop< EOT > pop( popSize, init );
eoParallelPopLoopEval< EOT > popEval( assign, eo::mpi::DEFAULT_MASTER, eval );
popEval( pop, pop );
}
return 0;
}
//-----------------------------------------------------------------------------

View file

@ -0,0 +1,113 @@
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include <boost/serialization/vector.hpp>
# include <iostream>
# include <vector>
using namespace std;
using namespace eo::mpi;
// Role map
// 0 : general master
// 1, 2 : worker of general job, master of subjob
// 3 to 7 : workers of subjob
struct SubWork: public eoUF< int&, void >
{
void operator() ( int & x )
{
cout << "Subwork phase." << endl;
++x;
}
};
void subtask( vector<int>& v, int rank )
{
vector<int> workers;
workers.push_back( rank + 2 );
workers.push_back( rank + 4 );
DynamicAssignmentAlgorithm algo( workers );
SubWork sw;
ParallelApplyStore<int> store( sw, rank );
store.data( v );
ParallelApply<int> job( algo, rank, store );
job.run();
EmptyJob stop( algo, rank );
}
struct Work: public eoUF< vector<int>&, void >
{
void operator() ( vector<int>& v )
{
cout << "Work phase..." << endl;
subtask( v, Node::comm().rank() );
for( int i = 0; i < v.size(); ++i )
{
v[i] *= 2;
}
}
};
int main(int argc, char** argv)
{
// eo::log << eo::setlevel( eo::debug );
Node::init( argc, argv );
vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(3);
v.push_back(7);
v.push_back(42);
vector< vector<int> > metaV;
metaV.push_back( v );
metaV.push_back( v );
switch( Node::comm().rank() )
{
case 0:
case 1:
case 2:
{
Work w;
DynamicAssignmentAlgorithm algo( 1, 2 );
ParallelApplyStore< vector<int> > store( w, 0 );
store.data( metaV );
ParallelApply< vector<int> > job( algo, 0, store );
job.run();
if( job.isMaster() )
{
EmptyJob stop( algo, 0 );
v = metaV[0];
cout << "Results : " << endl;
for(int i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
}
}
break;
default:
{
// all the other nodes are sub workers
int rank = Node::comm().rank();
if ( rank == 3 or rank == 5 )
{
subtask( v, 1 );
} else {
subtask( v, 2 );
}
}
break;
}
return 0;
}

View file

@ -0,0 +1,150 @@
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include <iostream>
# include <vector>
using namespace std;
using namespace eo::mpi;
struct plusOne : public eoUF< int&, void >
{
void operator() ( int & x )
{
++x;
}
};
struct Test
{
AssignmentAlgorithm * assign;
string description;
int requiredNodesNumber; // nb : chosen nodes ranks must be sequential
};
// These tests require at least 3 processes to be launched.
int main(int argc, char** argv)
{
// eo::log << eo::setlevel( eo::debug );
eo::log << eo::setlevel( eo::quiet );
bool launchOnlyOne = false ; // Set this to true if you wanna launch only the first test.
Node::init( argc, argv );
srand( time(0) );
vector<int> v;
for( int i = 0; i < 1000; ++i )
{
v.push_back( rand() );
}
int offset = 0;
vector<int> originalV = v;
plusOne plusOneInstance;
vector< Test > tests;
const int ALL = Node::comm().size();
Test tIntervalStatic;
tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, REST_OF_THE_WORLD, v.size() );
tIntervalStatic.description = "Correct static assignment with interval.";
tIntervalStatic.requiredNodesNumber = ALL;
tests.push_back( tIntervalStatic );
if( !launchOnlyOne )
{
Test tWorldStatic;
tWorldStatic.assign = new StaticAssignmentAlgorithm( v.size() );
tWorldStatic.description = "Correct static assignment with whole world as workers.";
tWorldStatic.requiredNodesNumber = ALL;
tests.push_back( tWorldStatic );
Test tStaticOverload;
tStaticOverload.assign = new StaticAssignmentAlgorithm( v.size()+100 );
tStaticOverload.description = "Static assignment with too many runs.";
tStaticOverload.requiredNodesNumber = ALL;
tests.push_back( tStaticOverload );
Test tUniqueStatic;
tUniqueStatic.assign = new StaticAssignmentAlgorithm( 1, v.size() );
tUniqueStatic.description = "Correct static assignment with unique worker.";
tUniqueStatic.requiredNodesNumber = 2;
tests.push_back( tUniqueStatic );
Test tVectorStatic;
vector<int> workers;
workers.push_back( 1 );
workers.push_back( 2 );
tVectorStatic.assign = new StaticAssignmentAlgorithm( workers, v.size() );
tVectorStatic.description = "Correct static assignment with precise workers specified.";
tVectorStatic.requiredNodesNumber = 3;
tests.push_back( tVectorStatic );
Test tIntervalDynamic;
tIntervalDynamic.assign = new DynamicAssignmentAlgorithm( 1, REST_OF_THE_WORLD );
tIntervalDynamic.description = "Dynamic assignment with interval.";
tIntervalDynamic.requiredNodesNumber = ALL;
tests.push_back( tIntervalDynamic );
Test tUniqueDynamic;
tUniqueDynamic.assign = new DynamicAssignmentAlgorithm( 1 );
tUniqueDynamic.description = "Dynamic assignment with unique worker.";
tUniqueDynamic.requiredNodesNumber = 2;
tests.push_back( tUniqueDynamic );
Test tVectorDynamic;
tVectorDynamic.assign = new DynamicAssignmentAlgorithm( workers );
tVectorDynamic.description = "Dynamic assignment with precise workers specified.";
tVectorDynamic.requiredNodesNumber = tVectorStatic.requiredNodesNumber;
tests.push_back( tVectorDynamic );
Test tWorldDynamic;
tWorldDynamic.assign = new DynamicAssignmentAlgorithm;
tWorldDynamic.description = "Dynamic assignment with whole world as workers.";
tWorldDynamic.requiredNodesNumber = ALL;
tests.push_back( tWorldDynamic );
}
for( unsigned int i = 0; i < tests.size(); ++i )
{
ParallelApplyStore< int > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 3 );
store.data( v );
ParallelApply< int > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store );
if( job.isMaster() )
{
cout << "Test : " << tests[i].description << endl;
}
if( Node::comm().rank() < tests[i].requiredNodesNumber )
{
job.run();
}
if( job.isMaster() )
{
EmptyJob stop( *(tests[i].assign), eo::mpi::DEFAULT_MASTER );
++offset;
for(int i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
if( originalV[i] + offset != v[i] )
{
cout << " <-- ERROR at this point." << endl;
exit( EXIT_FAILURE );
}
}
cout << endl;
}
Node::comm().barrier();
delete tests[i].assign;
}
return 0;
}

View file

@ -0,0 +1,91 @@
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include <iostream>
# include <vector>
using namespace std;
using namespace eo::mpi;
struct plusOne : public eoUF< int&, void >
{
void operator() ( int & x )
{
++x;
}
};
template< class EOT >
struct ShowWrappedResult : public IsFinishedParallelApply<EOT>
{
using IsFinishedParallelApply<EOT>::_wrapped;
ShowWrappedResult ( IsFinishedParallelApply<EOT> * w = 0 ) : IsFinishedParallelApply<EOT>( w ), times( 0 )
{
// empty
}
bool operator()()
{
bool wrappedValue = _wrapped->operator()(); // (*_wrapped)();
cout << times << ") Wrapped function would say that it is " << ( wrappedValue ? "":"not ") << "finished" << std::endl;
++times;
return wrappedValue;
}
private:
int times;
};
// These tests require at least 3 processes to be launched.
int main(int argc, char** argv)
{
// eo::log << eo::setlevel( eo::debug );
eo::log << eo::setlevel( eo::quiet );
Node::init( argc, argv );
srand( time(0) );
vector<int> v;
for( int i = 0; i < 1000; ++i )
{
v.push_back( rand() );
}
int offset = 0;
vector<int> originalV = v;
plusOne plusOneInstance;
StaticAssignmentAlgorithm assign( v.size() );
ParallelApplyStore< int > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 1 );
store.data( v );
store.wrapIsFinished( new ShowWrappedResult<int> );
ParallelApply<int> job( assign, eo::mpi::DEFAULT_MASTER, store );
// Equivalent to:
// Job< ParallelApplyData<int> > job( assign, 0, store );
job.run();
EmptyJob stop( assign, eo::mpi::DEFAULT_MASTER );
if( job.isMaster() )
{
++offset;
for(int i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
if( originalV[i] + offset != v[i] )
{
cout << " <-- ERROR at this point." << endl;
exit( EXIT_FAILURE );
}
}
cout << endl;
}
return 0;
}