[Debian-astro-commits] [gyoto] 51/221: Do not run MPI_Init automatically, instead check that it has been done and fall-back to non-MPI behaviour if it has not.
Thibaut Jean-Claude Paumard
thibaut at moszumanska.debian.org
Fri May 22 20:52:33 UTC 2015
This is an automated email from the git hooks/post-receive script.
thibaut pushed a commit to branch master
in repository gyoto.
commit b59317d408f3e08a5c834d64533b1890d6f01c7e
Author: Thibaut Paumard <paumard at users.sourceforge.net>
Date: Wed Oct 15 13:06:05 2014 +0200
Do not run MPI_Init automatically, instead check that it has been done and fall-back to non-MPI behaviour if it has not.
---
bin/gyoto-mpi-worker.C | 5 +--
bin/gyoto.C | 44 +++++++++++++++++++++-----
include/GyotoScenery.h | 28 +++++++++++++++--
lib/Scenery.C | 58 +++++++++++++++++------------------
yorick/gyoto.i | 80 +++++++++++++++++++++++++++++++++++-------------
yorick/gyoto_Scenery.C | 5 +--
yorick/gyoto_namespace.i | 2 ++
yorick/gyoto_utils.C | 50 +++++++++++++++++++++++++++---
8 files changed, 202 insertions(+), 70 deletions(-)
diff --git a/bin/gyoto-mpi-worker.C b/bin/gyoto-mpi-worker.C
index 3a9043f..359fb0c 100644
--- a/bin/gyoto-mpi-worker.C
+++ b/bin/gyoto-mpi-worker.C
@@ -69,13 +69,12 @@ int main(int argc, char** argv) {
debug(0);
// verbose(1);
- mpi::environment env;
+ mpi::environment env(argc, argv);
MPI_Comm parent_c;
MPI_Comm_get_parent(&parent_c);
- mpi::communicator world;
mpi::communicator team=mpi::intercommunicator(parent_c,mpi::comm_take_ownership).merge(true);
string pluglist= getenv("GYOTO_PLUGINS")?
@@ -86,8 +85,6 @@ int main(int argc, char** argv) {
curretval = 1;
Gyoto::Register::init(pluglist.c_str());
- int rk=world.rank();
-
sc = new Scenery();
sc -> mpi_team_ = &team;
diff --git a/bin/gyoto.C b/bin/gyoto.C
index 5055ebf..0b79f90 100644
--- a/bin/gyoto.C
+++ b/bin/gyoto.C
@@ -32,7 +32,12 @@
// getpid()
#include <sys/types.h>
#include <unistd.h>
-
+
+// MPI
+#if defined HAVE_MPI
+# include <mpi.h>
+#endif
+
using namespace std;
using namespace Gyoto;
@@ -80,6 +85,7 @@ int main(int argc, char** argv) {
fixed star or disk). The final result is a list of illuminated
pixels.
*/
+
// For debug output
debug(0);
// verbose(1);
@@ -240,10 +246,32 @@ int main(int argc, char** argv) {
curmsg = "In gyoto.C: Error getting Kind: ";
const string kind = factory->kind();
- if (!kind.compare("Scenery")) {
+ if (kind.compare("Scenery")) {
+ cerr << "Unknown kind for root element in XML file" << endl;
+ return 1;
+ }
+
+ curmsg = "In gyoto.C: Error getting Scenery: ";
+ SmartPointer<Scenery> scenery = factory -> getScenery();
+
+ curmsg = "In gyoto.C: Error deleting Scenery: ";
+ delete factory;
+
+ if (xnprocs) scenery -> nProcesses ( nprocs );
+
+#if defined HAVE_MPI
+ if (scenery -> nProcesses()) {
+ int status = MPI_Init(&argc, &argv);
+ if (status) {
+ cerr << "error initializing MPI"<< endl;
+ return 2;
+ }
+ }
+#endif
+
+ {
curmsg = "In gyoto.C: Error initializing ray-tracing: ";
curretval = 2;
- SmartPointer<Scenery> scenery = factory -> getScenery();
SmartPointer<Screen> screen = scenery->screen();
SmartPointer<Astrobj::Generic> object = scenery->astrobj();
@@ -258,7 +286,6 @@ int main(int argc, char** argv) {
if (xpaln) screen -> PALN ( paln );
if (xarg) screen -> argument ( arg );
if (xnthreads) scenery -> nThreads ( nthreads );
- if (xnprocs) scenery -> nProcesses ( nprocs );
if (ipctfile != "") {
// if (verbose() >= GYOTO_QUIET_VERBOSITY)
@@ -493,11 +520,12 @@ int main(int argc, char** argv) {
if (status) return status;
- } else {
- cerr << "Unknown kind for root element in XML file" << endl;
- return 1;
}
- delete factory;
+#if defined HAVE_MPI
+ if (MPI::Is_initialized() && !MPI::Is_finalized()) MPI_Finalize();
+#endif
+
+
return 0;
}
diff --git a/include/GyotoScenery.h b/include/GyotoScenery.h
index e46225c..9cd5014 100644
--- a/include/GyotoScenery.h
+++ b/include/GyotoScenery.h
@@ -211,18 +211,42 @@ class Gyoto::Scenery : protected Gyoto::SmartPointee {
Gyoto::SmartPointer<Gyoto::Units::Converter> binspectrum_converter_;
# endif
-# ifdef HAVE_MPI
public:
+# ifdef HAVE_MPI
+ /// Team of processes for MPI
+ /**
+ * Rank 0 is the manager, other ranks are workers, instances of the
+ * gyoto-mpi-worker executable.
+ */
boost::mpi::communicator * mpi_team_;
+# endif
+ /// True in instance of gyoto-mpi-worker, otherwise false.
static bool am_worker;
+
+ /// Spawn gyoto-mpi-worker processes
+ /**
+ * Also sets nprocesses_. If the right number of workers is already
+ * running, does nothing. Also does nothing if MPI_Init() has not
+ * been called yet.
+ */
void mpiSpawn(int nbchildren);
+
+ /// Terminate gyoto-mpi-worker-processes
void mpiTerminate ();
+
+ /// Send a copy of self to the mpi workers
+ /**
+ * Always call mpiClone() before ray-tracing if workers are running.
+ */
void mpiClone();
+
+ /// Tags that may be sent to communicate with workers using MPI_Send()
enum mpi_tag {give_task, read_scenery, terminate,
raytrace, raytrace_done, ready,
impactcoords, noimpactcoords};
+
+ /// Send a tag to workers
void mpiTask(mpi_tag &tag);
-# endif
// Constructors - Destructor
// -------------------------
diff --git a/lib/Scenery.C b/lib/Scenery.C
index f2e857d..110bf47 100644
--- a/lib/Scenery.C
+++ b/lib/Scenery.C
@@ -50,7 +50,7 @@ using namespace std;
Scenery::Scenery() :
screen_(NULL), delta_(GYOTO_DEFAULT_DELTA),
- quantities_(0), ph_(), nthreads_(0)
+ quantities_(0), ph_(), nthreads_(0), nprocesses_(0)
#ifdef HAVE_MPI
, mpi_team_(NULL)
#endif
@@ -60,7 +60,7 @@ Scenery::Scenery(SmartPointer<Metric::Generic> met,
SmartPointer<Screen> scr,
SmartPointer<Astrobj::Generic> obj) :
screen_(scr), delta_(GYOTO_DEFAULT_DELTA),
- quantities_(0), ph_(), nthreads_(0)
+ quantities_(0), ph_(), nthreads_(0), nprocesses_(0)
#ifdef HAVE_MPI
, mpi_team_(NULL)
#endif
@@ -74,7 +74,7 @@ Scenery::Scenery(const Scenery& o) :
SmartPointee(o),
screen_(NULL), delta_(o.delta_),
quantities_(o.quantities_), ph_(o.ph_),
- nthreads_(o.nthreads_)
+ nthreads_(o.nthreads_), nprocesses_(0)
#ifdef HAVE_MPI
, mpi_team_(NULL)
#endif
@@ -244,16 +244,9 @@ void Scenery::rayTrace(size_t imin, size_t imax,
double * impactcoords) {
#if defined HAVE_MPI
- bool need_to_terminate=false;
- if (nprocesses_ && mpi_team_) {
- if (!MPI::Is_initialized() && !MPI::Is_finalized()) need_to_terminate=true;
- if (MPI::Is_finalized()) {
- GYOTO_SEVERE
- << "MPI_Finalize() has been called already, won't use MPI"<< endl;
- } else {
- mpiSpawn(nprocesses_);
- mpiClone();
- }
+ if (nprocesses_ && !mpi_team_) {
+ mpiSpawn(nprocesses_);
+ mpiClone();
}
#endif
@@ -464,10 +457,6 @@ void Scenery::rayTrace(size_t imin, size_t imax,
}
}
if (verbose()) cout << endl;
- if (need_to_terminate) {
- mpiTerminate();
- MPI_Finalize();
- }
} else {
// We are a worker, do we need to query for impactcoords?
double ipct[16];
@@ -875,11 +864,21 @@ SmartPointer<Scenery> Gyoto::Scenery::Subcontractor(FactoryMessenger* fmp) {
}
#endif
-#ifdef HAVE_MPI
bool Gyoto::Scenery::am_worker=false;
void Gyoto::Scenery::mpiSpawn(int nbchildren) {
-
+#ifdef HAVE_MPI
+ int flag;
+ if (MPI_Initialized(&flag)) throwError("Error running MPI_Initialized()");
+ if (!flag) {
+ nprocesses_=0;
+ return;
+ }
+ nprocesses_=nbchildren;
+ if (mpi_team_) {
+ if (mpi_team_->size()==nbchildren+1) return;
+ mpiTerminate();
+ }
// Add our SO-versionned directory at the end of the PATH variable.
string PATH=getenv("PATH");
@@ -890,14 +889,7 @@ void Gyoto::Scenery::mpiSpawn(int nbchildren) {
setenv("PATH", PATH.c_str(), 1);
- if (mpi_team_) {
- if (mpi_team_->size()==nbchildren+1) return;
- mpiTerminate();
- }
-
if (nbchildren) {
- if (!MPI::Is_initialized()) MPI::Init();
-
MPI_Comm children_c;
MPI_Comm_spawn(const_cast<char*>("gyoto-mpi-worker"),
MPI_ARGV_NULL, nbchildren,
@@ -906,9 +898,12 @@ void Gyoto::Scenery::mpiSpawn(int nbchildren) {
mpi_team_ = new mpi::communicator(mpi::intercommunicator (children_c, mpi::comm_take_ownership).merge(false));
}
+
+#endif
}
void Gyoto::Scenery::mpiTerminate() {
+#ifdef HAVE_MPI
if (mpi_team_) {
mpi_tag tag=terminate;
mpiTask(tag);
@@ -916,20 +911,25 @@ void Gyoto::Scenery::mpiTerminate() {
delete mpi_team_;
mpi_team_=NULL;
}
+#endif
}
-void Gyoto::Scenery::mpiClone()
-{
+void Gyoto::Scenery::mpiClone() {
+#ifdef HAVE_MPI
+ if (!mpi_team_) return;
std::string xmldata=
Gyoto::Factory(this).format();
int errcode;
mpi_tag tag=read_scenery;
mpiTask(tag);
broadcast(*mpi_team_, xmldata, 0);
+#endif
}
void Gyoto::Scenery::mpiTask(mpi_tag &tag) {
+#ifdef HAVE_MPI
+ if (!mpi_team_) return;
mpi::broadcast(*mpi_team_, tag, 0);
+#endif
}
-#endif
diff --git a/yorick/gyoto.i b/yorick/gyoto.i
index 25973e2..5d7d845 100644
--- a/yorick/gyoto.i
+++ b/yorick/gyoto.i
@@ -63,27 +63,51 @@ extern gyoto_haveMPI;
OUTPUT:
HAVE_MPI=1 if compiled with MPI, else 0.
+
+ SEE ALSO: gyoto.mpiInit, .mpiFinalize, .mpiInitialized, .mpiFinalized
+*/
+
+extern gyoto_mpiInit;
+/* DOCUMENT status = gyoto.mpiInit([argv]);
+ Initialize MPI.
+
+ Wrapper around MPI_Init(numberof(argv), argv). argv may be
+ modified upon completion.
+
+ Returns 0 for success, no-zer otherwise.
+
+ If MPI is not compiled-in, returns 1.
+
+ SEE ALSO: gyoto.haveMPI, .mpiFinalize, .mpiInitialized, .mpiFinalized
*/
extern gyoto_mpiFinalize;
/* DOCUMENT gyoto.mpiFinalize;
Finalize MPI.
- Unlike the underlying implementation, does not trigger an error if
- MPI is already finalized.
-
- This is a noop if MPI is not compiled-in.
+ Wrapper around MPI_Finalize(). Returns 0 for success, non-zero otherwise.
+
+ If MPI is not compiled-in, returns 1.
- SEE ALSO: gyoto.haveMPI, gyoto.mpiFinalized
+ SEE ALSO: gyoto.haveMPI, .mpiInit, .mpiFinalized, .mpiInitialized
*/
extern gyoto_mpiFinalized;
/* DOCUMENT is_finalized=gyoto.mpiFinalized();
Tell whether some implemention of MPI_Finalize() was already called.
- If MPI support is not present, return 1.
+ If MPI support is not present, return 0.
- SEE ALSO: gyoto.haveMPI, gyoto.mpiFinalize
+ SEE ALSO: gyoto.haveMPI, .mpiFinalize, .mpiInit, .mpiInitialzed
+ */
+
+extern gyoto_mpiInitialized;
+/* DOCUMENT is_initialized=gyoto.mpiInitialized();
+ Tell whether some implemention of MPI_Init() was already called.
+
+ If MPI support is not present, return 0.
+
+ SEE ALSO: gyoto.haveMPI, .mpiInit, .mpiFinalize, .mpiFinalized
*/
extern __gyoto_setErrorHandler;
@@ -515,22 +539,36 @@ extern gyoto_Scenery;
gyoto.Scenery_rayTrace. This has no effect when
ray-tracing using the "data = scenery()" syntax below.
- mpispawn=number of parallel MPI jobs (a.k.a. workers) to spawn for
- ray-tracing using gyoto.Scenery_rayTrace(). Works only if
- MPI support was built in. Spawned jobs may consume CPU
- cycles even if they are idle. Use mpispawn=0 to terminate
- those jobs. Always use mpiclone to send the current
- Scenery to the workers before calling
- gyoto.Scenery_rayTrace(). This can be done in the same
- call as mpispawn:
- sc, mpispawn=12, mpiclone=;
-
- mpiclone=[anything]: clone this Scenery into the MPI workers (see
+
+ MPI MULTI-PROCESSING:
+
+ You can check whether MPI support is compiled-in using
+ gyoto.haveMPI(). To benefit from it, you must call
+ gyoto.mpiInit() once, before using the following keywords. Before
+ quitting Yorick, should should also call 'sc, mpispawn=0;
+ gyoto.mpiFinalize;'. Failure to do that may lead to helper
+ processes lingering around.
+
+ nprocesses=number of parallel processes to use. If you just set
+ nprocesses this way, they will be launched (but not
+ stopped) automatically the first time ray-tracing is
+ attempted. Setting nprocesses after processes have been
+ launched does not change the number of processes running.
+
+ mpispawn=number of parallel MPI jobs (a.k.a. workers) to
+ spawn. This also sets nprocesses, and actually launches
+ the processes. use mpilaunch=0 to stop the processes (they
+ consume CPU cycles even when idle). Always use mpiclone to
+ send the current Scenery to the workers before calling
+ gyoto.Scenery_rayTrace(). This can be done in the same
+ call as mpispawn: sc, mpispawn=12, mpiclone=;
+
+ mpiclone=[anything]: clone this Scenery into the MPI workers (see
mpispawn). The workers do not stay synchonised
automatically. mpiclone must always be called right
- before gyoto.Scenery_rayTrace() (i.e. after any
- modification to the Scenery or any of the objects it
- contains, and after having called mpispawn).
+ before ray-tracing (i.e. after any modification to the
+ Scenery or any of the objects it contains, and after
+ having called mpispawn).
RAY-TRACING:
diff --git a/yorick/gyoto_Scenery.C b/yorick/gyoto_Scenery.C
index 59c48a9..72b2698 100644
--- a/yorick/gyoto_Scenery.C
+++ b/yorick/gyoto_Scenery.C
@@ -165,12 +165,12 @@ extern "C" {
"maxiter", "integrator", "deltamin", "deltamax", "deltamaxoverr",
"abstol", "reltol",
"xmlwrite", "clone", "clonephoton",
- "impactcoords", "nthreads",
+ "impactcoords", "nthreads", "nprocesses",
"mpispawn", "mpiclone",
0
};
- YGYOTO_WORKER_INIT1(Scenery, Scenery, knames, 23)
+ YGYOTO_WORKER_INIT1(Scenery, Scenery, knames, 24)
// Get pointer
if (yarg_true(kiargs[++k])) {
@@ -249,6 +249,7 @@ extern "C" {
}
YGYOTO_WORKER_GETSET_LONG2(nThreads);
+ YGYOTO_WORKER_GETSET_LONG2(nProcesses);
#ifdef HAVE_MPI
YGYOTO_WORKER_RUN( mpiSpawn(ygets_l(iarg)) );
YGYOTO_WORKER_RUN( mpiClone() );
diff --git a/yorick/gyoto_namespace.i b/yorick/gyoto_namespace.i
index fe5d564..7e9a7fc 100644
--- a/yorick/gyoto_namespace.i
+++ b/yorick/gyoto_namespace.i
@@ -5,7 +5,9 @@ gyoto=save(
haveUDUNITS=gyoto_haveUDUNITS,
havePTHREAD=gyoto_havePTHREAD,
haveMPI=gyoto_haveMPI,
+ mpiInit=gyoto_mpiInit,
mpiFinalize=gyoto_mpiFinalize,
+ mpiInitialized=gyoto_mpiInitialized,
mpiFinalized=gyoto_mpiFinalized,
loadPlugin=gyoto_loadPlugin,
diff --git a/yorick/gyoto_utils.C b/yorick/gyoto_utils.C
index 07a8f47..cd51739 100644
--- a/yorick/gyoto_utils.C
+++ b/yorick/gyoto_utils.C
@@ -20,6 +20,7 @@
#include <GyotoUtils.h>
#include <GyotoRegister.h>
#include <yapi.h>
+#include <pstdlib.h>
#include <cstring>
#include <iostream>
#include <sstream>
@@ -188,11 +189,50 @@ extern "C" {
}
void
+ Y_gyoto_mpiInit(int argc)
+ {
+#if defined HAVE_MPI
+ long int mpiargcl=0;
+ char **mpiargv=NULL;
+ long index=-1;
+ if (argc>1) y_error("gyoto.mpiInit() takes at most one argument");
+ if (argc) {
+ index=yget_ref(0);
+ if (!yarg_nil(0)) mpiargv=ygeta_q(0, &mpiargcl, NULL);
+ }
+ int mpiargc=mpiargcl;
+ ypush_long(MPI_Init(&mpiargc, &mpiargv));
+ if (index>=0) {
+ long dims[]={1, mpiargc};
+ ystring_t * out=ypush_q(dims);
+ for (long i=0; i<mpiargc; ++i) out[i] = p_strcpy(mpiargv[i]);
+ yput_global(index, 0);
+ yarg_drop(1);
+ }
+#else
+ ypush_long(1);
+#endif
+ }
+
+ void
+ Y_gyoto_mpiInitialized(int argc)
+ {
+#if defined HAVE_MPI
+ int flag=0;
+ MPI_Initialized(&flag);
+ ypush_long(flag);
+#else
+ ypush_long(0);
+#endif
+ }
+
+ void
Y_gyoto_mpiFinalize(int)
{
- ypush_nil();
#if defined HAVE_MPI
- if (!MPI::Is_finalized()) MPI::Finalize();
+ ypush_long(MPI_Finalize());
+#else
+ ypush_long(1);
#endif
}
@@ -200,9 +240,11 @@ extern "C" {
Y_gyoto_mpiFinalized(int argc)
{
#if defined HAVE_MPI
- ypush_long(MPI::Is_finalized());
+ int flag=0;
+ MPI_Finalized(&flag);
+ ypush_long(flag);
#else
- ypush_long(1);
+ ypush_long(0);
#endif
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-astro/packages/gyoto.git
More information about the Debian-astro-commits
mailing list