LogicGrowsOnTrees-MPI-1.0.0: an adapter for LogicGrowsOnTrees that uses MPI

Safe HaskellNone

LogicGrowsOnTrees.Parallel.Adapter.MPI

Contents

Description

This adapter implements parallelism by via MPI; process 0 is the supervisor and the other processes are the workers. (This does mean that one process is used only for coordination, but this approach simplifies things and also ensures that worker requests and responses will be handled promptly.)

WARNING: Do *NOT* use the threaded runtime with this adapter as it has been designed with the assumption that the run-time is single-threaded. This was done because the MPI implementation might not support having multiple operating system threads (even if only one of them calls MPI functions), and anyway multiple operating system threads provide no benefit over lightweight Haskell threads in this case because the MPI scheduler will assign an MPI process to each CPU core so multiple threads will not result in better performance but rather in multiple processes fighting over the same CPU core, as well as the additional overhead of the threaded runtime compared to the non-threaded runtime.

Synopsis

Driver

driver :: forall shared_configuration supervisor_configuration m n exploration_mode. (Serialize shared_configuration, Serialize (ProgressFor exploration_mode), Serialize (WorkerFinishedProgressFor exploration_mode)) => Driver IO shared_configuration supervisor_configuration m n exploration_mode

This is the driver for the MPI adapter; process 0 acts as the supervisor and the other processes act as workers.

WARNING: Do *NOT* use the threaded runtime with this driver (or driverMPI); see the warning in the documentation for this module for more details.

driverMPI :: (Serialize shared_configuration, Serialize (ProgressFor exploration_mode), Serialize (WorkerFinishedProgressFor exploration_mode)) => Driver MPI shared_configuration supervisor_configuration m n exploration_mode

The same as driver, but runs in the MPI monad; use this driver if you want to do other things within MPI (such as starting a subsequent parallel exploration) after the run completes.

MPI

Monad and runner

data MPI α

This monad exists in order to ensure that the MPI system is initialized before it is used and finalized when we are done; all MPI operations are run within it, and it itself is run by using the runMPI function.

runMPI :: MPI α -> IO α

Initilizes MPI, runs the MPI action, and then finalizes MPI.

Information and communication

getMPIInformation :: MPI (Bool, CInt)

Gets the total number of processes and whether this process is process 0.

receiveBroadcastMessage :: Serialize α => MPI α

Receves a message broadcast from process 0 (which must not be this process).

sendBroadcastMessage :: Serialize α => α -> MPI ()

Sends a message broadcast from this process, which must be process 0.

sendMessage :: Serialize α => α -> CInt -> MPI ()

Sends a message to another process.

tryReceiveMessage :: Serialize α => MPI (Maybe (CInt, α))

Receives a message (along with the sending process id) if one is waiting to be received; this function will not block if there are no messages available.

Controller

data MPIControllerMonad exploration_mode α

This is the monad in which the MPI controller will run.

Instances

Monad (MPIControllerMonad exploration_mode) 
Functor (MPIControllerMonad exploration_mode) 
Applicative (MPIControllerMonad exploration_mode) 
MonadIO (MPIControllerMonad exploration_mode) 
RequestQueueMonad (MPIControllerMonad exploration_mode) 
HasExplorationMode (MPIControllerMonad exploration_mode) 
MonadCatchIO (MPIControllerMonad exploration_mode) 

abort :: RequestQueueMonad m => m ()

Abort the supervisor.

fork :: RequestQueueMonad m => m () -> m ThreadId

Fork a new thread running in this monad; all controller threads are automnatically killed when the run is finished.

getCurrentProgressAsync :: RequestQueueMonad m => (ProgressFor (ExplorationModeFor m) -> IO ()) -> m ()

Request the current progress, invoking the given callback with the result; see getCurrentProgress for the synchronous version.

getCurrentProgress :: RequestQueueMonad m => m (ProgressFor (ExplorationModeFor m))

Like getCurrentProgressAsync, but blocks until the result is ready.

getNumberOfWorkersAsync :: RequestQueueMonad m => (Int -> IO ()) -> m ()

Request the number of workers, invoking the given callback with the result; see getNumberOfWorkers for the synchronous version.

getNumberOfWorkers :: RequestQueueMonad m => m Int

Like getNumberOfWorkersAsync, but blocks until the result is ready.

requestProgressUpdateAsync :: RequestQueueMonad m => (ProgressFor (ExplorationModeFor m) -> IO ()) -> m ()

Request that a global progress update be performed, invoking the given callback with the result; see requestProgressUpdate for the synchronous version.

requestProgressUpdate :: RequestQueueMonad m => m (ProgressFor (ExplorationModeFor m))

Like requestProgressUpdateAsync, but blocks until the progress update has completed.

setWorkloadBufferSize :: RequestQueueMonad m => Int -> m ()

Sets the size of the workload buffer; for more information, see setWorkloadBufferSize (which links to the LogicGrowsOnTrees.Parallel.Common.Supervisor module).

Outcome types

data RunOutcome progress final_result

A type that represents the outcome of a run.

Constructors

RunOutcome 

Fields

runStatistics :: RunStatistics

statistics gathered during the run, useful if the system is not scaling with the number of workers as it should

runTerminationReason :: TerminationReason progress final_result

the reason why the run terminated

Instances

