manual merge: deactivate t-eoParallel, that depends on OpenMP, whatever the build options

This commit is contained in:
Johann Dreo 2012-07-16 15:15:42 +02:00
commit afd02eeb37
34 changed files with 2330 additions and 809 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 # does not work anymore since functions used in this test were removed from EO
#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()
######################################################################################

View file

@ -1,108 +0,0 @@
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.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, v, rank );
ParallelApply<int> job( algo, rank, store );
job.run();
}
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, metaV, 0 );
ParallelApply< vector<int> > job( algo, 0, store );
job.run();
if( job.isMaster() )
{
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

@ -1,18 +1,39 @@
//-----------------------------------------------------------------------------
// t-eoMpiParallel.cpp
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of parallel evaluation of a population, when using an eoEasyEA algorithm.
* Moreover, we add a basic wrapper on the parallel evaluation, so as to show how to retrieve the best solutions.
*/
//-----------------------------------------------------------------------------
#include <eo>
#include <eoPopEvalFunc.h>
#include <es/make_real.h>
// #include <apply.h>
#include "../real_value.h"
#include <mpi/eoMpi.h>
#include <mpi/eoTerminateJob.h>
#include <boost/mpi.hpp>
#include <vector>
@ -82,6 +103,16 @@ class eoRealSerializable : public eoReal< eoMinimizingFitness >, public eoserial
typedef eoRealSerializable EOT;
/*
* Wrapper for HandleResponse: shows the best answer, as it is found.
*
* Finding the best solution is an associative operation (as it is based on a "min" function, which is associative too)
* and that's why we can perform it here. Indeed, the min element of 5 elements is the min element of the 3 first
* elements and the min element of the 2 last elements:
* min(1, 2, 3, 4, 5) = min( min(1, 2, 3), min(4, 5) )
*
* This is a reduction. See MapReduce example to have another examples of reduction.
*/
struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply<EOT>
{
CatBestAnswers()
@ -89,14 +120,15 @@ struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply<EOT>
best.fitness( 1000000000. );
}
using eo::mpi::HandleResponseParallelApply<EOT>::_wrapped;
using eo::mpi::HandleResponseParallelApply<EOT>::d;
// if EOT were a template, we would have to do: (thank you C++ :)
// 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 );
(*_wrapped)( wrkRank ); // call to the wrapped function HERE
for(int i = index; i < index+size; ++i)
{
if( best.fitness() < d->data()[ i ].fitness() )
@ -136,6 +168,9 @@ int main(int ac, char** av)
eoEvalFuncPtr< EOT, double, const std::vector< double >& > mainEval( real_value );
eoEvalFuncCounter< EOT > eval( mainEval );
// until this point, everything (but eo::mpi::Node::init) is exactly as in an sequential version.
// We then instanciate the parallel algorithm. The store is directly used by the eoParallelPopLoopEval, which
// internally uses parallel apply.
int rank = eo::mpi::Node::comm().rank();
eo::mpi::DynamicAssignmentAlgorithm assign;
if( rank == eo::mpi::DEFAULT_MASTER )
@ -144,10 +179,10 @@ int main(int ac, char** av)
eo::log << "Size of population : " << popSize << std::endl;
eo::mpi::ParallelEvalStore< EOT > store( eval, eo::mpi::DEFAULT_MASTER );
eo::mpi::ParallelApplyStore< EOT > store( eval, eo::mpi::DEFAULT_MASTER );
store.wrapHandleResponse( new CatBestAnswers );
eoParallelPopLoopEval< EOT > popEval( eval, assign, &store, eo::mpi::DEFAULT_MASTER, 3 );
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;
@ -159,8 +194,8 @@ int main(int ac, char** av)
eo::log << eo::quiet << "DONE!" << std::endl;
} else
{
eoPop< EOT > pop( popSize, init );
eoParallelPopLoopEval< EOT > popEval( eval, assign, eo::mpi::DEFAULT_MASTER, 3 );
eoPop< EOT > pop; // the population doesn't have to be initialized, as it is not used by workers.
eoParallelPopLoopEval< EOT > popEval( assign, eo::mpi::DEFAULT_MASTER, eval );
popEval( pop, pop );
}

View file

@ -0,0 +1,169 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of how to make a hierarchy between nodes, when using a parallel apply. In this basic
* test, the master delegates the charge of finding workers to 2 "sub" masters, which then send part of the table to
* their workers.
*
* It's convenient to establish a role map, so as to clearly identify every role:
* - The node 0 is the general master, that delegates the job. It sends the table to the 2 submasters, and waits for the
* results.
* - Nodes 1 and 2 are the worker of the first job: the delegates. They receive the elements of the table and
* retransmit them to the subworkers. They play the roles of worker in the delegating job, and master in the plus one
* job.
* - Following nodes (3 to 6) are workers of the plus one job. They do the real job. Nodes 3 and 5 are attached to
* submaster 1, 4 and 6 to submaster 2.
*
* This test requires exactly 7 hosts. If the size is bigger, an exception will be thrown at the beginning.
**/
# 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;
// The real job to execute, for the subworkers: add one to each element of a table.
struct SubWork: public eoUF< int&, void >
{
void operator() ( int & x )
{
cout << "Subwork phase." << endl;
++x;
}
};
// Function called by both subworkers and delegates.
// v is the vector to process, rank is the MPI rank of the sub master
void subtask( vector<int>& v, int rank )
{
// Attach workers according to nodes.
// Submaster with rank 1 will have ranks 3 and 5 as subworkers.
// Submaster with rank 2 will have ranks 4 and 6 as subworkers.
vector<int> workers;
workers.push_back( rank + 2 );
workers.push_back( rank + 4 );
DynamicAssignmentAlgorithm algo( workers );
SubWork sw;
// Launch the job!
ParallelApplyStore<int> store( sw, rank );
store.data( v );
ParallelApply<int> job( algo, rank, store );
job.run();
EmptyJob stop( algo, rank );
}
// Functor applied by submasters. Wait for the subworkers responses and then add some random processing (here, multiply
// each result by two).
// Note that this work receives a vector of integers as an entry, while subworkers task's operator receives a simple
// integer.
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 );
if( Node::comm().size() != 7 ) {
throw std::runtime_error("World size should be 7.");
}
vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(3);
v.push_back(7);
v.push_back(42);
// As submasters' operator receives a vector<int> as an input, and ParallelApply takes a vector of
// operator's input as an input, we have to deal with a vector of vector of integers for the master task.
vector< vector<int> > metaV;
// Here, we send twice the same vector. We could also have splitted the first vector into two vectors, one
// containing the beginning and another one containing the end.
metaV.push_back( v );
metaV.push_back( v );
// Assigning roles is done by comparing MPI ranks.
switch( Node::comm().rank() )
{
// Nodes from 0 to 2 are implicated into the delegating task.
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;
// Other nodes are implicated into the subwork task.
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

@ -1,5 +1,44 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of use of parallel apply, in the following context: each element of a table is
* incremented... in a parallel fashion. While this operation is very easy to perform even on a single host, it's just
* an example for parallel apply use.
*
* Besides, this is also a test for assignment (scheduling) algorithms, in different cases. The test succeeds if and
* only if the program terminates without any segfault ; otherwise, there could be a deadlock which prevents the end or
* a segfault at any time.
*
* One important thing is to instanciate an EmptyJob after having launched a ParallelApplyJob, so as the workers to be
* aware that the job is done (as it's a MultiJob).
*
* This test needs at least 3 processes to be launched. Under this size, it will directly throw an exception, at the
* beginning;
*/
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include <iostream>
@ -8,6 +47,9 @@ using namespace std;
using namespace eo::mpi;
/*
* The function to be called on each element of the table: just increment the value.
*/
struct plusOne : public eoUF< int&, void >
{
void operator() ( int & x )
@ -16,22 +58,26 @@ struct plusOne : public eoUF< int&, void >
}
};
/*
* Internal structure representating a test.
*/
struct Test
{
AssignmentAlgorithm * assign;
string description;
int requiredNodesNumber; // nb : chosen nodes ranks must be sequential
AssignmentAlgorithm * assign; // used assignment algorithm for this test.
string description; // textual description of the test
int requiredNodesNumber; // number of required nodes. 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::debug ); // if you like tty full of rainbows, decomment this line and comment the following one.
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 );
// Initializes a vector with random values.
srand( time(0) );
vector<int> v;
for( int i = 0; i < 1000; ++i )
@ -39,18 +85,27 @@ int main(int argc, char** argv)
v.push_back( rand() );
}
// We need to be sure the values are correctly incremented between each test. So as to check this, we save the
// original vector into a variable originalV, and put an offset variable to 0. After each test, the offset is
// incremented and we can compare the returned value of each element to the value of each element in originalV +
// offset. If the two values are different, there has been a problem.
int offset = 0;
vector<int> originalV = v;
// Instanciates the functor to apply on each element
plusOne plusOneInstance;
vector< Test > tests;
const int ALL = Node::comm().size();
if( ALL < 3 ) {
throw std::runtime_error("Needs at least 3 processes to be launched!");
}
// Tests are auto described thanks to member "description"
Test tIntervalStatic;
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."; // workers have ranks from 1 to size - 1
tIntervalStatic.requiredNodesNumber = ALL;
tests.push_back( tIntervalStatic );
@ -110,22 +165,32 @@ int main(int argc, char** argv)
for( unsigned int i = 0; i < tests.size(); ++i )
{
ParallelApplyStore< int > store( plusOneInstance, v, eo::mpi::DEFAULT_MASTER, 3 );
// Job< JobData<int> > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store );
// Instanciates a store with the functor, the master rank and size of packet (see ParallelApplyStore doc).
ParallelApplyStore< int > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 3 );
// Updates the contained data
store.data( v );
// Creates the job with the assignment algorithm, the master rank and the store
ParallelApply< int > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store );
// Only master writes information
if( job.isMaster() )
{
cout << "Test : " << tests[i].description << endl;
}
// Workers whose rank is inferior to required nodes number have to run the test, the other haven't anything to
// do.
if( Node::comm().rank() < tests[i].requiredNodesNumber )
{
job.run();
}
// After the job run, the master checks the result with offset and originalV
if( job.isMaster() )
{
// This job has to be instanciated, not launched, so as to tell the workers they're done with the parallel
// job.
EmptyJob stop( *(tests[i].assign), eo::mpi::DEFAULT_MASTER );
++offset;
for(int i = 0; i < v.size(); ++i)
{
@ -139,6 +204,7 @@ int main(int argc, char** argv)
cout << endl;
}
// MPI synchronization (all the processes wait to be here).
Node::comm().barrier();
delete tests[i].assign;

View file

@ -0,0 +1,132 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of how to wrap a handler of a job store. Here, the wrapped handler is the "IsFinished"
* one. The only function that has been added is that the wrapper prints a message on standard output, indicating what
* the wrapped function returns as a result.
*
* This test is performed on a parallel apply job, the same as in parallelApply. The main difference is when
* instanciating the store.
*/
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include <iostream>
# include <vector>
using namespace std;
using namespace eo::mpi;
// Job functor.
struct plusOne : public eoUF< int&, void >
{
void operator() ( int & x )
{
++x;
}
};
/*
* Shows the wrapped result of IsFinished, prints a message and returns the wrapped value.
* times is an integer counting how many time the wrapper (hence the wrapped too) has been called.
*/
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;
};
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 );
// This is the only thing which changes: we wrap the IsFinished function.
// According to RAII, we'll delete the invokated wrapper at the end of the main ; the store won't delete it
// automatically.
IsFinishedParallelApply* wrapper = new ShowWrappedResult<int>;
store.wrapIsFinished( wrapper );
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;
}
delete wrapper;
return 0;
}

View file

@ -1,88 +0,0 @@
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.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, v, eo::mpi::DEFAULT_MASTER, 1 );
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();
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;
}