[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