(Eq progress, Eq final_result) => Eq (RunOutcome progress final_result) 
(Show progress, Show final_result) => Show (RunOutcome progress final_result) 

data RunStatistics

Statistics gathered about the run.

Constructors

RunStatistics 

Fields

runStartTime :: !UTCTime

the start time of the run

runEndTime :: !UTCTime

the end time of the run

runWallTime :: !NominalDiffTime

the wall time of the run

runSupervisorOccupation :: !Float

the fraction of the time the supervisor spent processing events

runSupervisorMonadOccupation :: !Float

the fraction of the time the supervisor spent processing events while inside the SupervisorMonad

runNumberOfCalls :: !Int

the number of calls made to functions in LogicGrowsOnTrees.Parallel.Common.Supervisor

runAverageTimePerCall :: !Float

the average amount of time per call made to functions in LogicGrowsOnTrees.Parallel.Common.Supervisor

runWorkerOccupation :: !Float

the fraction of the total time that workers were occupied

runWorkerWaitTimes :: !(FunctionOfTimeStatistics NominalDiffTime)

statistics for how long it took for workers to obtain a workload

runStealWaitTimes :: !IndependentMeasurementsStatistics

statistics for the time needed to steal a workload from a worker

runWaitingWorkerStatistics :: !(FunctionOfTimeStatistics Int)

statistics for the number of workers waiting for a workload

runAvailableWorkloadStatistics :: !(FunctionOfTimeStatistics Int)

statistics for the number of available workloads waiting for a worker

runInstantaneousWorkloadRequestRateStatistics :: !(FunctionOfTimeStatistics Float)

statistics for the instantaneous rate at which workloads were requested (using an exponentially decaying sum)

runInstantaneousWorkloadStealTimeStatistics :: !(FunctionOfTimeStatistics Float)

statistics for the instantaneous time needed for workloads to be stolen (using an exponentially decaying weighted average)

data TerminationReason progress final_result

A type that represents the reason why a run terminated.

Constructors

Aborted progress

the run was aborted with the given progress

Completed final_result

the run completed with the given final result

Failure progress String

the run failed with the given progress for the given reason

Instances

(Eq progress, Eq final_result) => Eq (TerminationReason progress final_result) 
(Show progress, Show final_result) => Show (TerminationReason progress final_result) 

Generic runners

In this section the full functionality of this module is exposed in case one does not want the restrictions of the driver interface. If you decide to go in this direction, then you need to decide whether you want to manually handle factors such as deciding whether a process is the supervisor or a worker and the propagation of configuration information to the worker or whether you want this to be done automatically; if you want full control then call runSupervisor in the supervisor process --- which *must* be process 0! --- and call runWorker in the worker processes, otherwise call runExplorer.

WARNING: Do *NOT* use the threaded runtime with this adapter; see the warning in the documentation for this module for more details.

runSupervisor

Arguments

:: forall exploration_mode . (Serialize (ProgressFor exploration_mode), Serialize (WorkerFinishedProgressFor exploration_mode)) 
=> CInt

the number of workers

-> ExplorationMode exploration_mode

the exploration mode

-> ProgressFor exploration_mode

the initial progress of the run

-> MPIControllerMonad exploration_mode ()

the controller of the supervisor

-> MPI (RunOutcomeFor exploration_mode)

the outcome of the run

This runs the supervisor; it must be called in process 0.

runWorker

Arguments

:: (Serialize (ProgressFor exploration_mode), Serialize (WorkerFinishedProgressFor exploration_mode)) 
=> ExplorationMode exploration_mode

the mode in to explore the tree

-> Purity m n

the purity of the tree

-> TreeT m (ResultFor exploration_mode)

the tree

-> MPI () 

Runs a worker; it must be called in all processes other than process 0.

runExplorer

Arguments

:: forall shared_configuration supervisor_configuration exploration_mode m n . (Serialize shared_configuration, Serialize (ProgressFor exploration_mode), Serialize (WorkerFinishedProgressFor exploration_mode)) 
=> (shared_configuration -> ExplorationMode exploration_mode)

a function that constructs the exploration mode given the shared configuration

-> Purity m n

the purity of the tree

-> IO (shared_configuration, supervisor_configuration)

an action that gets the shared and supervisor-specific configuration information (run only on the supervisor)

-> (shared_configuration -> IO ())

an action that initializes the global state of the process given the shared configuration (run on both supervisor and worker processes)

-> (shared_configuration -> TreeT m (ResultFor exploration_mode))

a function that constructs the tree from the shared configuration (called only on the worker)

-> (shared_configuration -> supervisor_configuration -> IO (ProgressFor exploration_mode))

an action that gets the starting progress given the full configuration information (run only on the supervisor)

-> (shared_configuration -> supervisor_configuration -> MPIControllerMonad exploration_mode ())

a function that constructs the controller for the supervisor, which must at least set the number of workers to be non-zero (called only on the supervisor)

-> MPI (Maybe ((shared_configuration, supervisor_configuration), RunOutcomeFor exploration_mode))

if this process is the supervisor, then the outcome of the run as well as the configuration information wrapped in Just; otherwise Nothing

Explores the given tree using MPI to achieve parallelism.

This function grants access to all of the functionality of this adapter, rather than having to go through the more restricted driver interface. The signature of this function is very complicated because it is meant to be used in all processes, supervisor and worker alike.