The SKIRT project
advanced radiative transfer for astrophysics
Public Member Functions | Static Public Member Functions | Static Private Member Functions | Static Private Attributes | List of all members
ProcessManager Class Referencefinal

#include <ProcessManager.hpp>

Public Member Functions

 ProcessManager (const ProcessManager &)=delete
 
 ProcessManager (int *argc, char ***argv)
 
 ~ProcessManager ()
 
ProcessManageroperator= (const ProcessManager &)=delete
 

Static Public Member Functions

static void abort (int exitcode)
 
static void broadcastAllToAll (std::function< void(vector< double > &data)> producer, std::function< void(const vector< double > &data)> consumer)
 
static void clearLogger ()
 
static bool isMultiProc ()
 
static bool isRoot ()
 
static int rank ()
 
static bool requestChunk (size_t &firstIndex, size_t &numIndices)
 
static void serveChunkRequest (int rank, size_t firstIndex, size_t numIndices)
 
static void setLogger (std::function< void(string)> logger)
 
static int size ()
 
static void sumToAll (Array &arr)
 
static void sumToRoot (Array &arr, bool wait=false)
 
static void wait ()
 
static int waitForChunkRequest ()
 

Static Private Member Functions

static void finalize ()
 
static void initialize (int *argc, char ***argv)
 

Static Private Attributes

static int _rank
 
static int _size
 

Detailed Description

The ProcessManager class is an interface to the MPI library, and is the only place in the SKIRT code where explicit calls to this library are allowed. A single instance of the ProcessManager class must be constructed just after program startup, and before the command-line arguments are used by other parts of the program. The latter is important because the MPI initialization functions called by the ProcessManager constructor may adjust the command-line arguments to remove MPI specific options. The program should let the main() function run to normal completion and return an exit code rather than calling the std::exit() function. In case of abnormal termination, the program should call the ProcessManager::abort() function as opposed to the std::abort() function.

The functions of this class should be called only from the main thread of the program. Violation of this rule causes undefined behavior that may differ between MPI implementations.

Constructor & Destructor Documentation

◆ ProcessManager() [1/2]

ProcessManager::ProcessManager ( int *  argc,
char ***  argv 
)
inline

The constructor initializes the MPI library used for remote communication, if present. It is passed a reference to the command line arguments to provide the MPI library with the opportunity to use and/or adjust them (e.g. to remove any MPI related arguments).

◆ ~ProcessManager()

ProcessManager::~ProcessManager ( )
inline

The destructor finalizes the MPI library used for remote communication, if present.

◆ ProcessManager() [2/2]

ProcessManager::ProcessManager ( const ProcessManager )
delete

The copy constructor is deleted because instances of this class should never be copied or moved.

Member Function Documentation

◆ abort()

static void ProcessManager::abort ( int  exitcode)
static

This function should be called when a process experiences a fatal error (after the error was reported to the user). If there are two or more processes in the current run-time environment, this function aborts the complete MPI process group, including the calling process. If the MPI library is not present, or the program was invoked without MPI, or there is only one process, this function does nothing.

◆ broadcastAllToAll()

static void ProcessManager::broadcastAllToAll ( std::function< void(vector< double > &data)>  producer,
std::function< void(const vector< double > &data)>  consumer 
)
static

This function broadcasts a separate sequence of floating point values from each process to the other processes. The chunk of data to be sent by the calling process must be generated by the provided call-back function producer. Similarly, the chunks of data reveived by the calling process from the other processes must be processed by the provided call-back function consumer. The chunks of data sent by each process may have different sizes. Using call-back functions (as apposed to passing the data directly) avoids the need for holding all data in memory at the same time, which can be a significant benefit in some cases. The following table lists the number of times each function is invoked.

nr of processes producer invocations consumer invocations
N=1 0 0
N>1 1 N-1

The producer function must store the data to be sent into the vector specified as its argument. The vector is guaranteed to be empty when the function is called (but it may have a nonzero memory allocation). Similarly, the consumer function can retrieve the received data from the vector specified as its argument.

Within each process, the calls to the producer and consumer functions are serialized (i.e. they never occur in parallel threads). However, there is no ordering guarantee within or across processes other than that consuming data can happen only after it has been produced. This freedom allows a future implementation to use non-blocking communication primitives.

◆ clearLogger()

static void ProcessManager::clearLogger ( )
static

This function clears the usage logger so that it is no longer called.

◆ finalize()

