Documentation of MPI examples.
This commit is contained in:
parent
d2816d530a
commit
b92f17fce5
4 changed files with 219 additions and 21 deletions
|
|
@ -1,12 +1,35 @@
|
||||||
//-----------------------------------------------------------------------------
|
/*
|
||||||
// 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 <eo>
|
||||||
#include <eoPopEvalFunc.h>
|
#include <eoPopEvalFunc.h>
|
||||||
|
|
||||||
#include <es/make_real.h>
|
#include <es/make_real.h>
|
||||||
// #include <apply.h>
|
|
||||||
#include "../real_value.h"
|
#include "../real_value.h"
|
||||||
|
|
||||||
#include <mpi/eoMpi.h>
|
#include <mpi/eoMpi.h>
|
||||||
|
|
@ -80,6 +103,16 @@ class eoRealSerializable : public eoReal< eoMinimizingFitness >, public eoserial
|
||||||
|
|
||||||
typedef eoRealSerializable EOT;
|
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>
|
struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply<EOT>
|
||||||
{
|
{
|
||||||
CatBestAnswers()
|
CatBestAnswers()
|
||||||
|
|
@ -87,14 +120,15 @@ struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply<EOT>
|
||||||
best.fitness( 1000000000. );
|
best.fitness( 1000000000. );
|
||||||
}
|
}
|
||||||
|
|
||||||
using eo::mpi::HandleResponseParallelApply<EOT>::_wrapped;
|
// if EOT were a template, we would have to do: (thank you C++ :)
|
||||||
using eo::mpi::HandleResponseParallelApply<EOT>::d;
|
// using eo::mpi::HandleResponseParallelApply<EOT>::_wrapped;
|
||||||
|
// using eo::mpi::HandleResponseParallelApply<EOT>::d;
|
||||||
|
|
||||||
void operator()(int wrkRank)
|
void operator()(int wrkRank)
|
||||||
{
|
{
|
||||||
int index = d->assignedTasks[wrkRank].index;
|
int index = d->assignedTasks[wrkRank].index;
|
||||||
int size = d->assignedTasks[wrkRank].size;
|
int size = d->assignedTasks[wrkRank].size;
|
||||||
(*_wrapped)( wrkRank );
|
(*_wrapped)( wrkRank ); // call to the wrapped function HERE
|
||||||
for(int i = index; i < index+size; ++i)
|
for(int i = index; i < index+size; ++i)
|
||||||
{
|
{
|
||||||
if( best.fitness() < d->data()[ i ].fitness() )
|
if( best.fitness() < d->data()[ i ].fitness() )
|
||||||
|
|
@ -134,6 +168,9 @@ int main(int ac, char** av)
|
||||||
eoEvalFuncPtr< EOT, double, const std::vector< double >& > mainEval( real_value );
|
eoEvalFuncPtr< EOT, double, const std::vector< double >& > mainEval( real_value );
|
||||||
eoEvalFuncCounter< EOT > eval( mainEval );
|
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();
|
int rank = eo::mpi::Node::comm().rank();
|
||||||
eo::mpi::DynamicAssignmentAlgorithm assign;
|
eo::mpi::DynamicAssignmentAlgorithm assign;
|
||||||
if( rank == eo::mpi::DEFAULT_MASTER )
|
if( rank == eo::mpi::DEFAULT_MASTER )
|
||||||
|
|
@ -157,7 +194,7 @@ int main(int ac, char** av)
|
||||||
eo::log << eo::quiet << "DONE!" << std::endl;
|
eo::log << eo::quiet << "DONE!" << std::endl;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
eoPop< EOT > pop( popSize, init );
|
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 );
|
eoParallelPopLoopEval< EOT > popEval( assign, eo::mpi::DEFAULT_MASTER, eval );
|
||||||
popEval( pop, pop );
|
popEval( pop, pop );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,42 @@
|
||||||
|
/*
|
||||||
|
(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/eoMpi.h>
|
||||||
# include <mpi/eoParallelApply.h>
|
# include <mpi/eoParallelApply.h>
|
||||||
# include <mpi/eoTerminateJob.h>
|
# include <mpi/eoTerminateJob.h>
|
||||||
|
|
@ -11,11 +50,7 @@ using namespace std;
|
||||||
|
|
||||||
using namespace eo::mpi;
|
using namespace eo::mpi;
|
||||||
|
|
||||||
// Role map
|
// The real job to execute, for the subworkers: add one to each element of a table.
|
||||||
// 0 : general master
|
|
||||||
// 1, 2 : worker of general job, master of subjob
|
|
||||||
// 3 to 7 : workers of subjob
|
|
||||||
|
|
||||||
struct SubWork: public eoUF< int&, void >
|
struct SubWork: public eoUF< int&, void >
|
||||||
{
|
{
|
||||||
void operator() ( int & x )
|
void operator() ( int & x )
|
||||||
|
|
@ -25,14 +60,20 @@ struct SubWork: public eoUF< int&, void >
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 )
|
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;
|
vector<int> workers;
|
||||||
workers.push_back( rank + 2 );
|
workers.push_back( rank + 2 );
|
||||||
workers.push_back( rank + 4 );
|
workers.push_back( rank + 4 );
|
||||||
DynamicAssignmentAlgorithm algo( workers );
|
DynamicAssignmentAlgorithm algo( workers );
|
||||||
SubWork sw;
|
SubWork sw;
|
||||||
|
|
||||||
|
// Launch the job!
|
||||||
ParallelApplyStore<int> store( sw, rank );
|
ParallelApplyStore<int> store( sw, rank );
|
||||||
store.data( v );
|
store.data( v );
|
||||||
ParallelApply<int> job( algo, rank, store );
|
ParallelApply<int> job( algo, rank, store );
|
||||||
|
|
@ -40,6 +81,10 @@ void subtask( vector<int>& v, int rank )
|
||||||
EmptyJob stop( algo, rank );
|
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 >
|
struct Work: public eoUF< vector<int>&, void >
|
||||||
{
|
{
|
||||||
void operator() ( vector<int>& v )
|
void operator() ( vector<int>& v )
|
||||||
|
|
@ -57,6 +102,10 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
// eo::log << eo::setlevel( eo::debug );
|
// eo::log << eo::setlevel( eo::debug );
|
||||||
Node::init( argc, argv );
|
Node::init( argc, argv );
|
||||||
|
if( Node::comm().size() != 7 ) {
|
||||||
|
throw std::runtime_error("World size should be 7.");
|
||||||
|
}
|
||||||
|
|
||||||
vector<int> v;
|
vector<int> v;
|
||||||
|
|
||||||
v.push_back(1);
|
v.push_back(1);
|
||||||
|
|
@ -65,12 +114,18 @@ int main(int argc, char** argv)
|
||||||
v.push_back(7);
|
v.push_back(7);
|
||||||
v.push_back(42);
|
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;
|
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 );
|
||||||
metaV.push_back( v );
|
metaV.push_back( v );
|
||||||
|
|
||||||
|
// Assigning roles is done by comparing MPI ranks.
|
||||||
switch( Node::comm().rank() )
|
switch( Node::comm().rank() )
|
||||||
{
|
{
|
||||||
|
// Nodes from 0 to 2 are implicated into the delegating task.
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
|
|
@ -95,6 +150,7 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Other nodes are implicated into the subwork task.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// all the other nodes are sub workers
|
// all the other nodes are sub workers
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,41 @@
|
||||||
|
/*
|
||||||
|
(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/eoMpi.h>
|
||||||
# include <mpi/eoParallelApply.h>
|
# include <mpi/eoParallelApply.h>
|
||||||
# include <mpi/eoTerminateJob.h>
|
# include <mpi/eoTerminateJob.h>
|
||||||
|
|
@ -9,6 +47,9 @@ using namespace std;
|
||||||
|
|
||||||
using namespace eo::mpi;
|
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 >
|
struct plusOne : public eoUF< int&, void >
|
||||||
{
|
{
|
||||||
void operator() ( int & x )
|
void operator() ( int & x )
|
||||||
|
|
@ -17,22 +58,26 @@ struct plusOne : public eoUF< int&, void >
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal structure representating a test.
|
||||||
|
*/
|
||||||
struct Test
|
struct Test
|
||||||
{
|
{
|
||||||
AssignmentAlgorithm * assign;
|
AssignmentAlgorithm * assign; // used assignment algorithm for this test.
|
||||||
string description;
|
string description; // textual description of the test
|
||||||
int requiredNodesNumber; // nb : chosen nodes ranks must be sequential
|
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)
|
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 );
|
eo::log << eo::setlevel( eo::quiet );
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
Node::init( argc, argv );
|
Node::init( argc, argv );
|
||||||
|
|
||||||
|
// Initializes a vector with random values.
|
||||||
srand( time(0) );
|
srand( time(0) );
|
||||||
vector<int> v;
|
vector<int> v;
|
||||||
for( int i = 0; i < 1000; ++i )
|
for( int i = 0; i < 1000; ++i )
|
||||||
|
|
@ -40,18 +85,27 @@ int main(int argc, char** argv)
|
||||||
v.push_back( rand() );
|
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;
|
int offset = 0;
|
||||||
vector<int> originalV = v;
|
vector<int> originalV = v;
|
||||||
|
|
||||||
|
// Instanciates the functor to apply on each element
|
||||||
plusOne plusOneInstance;
|
plusOne plusOneInstance;
|
||||||
|
|
||||||
vector< Test > tests;
|
vector< Test > tests;
|
||||||
|
|
||||||
const int ALL = Node::comm().size();
|
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;
|
Test tIntervalStatic;
|
||||||
tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, 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."; // workers have ranks from 1 to size - 1
|
||||||
tIntervalStatic.requiredNodesNumber = ALL;
|
tIntervalStatic.requiredNodesNumber = ALL;
|
||||||
tests.push_back( tIntervalStatic );
|
tests.push_back( tIntervalStatic );
|
||||||
|
|
||||||
|
|
@ -111,23 +165,32 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
for( unsigned int i = 0; i < tests.size(); ++i )
|
for( unsigned int i = 0; i < tests.size(); ++i )
|
||||||
{
|
{
|
||||||
|
// 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 );
|
ParallelApplyStore< int > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 3 );
|
||||||
|
// Updates the contained data
|
||||||
store.data( v );
|
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 );
|
ParallelApply< int > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store );
|
||||||
|
|
||||||
|
// Only master writes information
|
||||||
if( job.isMaster() )
|
if( job.isMaster() )
|
||||||
{
|
{
|
||||||
cout << "Test : " << tests[i].description << endl;
|
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 )
|
if( Node::comm().rank() < tests[i].requiredNodesNumber )
|
||||||
{
|
{
|
||||||
job.run();
|
job.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After the job run, the master checks the result with offset and originalV
|
||||||
if( job.isMaster() )
|
if( job.isMaster() )
|
||||||
{
|
{
|
||||||
EmptyJob stop( *(tests[i].assign), eo::mpi::DEFAULT_MASTER );
|
// 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;
|
++offset;
|
||||||
for(int i = 0; i < v.size(); ++i)
|
for(int i = 0; i < v.size(); ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -141,6 +204,7 @@ int main(int argc, char** argv)
|
||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MPI synchronization (all the processes wait to be here).
|
||||||
Node::comm().barrier();
|
Node::comm().barrier();
|
||||||
|
|
||||||
delete tests[i].assign;
|
delete tests[i].assign;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,34 @@
|
||||||
|
/*
|
||||||
|
(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/eoMpi.h>
|
||||||
# include <mpi/eoParallelApply.h>
|
# include <mpi/eoParallelApply.h>
|
||||||
# include <mpi/eoTerminateJob.h>
|
# include <mpi/eoTerminateJob.h>
|
||||||
|
|
@ -9,6 +40,7 @@ using namespace std;
|
||||||
|
|
||||||
using namespace eo::mpi;
|
using namespace eo::mpi;
|
||||||
|
|
||||||
|
// Job functor.
|
||||||
struct plusOne : public eoUF< int&, void >
|
struct plusOne : public eoUF< int&, void >
|
||||||
{
|
{
|
||||||
void operator() ( int & x )
|
void operator() ( int & x )
|
||||||
|
|
@ -17,6 +49,10 @@ struct plusOne : public eoUF< int&, void >
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 >
|
template< class EOT >
|
||||||
struct ShowWrappedResult : public IsFinishedParallelApply<EOT>
|
struct ShowWrappedResult : public IsFinishedParallelApply<EOT>
|
||||||
{
|
{
|
||||||
|
|
@ -39,7 +75,6 @@ struct ShowWrappedResult : public IsFinishedParallelApply<EOT>
|
||||||
int times;
|
int times;
|
||||||
};
|
};
|
||||||
|
|
||||||
// These tests require at least 3 processes to be launched.
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
// eo::log << eo::setlevel( eo::debug );
|
// eo::log << eo::setlevel( eo::debug );
|
||||||
|
|
@ -63,7 +98,11 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
ParallelApplyStore< int > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 1 );
|
ParallelApplyStore< int > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 1 );
|
||||||
store.data( v );
|
store.data( v );
|
||||||
store.wrapIsFinished( new ShowWrappedResult<int> );
|
// 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 );
|
ParallelApply<int> job( assign, eo::mpi::DEFAULT_MASTER, store );
|
||||||
// Equivalent to:
|
// Equivalent to:
|
||||||
|
|
@ -86,6 +125,8 @@ int main(int argc, char** argv)
|
||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete wrapper;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Reference in a new issue