static void ProcessManager::finalize ( )
staticprivate

This static function finalizes the MPI library used for remote communication, if present. The function is called from the destructor of this class.

◆ initialize()

static void ProcessManager::initialize ( int *  argc,
char ***  argv 
)
staticprivate

This static function initializes the MPI library used for remote communication, if present. The function is called from the constructor of this class.

◆ isMultiProc()

static bool ProcessManager::isMultiProc ( )
inlinestatic

This function returns true if the current run-time environment has two or more processes. If the MPI library is not present, or the program was invoked without MPI, the function returns false.

◆ isRoot()

static bool ProcessManager::isRoot ( )
inlinestatic

This function returns true if the calling process is considered to be the root process, i.e. its rank is zero. If the MPI library is not present, or the program was invoked without MPI, the function always returns true.

◆ operator=()

ProcessManager & ProcessManager::operator= ( const ProcessManager )
delete

The assignment operator is deleted because instances of this class should never be copied or moved.

◆ rank()

static int ProcessManager::rank ( )
inlinestatic

This function returns the rank of the calling process in the current run-time environment, i.e. an integer in a range from zero to the number of processes minus one. If the MPI library is not present, or the program was invoked without MPI, the function always returns zero.

◆ requestChunk()

static bool ProcessManager::requestChunk ( size_t &  firstIndex,
size_t &  numIndices 
)
static

This function is part of the mechanism for dynamically allocating chunks of parallel tasks across multiple processes. It requests the next available chunk from the root process and waits for a response. When successful, the function places a chunk index range in its arguments and returns true. If no more chunks are available, the function returns false (and the output arguments are both set to zero). If there is only one process, or if the function is invoked from the root process, a fatal error is thrown.

◆ serveChunkRequest()

static void ProcessManager::serveChunkRequest ( int  rank,
size_t  firstIndex,
size_t  numIndices 
)
static

This function is part of the mechanism for dynamically allocating chunks of parallel tasks across multiple processes. It communicates the index range of the next available chunk request to the process in the MPI group with the specified rank. If there is only one process, or if the function is invoked from any process other than the root process, a fatal error is thrown.

◆ setLogger()

static void ProcessManager::setLogger ( std::function< void(string)>  logger)
static

This function sets the specified callback function as the usage logger, which is called with diagnostic messages bracketing each MPI operation. Initially, the logger is cleared.

◆ size()

static int ProcessManager::size ( )
inlinestatic

This function returns the number of processes in the current run-time environment. If the MPI library is not present, or the program was invoked without MPI, the function returns one.

◆ sumToAll()

static void ProcessManager::sumToAll ( Array arr)
static

This function adds the floating point values of an array element-wise across the different processes. The resulting sums are then stored in the same Array passed to this function on each individual process. All processes must call this function for the communication to proceed. If there is only one process, or if the array has zero size, the function does nothing.

◆ sumToRoot()

static void ProcessManager::sumToRoot ( Array arr,
bool  wait = false 
)
static

This function adds the floating point values of an array element-wise across the different processes. The resulting sums are then stored in the same Array passed to this function on the root process. The arrays on the other processes are left untouched. All processes must call this function for the communication to proceed. If there is only one process, or if the array has zero size, the function does nothing.

If the wait argument is true, this function causes the processes to block until all other processes have invoked it as well. This is important in case the sumToRoot() call may be followed by a sequence of master-slave chunk requests without an intervening call to wait(). Indeed, because nonroot processes do not receive any data in this function, if the MPI implementation buffers the involved send operations, the sumToRoot() function may return in nonroot processes before the root process calls it. This causes problems in case the sumToRoot() call is followed by a sequence of master-slave chunk requests, because the nonroot process might steal a (terminating empty) chunk from the previous sequence, stalling some other non-root process indefinitely. In practice, this means wait should be set to true when sumToRoot() is called from probes and can be left to false when it is called from instruments.

◆ wait()

static void ProcessManager::wait ( )
static

This function causes the calling process to block until all other processes have invoked it as well. If there is only one process, the function does nothing.

◆ waitForChunkRequest()

static int ProcessManager::waitForChunkRequest ( )
static

This function is part of the mechanism for dynamically allocating chunks of parallel tasks across multiple processes. It waits for a chunk request from any of the processes in the MPI group and returns the rank of the requesting process. If there is only one process, or if the function is invoked from any process other than the root process, a fatal error is thrown.


The documentation for this class was generated from the following file: