packages feed

mpi-hs 0.5.1.2 → 0.5.2.0

raw patch · 10 files changed

+1260/−162 lines, 10 filesdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Control.Distributed.MPI.Storable: Comm :: CComm -> Comm
+ Control.Distributed.MPI.Storable: Count :: CInt -> Count
+ Control.Distributed.MPI.Storable: MPIException :: String -> MPIException
+ Control.Distributed.MPI.Storable: Rank :: CInt -> Rank
+ Control.Distributed.MPI.Storable: Status :: !Rank -> !Tag -> Status
+ Control.Distributed.MPI.Storable: Tag :: CInt -> Tag
+ Control.Distributed.MPI.Storable: [msgRank] :: Status -> !Rank
+ Control.Distributed.MPI.Storable: [msgTag] :: Status -> !Tag
+ Control.Distributed.MPI.Storable: abort :: Comm -> Int -> IO ()
+ Control.Distributed.MPI.Storable: anySource :: Rank
+ Control.Distributed.MPI.Storable: anyTag :: Tag
+ Control.Distributed.MPI.Storable: barrier :: Comm -> IO ()
+ Control.Distributed.MPI.Storable: bcastRecv :: CanSerialize a => Rank -> Comm -> IO a
+ Control.Distributed.MPI.Storable: bcastSend :: CanSerialize a => a -> Rank -> Comm -> IO ()
+ Control.Distributed.MPI.Storable: commRank :: Comm -> IO Rank
+ Control.Distributed.MPI.Storable: commSelf :: Comm
+ Control.Distributed.MPI.Storable: commSize :: Comm -> IO Rank
+ Control.Distributed.MPI.Storable: commWorld :: Comm
+ Control.Distributed.MPI.Storable: data Request a
+ Control.Distributed.MPI.Storable: data Status
+ Control.Distributed.MPI.Storable: fromCount :: Integral i => Count -> i
+ Control.Distributed.MPI.Storable: fromRank :: Enum e => Rank -> e
+ Control.Distributed.MPI.Storable: fromTag :: Enum e => Tag -> e
+ Control.Distributed.MPI.Storable: ibarrier :: Comm -> IO (Request ())
+ Control.Distributed.MPI.Storable: ibcastRecv :: CanSerialize a => Rank -> Comm -> IO (Request a)
+ Control.Distributed.MPI.Storable: ibcastSend :: CanSerialize a => a -> Rank -> Comm -> IO (Request ())
+ Control.Distributed.MPI.Storable: instance GHC.Classes.Eq Control.Distributed.MPI.Storable.MPIException
+ Control.Distributed.MPI.Storable: instance GHC.Classes.Eq Control.Distributed.MPI.Storable.Status
+ Control.Distributed.MPI.Storable: instance GHC.Classes.Ord Control.Distributed.MPI.Storable.MPIException
+ Control.Distributed.MPI.Storable: instance GHC.Classes.Ord Control.Distributed.MPI.Storable.Status
+ Control.Distributed.MPI.Storable: instance GHC.Exception.Type.Exception Control.Distributed.MPI.Storable.MPIException
+ Control.Distributed.MPI.Storable: instance GHC.Read.Read Control.Distributed.MPI.Storable.MPIException
+ Control.Distributed.MPI.Storable: instance GHC.Read.Read Control.Distributed.MPI.Storable.Status
+ Control.Distributed.MPI.Storable: instance GHC.Show.Show Control.Distributed.MPI.Storable.MPIException
+ Control.Distributed.MPI.Storable: instance GHC.Show.Show Control.Distributed.MPI.Storable.Status
+ Control.Distributed.MPI.Storable: irecv :: CanSerialize a => Rank -> Tag -> Comm -> IO (Request a)
+ Control.Distributed.MPI.Storable: isend :: CanSerialize a => a -> Rank -> Tag -> Comm -> IO (Request ())
+ Control.Distributed.MPI.Storable: mainMPI :: IO () -> IO ()
+ Control.Distributed.MPI.Storable: newtype Comm
+ Control.Distributed.MPI.Storable: newtype Count
+ Control.Distributed.MPI.Storable: newtype MPIException
+ Control.Distributed.MPI.Storable: newtype Rank
+ Control.Distributed.MPI.Storable: newtype Tag
+ Control.Distributed.MPI.Storable: recv :: CanSerialize a => Rank -> Tag -> Comm -> IO (Status, a)
+ Control.Distributed.MPI.Storable: recv_ :: CanSerialize a => Rank -> Tag -> Comm -> IO a
+ Control.Distributed.MPI.Storable: rootRank :: Rank
+ Control.Distributed.MPI.Storable: send :: CanSerialize a => a -> Rank -> Tag -> Comm -> IO ()
+ Control.Distributed.MPI.Storable: sendrecv :: (CanSerialize a, CanSerialize b) => a -> Rank -> Tag -> Rank -> Tag -> Comm -> IO (Status, b)
+ Control.Distributed.MPI.Storable: sendrecv_ :: (CanSerialize a, CanSerialize b) => a -> Rank -> Tag -> Rank -> Tag -> Comm -> IO b
+ Control.Distributed.MPI.Storable: test :: Request a -> IO (Maybe (Status, a))
+ Control.Distributed.MPI.Storable: test_ :: Request a -> IO (Maybe a)
+ Control.Distributed.MPI.Storable: toCount :: Integral i => i -> Count
+ Control.Distributed.MPI.Storable: toRank :: Enum e => e -> Rank
+ Control.Distributed.MPI.Storable: toTag :: Enum e => e -> Tag
+ Control.Distributed.MPI.Storable: unitTag :: Tag
+ Control.Distributed.MPI.Storable: wait :: Request a -> IO (Status, a)
+ Control.Distributed.MPI.Storable: wait_ :: Request a -> IO a
- Control.Distributed.MPI: Comm :: ForeignPtr Comm -> Comm
+ Control.Distributed.MPI: Comm :: CComm -> Comm
- Control.Distributed.MPI: Datatype :: ForeignPtr Datatype -> Datatype
+ Control.Distributed.MPI: Datatype :: CDatatype -> Datatype
- Control.Distributed.MPI: Op :: ForeignPtr Op -> Op
+ Control.Distributed.MPI: Op :: COp -> Op
- Control.Distributed.MPI: Request :: ForeignPtr Request -> Request
+ Control.Distributed.MPI: Request :: CRequest -> Request
- Control.Distributed.MPI: requestNull :: Request
+ Control.Distributed.MPI: requestNull :: IO Request
- Control.Distributed.MPI.Binary: Comm :: ForeignPtr Comm -> Comm
+ Control.Distributed.MPI.Binary: Comm :: CComm -> Comm
- Control.Distributed.MPI.Serialize: Comm :: ForeignPtr Comm -> Comm
+ Control.Distributed.MPI.Serialize: Comm :: CComm -> Comm
- Control.Distributed.MPI.Store: Comm :: ForeignPtr Comm -> Comm
+ Control.Distributed.MPI.Store: Comm :: CComm -> Comm

Files

README.md view
@@ -5,9 +5,12 @@ * [GitHub](https://github.com/eschnett/mpi-hs): Source code repository * [Hackage](http://hackage.haskell.org/package/mpi-hs): Haskell   package and documentation-* [CircleCI](https://circleci.com/gh/eschnett/mpi-hs): Continuous-  integration-  [![CircleCI](https://circleci.com/gh/eschnett/mpi-hs.svg?style=svg)](https://circleci.com/gh/eschnett/mpi-hs)+* [Stackage](https://www.stackage.org/package/mpi-hs): Stackage+  snapshots+* [Azure+  Pipelines](https://dev.azure.com/schnetter/ringal/_build):+  Build Status [![Build+  Status](https://dev.azure.com/schnetter/mpi-hs/_apis/build/status/eschnett.mpi-hs?branchName=master)](https://dev.azure.com/schnetter/mpi-hs/_build/latest?definitionId=1&branchName=master)   @@ -157,14 +160,14 @@  ``` stack build-mpirun -np 3 stack exec example && echo SUCCESS || echo FAILURE+mpirun-openmpi-mp -np 3 stack exec example && echo SUCCESS || echo FAILURE ```  With OpenMPI, and when running on a single node (e.g. on a laptop or a workstation), these additional `mpirun` options might be useful:  ```-mpirun -np 3 --mca btl self,vader --oversubscribe stack exec example && echo SUCCESS || echo FAILURE+mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec example && echo SUCCESS || echo FAILURE ```  The options `--mca btl self,vader` enable the shared memory byte@@ -184,8 +187,9 @@  ``` stack build --test --no-run-tests-mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec $(stack path --dist-dir)/build/mpi-test/mpi-test && echo SUCCESS || echo FAILURE-mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec $(stack path --dist-dir)/build/mpi-test-binary/mpi-test-binary && echo SUCCESS || echo FAILURE-mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec $(stack path --dist-dir)/build/mpi-test-serialize/mpi-test-serialize && echo SUCCESS || echo FAILURE-mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec $(stack path --dist-dir)/build/mpi-test-store/mpi-test-store && echo SUCCESS || echo FAILURE+mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec -- $(stack path --dist-dir)/build/mpi-test/mpi-test && echo SUCCESS || echo FAILURE+mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec -- $(stack path --dist-dir)/build/mpi-test-binary/mpi-test-binary && echo SUCCESS || echo FAILURE+mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec -- $(stack path --dist-dir)/build/mpi-test-serialize/mpi-test-serialize && echo SUCCESS || echo FAILURE+mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec -- $(stack path --dist-dir)/build/mpi-test-storable/mpi-test-storable && echo SUCCESS || echo FAILURE+mpirun-openmpi-mp -np 3 --mca btl self,vader --oversubscribe stack exec -- $(stack path --dist-dir)/build/mpi-test-store/mpi-test-store && echo SUCCESS || echo FAILURE ```
c/include/mpihs.h view
@@ -70,8 +70,4 @@ // Tag int mpihs_get_any_tag(); -// Wrappers-int mpihs_iprobe(int source, int tag, MPI_Comm *comm, int *flag,-                 MPI_Status *status);- #endif // #ifndef MPIHS_H
c/src/mpihs.c view
@@ -67,9 +67,3 @@  // Tag int mpihs_get_any_tag() { return MPI_ANY_TAG; }--// Wrappers-int mpihs_iprobe(int source, int tag, MPI_Comm *comm, int *flag,-                 MPI_Status *status) {-  return MPI_Iprobe(source, tag, *comm, flag, status);-}
lib/Control/Distributed/MPI.chs view
@@ -350,12 +350,27 @@ -- Communicators need to be explicitly created and freed by the MPI -- library. 'commWorld' is a communicator that is always available, -- and which includes all processes.-{#pointer *MPI_Comm as Comm foreign newtype#} -deriving instance Eq Comm-deriving instance Ord Comm-deriving instance Show Comm+newtype Comm = Comm CComm+  deriving (Eq, Ord, Show) +type CComm = {#type MPI_Comm#}++-- Pass a communicator directly+fromComm :: Comm -> CComm+fromComm (Comm ccomm) = ccomm++-- Pass a communicator as pointer+withComm :: Comm -> (Ptr CComm -> IO a) -> IO a+withComm (Comm ccomm) f =+  alloca $ \ptr -> do poke ptr ccomm+                      f ptr+-- Read a communicator from a pointer+peekComm :: Ptr CComm -> IO Comm+peekComm ptr =+  do ccomm <- peek ptr+     return (Comm ccomm)+ -- | The result of comparing two MPI communicator (see 'commCompare'). {#enum ComparisonResult {} deriving (Eq, Ord, Read, Show, Generic)#} @@ -391,14 +406,29 @@ -- explicitly created and freed by the MPI library. Predefined -- datatypes exist for most simple C types such as 'CInt' or -- 'CDouble'.-{#pointer *MPI_Datatype as Datatype foreign newtype#} -deriving instance Eq Datatype-deriving instance Ord Datatype-deriving instance Show Datatype+newtype Datatype = Datatype CDatatype+  deriving (Eq, Ord, Show) +type CDatatype = {#type MPI_Datatype#} +-- Pass a datatype directly+fromDatatype :: Datatype -> CDatatype+fromDatatype (Datatype cdatatype) = cdatatype +-- Pass a datatype as pointer+withDatatype :: Datatype -> (Ptr CDatatype -> IO a) -> IO a+withDatatype (Datatype cdatatype) f =+  alloca $ \ptr -> do poke ptr cdatatype+                      f ptr+-- Read a datatype from a pointer+peekDatatype :: Ptr CDatatype -> IO Datatype+peekDatatype ptr =+  do cdatatype <- peek ptr+     return (Datatype cdatatype)+++ -- | An MPI reduction operation, wrapping @MPI_Op@. Reduction -- operations need to be explicitly created and freed by the MPI -- library. Predefined operation exist for simple semigroups such as@@ -406,14 +436,29 @@ -- -- An MPI reduction operation corresponds to a Semigroup, not a -- Monoid, i.e. MPI has no notion of a respective neutral element.-{#pointer *MPI_Op as Op foreign newtype#} -deriving instance Eq Op-deriving instance Ord Op-deriving instance Show Op+newtype Op = Op COp+  deriving (Eq, Ord, Show) +type COp = {#type MPI_Op#} +-- Pass a operator directly+fromOp :: Op -> COp+fromOp (Op cop) = cop +-- Pass a operator as pointer+withOp :: Op -> (Ptr COp -> IO a) -> IO a+withOp (Op cop) f =+  alloca $ \ptr -> do poke ptr cop+                      f ptr+-- Read a operator from a pointer+peekOp :: Ptr COp -> IO Op+peekOp ptr =+  do cop <- peek ptr+     return (Op cop)+++ -- | A newtype wrapper describing the source or destination of a -- message, i.e. a process. Each communicator numbers its processes -- sequentially starting from zero. Use 'toRank' and 'fromRank' to@@ -459,14 +504,34 @@ -- | An MPI request, wrapping @MPI_Request@. A request describes a -- communication that is currently in progress. Each request must be -- explicitly freed via 'cancel', 'test', or 'wait'.-{#pointer *MPI_Request as Request foreign newtype#}+--+-- Some MPI functions modify existing requests. The new requests are+-- never interesting, and will not be returned.+--+-- TODO: Handle 'Comm', 'Datatype' etc. in this way as well (all+-- except 'Status').+newtype Request = Request CRequest+  deriving (Eq, Ord, Show) -deriving instance Eq Request-deriving instance Ord Request-deriving instance Show Request+type CRequest = {#type MPI_Request#} +-- Pass a request directly+fromRequest :: Request -> CRequest+fromRequest (Request creq) = creq +-- Pass a request as pointer+withRequest :: Request -> (Ptr CRequest -> IO a) -> IO a+withRequest (Request creq) f =+  alloca $ \ptr -> do poke ptr creq+                      f ptr+-- Read a request from a pointer+peekRequest :: Ptr CRequest -> IO Request+peekRequest ptr =+  do creq <- peek ptr+     return (Request creq) ++ -- | An MPI status, wrapping @MPI_Status@. The status describes -- certain properties of a message. It contains information such as -- the source of a communication ('getSource'), the message tag@@ -563,15 +628,21 @@   -- | A null (invalid) communicator (@MPI_COMM_NULL@).-{#fun pure mpihs_get_comm_null as commNull {+} -> `Comm'#}+{#fun pure mpihs_get_comm_null as commNull+   { alloca- `Comm' peekComm*+   } -> `()'#}  -- | The self communicator (@MPI_COMM_SELF@). Each process has its own -- self communicator that includes only this process.-{#fun pure mpihs_get_comm_self as commSelf {+} -> `Comm'#}+{#fun pure mpihs_get_comm_self as commSelf+   { alloca- `Comm' peekComm*+   } -> `()'#}  -- | The world communicator, which includes all processes -- (@MPI_COMM_WORLD@).-{#fun pure mpihs_get_comm_world as commWorld {+} -> `Comm'#}+{#fun pure mpihs_get_comm_world as commWorld+    { alloca- `Comm' peekComm*+    } -> `()'#}   @@ -583,47 +654,75 @@   -- | A null (invalid) datatype.-{#fun pure mpihs_get_datatype_null as datatypeNull {+} -> `Datatype'#}+{#fun pure mpihs_get_datatype_null as datatypeNull+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for a byte (essentially 'CUChar') (@MPI_BYTE@).-{#fun pure mpihs_get_byte as datatypeByte {+} -> `Datatype'#}+{#fun pure mpihs_get_byte as datatypeByte+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CChar' (@MPI_CHAR@).-{#fun pure mpihs_get_char as datatypeChar {+} -> `Datatype'#}+{#fun pure mpihs_get_char as datatypeChar+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CDouble' (@MPI_DOUBLE@).-{#fun pure mpihs_get_double as datatypeDouble {+} -> `Datatype'#}+{#fun pure mpihs_get_double as datatypeDouble+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CFloat' (@MPI_FLOAT@).-{#fun pure mpihs_get_float as datatypeFloat {+} -> `Datatype'#}+{#fun pure mpihs_get_float as datatypeFloat+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CInt' (@MPI_INT@).-{#fun pure mpihs_get_int as datatypeInt {+} -> `Datatype'#}+{#fun pure mpihs_get_int as datatypeInt+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CLong' (@MPI_LONG@).-{#fun pure mpihs_get_long as datatypeLong {+} -> `Datatype'#}+{#fun pure mpihs_get_long as datatypeLong+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for the C type 'long double' (@MPI_LONG_DOUBLE@).-{#fun pure mpihs_get_long_double as datatypeLongDouble {+} -> `Datatype'#}+{#fun pure mpihs_get_long_double as datatypeLongDouble+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CLLong' (@MPI_LONG_LONG_INT@). (There is no MPI -- datatype for 'CULLong@).-{#fun pure mpihs_get_long_long_int as datatypeLongLongInt {+} -> `Datatype'#}+{#fun pure mpihs_get_long_long_int as datatypeLongLongInt+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CShort' (@MPI_SHORT@).-{#fun pure mpihs_get_short as datatypeShort {+} -> `Datatype'#}+{#fun pure mpihs_get_short as datatypeShort+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CUInt' (@MPI_UNSIGNED@).-{#fun pure mpihs_get_unsigned as datatypeUnsigned {+} -> `Datatype'#}+{#fun pure mpihs_get_unsigned as datatypeUnsigned+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CUChar' (@MPI_UNSIGNED_CHAR@).-{#fun pure mpihs_get_unsigned_char as datatypeUnsignedChar {+} -> `Datatype'#}+{#fun pure mpihs_get_unsigned_char as datatypeUnsignedChar+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CULong' (@MPI_UNSIGNED_LONG@).-{#fun pure mpihs_get_unsigned_long as datatypeUnsignedLong {+} -> `Datatype'#}+{#fun pure mpihs_get_unsigned_long as datatypeUnsignedLong+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | MPI datatype for 'CUShort' (@MPI_UNSIGNED_SHORT@).-{#fun pure mpihs_get_unsigned_short as datatypeUnsignedShort {+} -> `Datatype'#}+{#fun pure mpihs_get_unsigned_short as datatypeUnsignedShort+    { alloca- `Datatype' peekDatatype*+    } -> `()'#}  -- | A type class mapping Haskell types to MPI datatypes. This is used -- to automatically determine the MPI datatype for communication@@ -644,45 +743,71 @@   -- | A null (invalid) reduction operation (@MPI_OP_NULL@).-{#fun pure mpihs_get_op_null as opNull {+} -> `Op'#}+{#fun pure mpihs_get_op_null as opNull+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The bitwise and @(.&.)@ reduction operation (@MPI_BAND@).-{#fun pure mpihs_get_band as opBand {+} -> `Op'#}+{#fun pure mpihs_get_band as opBand+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The bitwise or @(.|.)@ reduction operation (@MPI_BOR@).-{#fun pure mpihs_get_bor as opBor {+} -> `Op'#}+{#fun pure mpihs_get_bor as opBor+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The bitwise (@xor@) reduction operation (@MPI_BXOR@).-{#fun pure mpihs_get_bxor as opBxor {+} -> `Op'#}+{#fun pure mpihs_get_bxor as opBxor+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The logical and @(&&)@ reduction operation (@MPI_LAND@).-{#fun pure mpihs_get_land as opLand {+} -> `Op'#}+{#fun pure mpihs_get_land as opLand+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The logical or @(||)@ reduction operation (@MPI_LOR@).-{#fun pure mpihs_get_lor as opLor {+} -> `Op'#}+{#fun pure mpihs_get_lor as opLor+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The logical xor reduction operation (@MPI_LXOR@).-{#fun pure mpihs_get_lxor as opLxor {+} -> `Op'#}+{#fun pure mpihs_get_lxor as opLxor+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The 'maximum' reduction operation (@MPI_MAX@).-{#fun pure mpihs_get_max as opMax {+} -> `Op'#}+{#fun pure mpihs_get_max as opMax+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The argmax reduction operation to find the maximum and its rank -- (@MPI_MAXLOC@).-{#fun pure mpihs_get_maxloc as opMaxloc {+} -> `Op'#}+{#fun pure mpihs_get_maxloc as opMaxloc+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The 'minimum' reduction operation (@MPI_MIN@).-{#fun pure mpihs_get_min as opMin {+} -> `Op'#}+{#fun pure mpihs_get_min as opMin+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The argmin reduction operation to find the minimum and its rank -- (@MPI_MINLOC@).-{#fun pure mpihs_get_minloc as opMinloc {+} -> `Op'#}+{#fun pure mpihs_get_minloc as opMinloc+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The (@product@) reduction operation (@MPI_PROD@).-{#fun pure mpihs_get_prod as opProd {+} -> `Op'#}+{#fun pure mpihs_get_prod as opProd+    {alloca- `Op' peekOp*+    } -> `()'#}  -- | The (@sum@) reduction operation (@MPI_SUM@).-{#fun pure mpihs_get_sum as opSum {+} -> `Op'#}+{#fun pure mpihs_get_sum as opSum+    {alloca- `Op' peekOp*+    } -> `()'#}  instance HasDatatype a => HasDatatype (Monoid.Product a) where   getDatatype = getDatatype @a@@ -714,7 +839,9 @@   -- | A null (invalid) request (@MPI_REQUEST_NULL@).-{#fun pure mpihs_get_request_null as requestNull {+} -> `Request'#}+{#fun mpihs_get_request_null as requestNull+    { alloca- `Request' peekRequest*+    } -> `()'#}   @@ -1021,8 +1148,8 @@     , fromCount `Count'     , withDatatype* %`Datatype'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to gather data from all processes and broadcast the result, -- and return a handle to the communication request (collective,@@ -1050,8 +1177,8 @@     , withDatatype* %`Datatype'     , withOp* %`Op'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to reduce data from all processes and broadcast the result, -- and return a handle to the communication request (collective,@@ -1081,8 +1208,8 @@     , fromCount `Count'     , withDatatype* %`Datatype'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to send data from all processes to all processes, and -- return a handle to the communication request (collective,@@ -1109,8 +1236,8 @@ -- The request must be freed by calling 'test', 'wait', or similar. {#fun Ibarrier as ^     { withComm* %`Comm'         -- ^ Communicator-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  {#fun Ibcast as ibcastTyped     { id `Ptr ()'@@ -1118,8 +1245,8 @@     , withDatatype* %`Datatype'     , fromRank `Rank'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to broadcast data from one process to all processes, and -- return a handle to the communication request (collective,@@ -1145,8 +1272,8 @@     , withDatatype* %`Datatype'     , withOp* %`Op'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to reduce data from all processes via an exclusive (prefix) -- scan, and return a handle to the communication request (collective,@@ -1183,8 +1310,8 @@     , withDatatype* %`Datatype'     , fromRank `Rank'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to gather data from all processes to the root process, and -- return a handle to the communication request (collective,@@ -1241,12 +1368,11 @@  iprobeBool :: Rank -> Tag -> Comm -> IO (Bool, Status) iprobeBool rank tag comm =-  withComm comm $ \comm' ->   do st <- Status <$> mallocForeignPtrBytes {#sizeof MPI_Status#}      withStatus st $ \st' ->        do alloca $ \flag ->-            do _ <- {#call mpihs_iprobe as iprobeBool_#}-                    (fromRank rank) (fromTag tag) comm' flag st'+            do _ <- {#call Iprobe as iprobeBool_#}+                    (fromRank rank) (fromTag tag) (fromComm comm) flag st'                b <- peekBool flag                return (b, st) @@ -1269,11 +1395,10 @@         -> Comm                 -- ^ Communicator         -> IO Bool              -- ^ Whether a message is available iprobe_ rank tag comm =-  withComm comm $ \comm' ->   do withStatusIgnore $ \st ->        do alloca $ \flag ->-            do _ <- {#call mpihs_iprobe as iprobe__#}-                    (fromRank rank) (fromTag tag) comm' flag st+            do _ <- {#call Iprobe as iprobe__#}+                    (fromRank rank) (fromTag tag) (fromComm comm) flag st                peekBool flag  {#fun Irecv as irecvTyped@@ -1283,8 +1408,8 @@     , fromRank `Rank'     , fromTag `Tag'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to receive a message, and return a handle to the -- communication request (non-blocking,@@ -1310,8 +1435,8 @@     , withOp* %`Op'     , fromRank `Rank'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to reduce data from all processes, and return a handle to -- the communication request (collective, non-blocking,@@ -1340,8 +1465,8 @@     , withDatatype* %`Datatype'     , withOp* %`Op'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to reduce data from all processes via an (inclusive) scan, -- and return a handle to the communication request (collective,@@ -1372,8 +1497,8 @@     , withDatatype* %`Datatype'     , fromRank `Rank'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to scatter data from the root process to all processes, and -- return a handle to the communication request (collective,@@ -1402,8 +1527,8 @@     , fromRank `Rank'     , fromTag `Tag'     , withComm* %`Comm'-    , +-    } -> `Request' return*#}+    , alloca- `Request' peekRequest*+    } -> `()' return*-#}  -- | Begin to send a message, and return a handle to the -- communication request (non-blocking,@@ -1521,12 +1646,11 @@  requestGetStatusBool :: Request -> IO (Bool, Status) requestGetStatusBool req =-  withRequest req $ \req' ->   alloca $ \flag ->   do st <- Status <$> mallocForeignPtrBytes {#sizeof MPI_Status#}      withStatus st $ \st' ->        do _ <- {#call Request_get_status as requestGetStatusBool_#}-               (castPtr req') flag st'+               (fromRequest req) flag st'           b <- peekBool flag           return (b, st) @@ -1539,26 +1663,16 @@                                       -- 'Nothing' requestGetStatus req = bool2maybe <$> requestGetStatusBool req --- {#fun Request_get_status as requestGetStatus_---     { withRequest* `Request'---     , alloca- `Bool' peekBool*---     , withStatusIgnore- `Status'---     } -> `()' return*-#}- -- | Check whether a communication has completed without freeing the -- communication request -- (@[MPI_Request_get_status](https://www.open-mpi.org/doc/current/man3/MPI_Request_get_status.3.php)@). -- This function does not return a status, which might be more -- efficient if the status is not needed.-requestGetStatus_ :: Request    -- ^ Communication request-                  -> IO Bool    -- ^ Whether the request had completed-requestGetStatus_ req =-  withRequest req $ \req' ->-  alloca $ \flag ->-  withStatusIgnore $ \st ->-  do _ <- {#call MPI_Request_get_status as requestGetStatus__#}-          (castPtr req') flag st-     peekBool flag+{#fun Request_get_status as requestGetStatus_+    { fromRequest `Request'+    , alloca- `Bool' peekBool*+    , withStatusIgnore- `Status'+    } -> `()' return*-#}  {#fun Scan as scanTyped     { id `Ptr ()'@@ -1731,25 +1845,16 @@                           -- else 'Nothing' test req = bool2maybe <$> testBool req --- {#fun Test as test_---     { withRequest* `Request'---     , alloca- `Bool' peekBool*---     , withStatusIgnore- `Status'---     } -> `()' return*-#}- -- | Check whether a communication has completed, and free the -- communication request if so -- (@[MPI_Test](https://www.open-mpi.org/doc/current/man3/MPI_Test.3.php)@). -- This function does not return a status, which might be more -- efficient if the status is not needed.-test_ :: Request                -- ^ Communication request-      -> IO Bool                -- ^ Whether the request had completed-test_ req =-  withRequest req $ \req' ->-  alloca $ \flag ->-  withStatusIgnore $ \st ->-  do _ <- {#call Test as test__#} req' flag st-     peekBool flag+{#fun Test as test_+    { withRequest* `Request'+    , alloca- `Bool' peekBool*+    , withStatusIgnore- `Status'+    } -> `()' return*-#}  -- | Wait for a communication request to complete, then free the --  request
+ lib/Control/Distributed/MPI/Storable.hs view
@@ -0,0 +1,397 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeApplications #-}++-- | Module: Control.Distributed.MPI.Storable+-- Description: Simplified MPI bindings with automatic serialization+--              based on Foreign.Storable+-- Copyright: (C) 2019 Erik Schnetter+-- License: Apache-2.0+-- Maintainer: Erik Schnetter <schnetter@gmail.com>+-- Stability: experimental+-- Portability: Requires an externally installed MPI library++module Control.Distributed.MPI.Storable+  ( -- * Types, and associated functions and constants+    MPIException(..)++    -- ** Communicators+  , Comm(..)+  , commSelf+  , commWorld++    -- ** Message sizes+  , Count(..)+  , fromCount+  , toCount++    -- ** Process ranks+  , Rank(..)+  , anySource+  , commRank+  , commSize+  , fromRank+  , rootRank+  , toRank++    -- ** Message status+  , Status(..)++    -- ** Message tags+  , Tag(..)+  , anyTag+  , fromTag+  , toTag+  , unitTag++  , Request++    -- * Functions++    -- ** Initialization and shutdown+  , abort+  , mainMPI++    -- ** Point-to-point (blocking)+  , recv+  , recv_+  , send+  , sendrecv+  , sendrecv_++    -- ** Point-to-point (non-blocking)+  , irecv+  , isend+  , test+  , test_+  , wait+  , wait_++    -- ** Collective (blocking)+  , barrier+  , bcastRecv+  , bcastSend++    -- ** Collective (non-blocking)+  , ibarrier+  , ibcastRecv+  , ibcastSend+  ) where++import Prelude hiding (init)++import Control.Concurrent+import Control.Exception+import Control.Monad+import Control.Monad.Loops+import qualified Data.ByteString as B+import qualified Data.ByteString.Unsafe as B+import Data.Typeable+import Foreign+import Foreign.C.Types+import qualified Foreign.Storable as Storable++import qualified Control.Distributed.MPI as MPI+import Control.Distributed.MPI+  ( Comm(..)+  , commSelf+  , commWorld+  , Count(..)+  , fromCount+  , toCount+  , Rank(..)+  , anySource+  , commRank+  , commSize+  , fromRank+  , rootRank+  , toRank+  , Tag(..)+  , anyTag+  , fromTag+  , toTag+  , unitTag+  , abort+  , barrier+  )++++-- Serialization, based on Data.Binary+type CanSerialize a = Storable.Storable a+serialize :: CanSerialize a => a -> IO B.ByteString+serialize x = do let len = Storable.sizeOf x+                 ptr <- malloc+                 Storable.poke ptr x+                 B.unsafePackMallocCStringLen (castPtr ptr, len)+deserialize :: CanSerialize a => B.ByteString -> IO a+deserialize bs = B.unsafeUseAsCStringLen bs $ \(ptr, _) -> peek (castPtr ptr)++++-- | Run the supplied Maybe computation repeatedly while it returns+-- Nothing. If it returns a value, then returns that value.+whileNothing :: Monad m => m (Maybe a) -> m () -> m a+whileNothing cond loop = go+  where go = do mx <- cond+                case mx of+                  Nothing -> do loop+                                go+                  Just x -> return x++++-- | Exception type indicating an error in a call to MPI+newtype MPIException = MPIException String+  deriving (Eq, Ord, Read, Show, Typeable)+instance Exception MPIException++mpiAssert :: Bool -> String -> IO ()+mpiAssert cond msg =+  do when (not cond) $ throw (MPIException msg)+     return ()++++data DidInit = DidInit | DidNotInit++initMPI :: IO DidInit+initMPI =+  do isInit <- MPI.initialized+     if isInit+       then return DidNotInit+       else do ts <- MPI.initThread MPI.ThreadMultiple+               mpiAssert (ts >= MPI.ThreadMultiple)+                 ("MPI.init: Insufficient thread support: requiring " +++                  show MPI.ThreadMultiple +++                  ", but MPI library provided only " ++ show ts)+               return DidInit++finalizeMPI :: DidInit -> IO ()+finalizeMPI DidInit =+  do isFinalized <- MPI.finalized+     if isFinalized+       then return ()+       else do MPI.finalize+finalizeMPI DidNotInit = return ()++-- | Convenience function to initialize and finalize MPI. This+-- initializes MPI with 'ThreadMultiple' thread support.+mainMPI :: IO () -- ^ action to run with MPI, typically the whole program+        -> IO ()+mainMPI action = bracket initMPI finalizeMPI (\_ -> action)++++-- | A communication request, usually created by a non-blocking+-- communication function.+newtype Request a = Request (MVar (Status, a))++-- | The status of a finished communication, indicating rank and tag+-- of the other communication end point.+data Status = Status { msgRank :: !Rank+                     , msgTag :: !Tag+                     }+  deriving (Eq, Ord, Read, Show)++++-- | Receive an object.+recv :: CanSerialize a+     => Rank                    -- ^ Source rank+     -> Tag                     -- ^ Source tag+     -> Comm                    -- ^ Communicator+     -> IO (Status, a)          -- ^ Message status and received object+recv recvrank recvtag comm =+  do status <- whileNothing (MPI.iprobe recvrank recvtag comm) yield+     source <- MPI.getSource status+     tag <- MPI.getTag status+     count <- MPI.getCount status MPI.datatypeByte+     let len = MPI.fromCount count+     ptr <- mallocBytes len+     buffer <- B.unsafePackMallocCStringLen (ptr, len)+     req <- MPI.irecv buffer source tag comm+     whileM_ (not <$> MPI.test_ req) yield+     recvobj <- deserialize buffer+     return (Status source tag, recvobj)++-- | Receive an object without returning a status.+recv_ :: CanSerialize a+      => Rank                   -- ^ Source rank+      -> Tag                    -- ^ Source tag+      -> Comm                   -- ^ Communicator+      -> IO a                   -- ^ Received object+recv_ recvrank recvtag comm =+  snd <$> recv recvrank recvtag comm++-- | Send an object.+send :: CanSerialize a+     => a                     -- ^ Object to send+     -> Rank                  -- ^ Destination rank+     -> Tag                   -- ^ Message tag+     -> Comm                  -- ^ Communicator+     -> IO ()+send sendobj sendrank sendtag comm =+  do sendbuf <- serialize sendobj+     -- Use 'unsafeUseAsCStringLen' to ensure 'sendbuf' is not freed+     -- too early+     B.unsafeUseAsCStringLen sendbuf $ \_ ->+       do req <- MPI.isend sendbuf sendrank sendtag comm+          whileM_ (not <$> MPI.test_ req) yield++-- | Send and receive objects simultaneously.+sendrecv :: (CanSerialize a, CanSerialize b)+         => a                   -- ^ Object to send+         -> Rank                -- ^ Destination rank+         -> Tag                 -- ^ Send message tag+         -> Rank                -- ^ Source rank+         -> Tag                 -- ^ Receive message tag+         -> Comm                -- ^ Communicator+         -> IO (Status, b)      -- ^ Message status and received object+sendrecv sendobj sendrank sendtag recvrank recvtag comm =+  do recvreq <- irecv recvrank recvtag comm+     send sendobj sendrank sendtag comm+     wait recvreq++-- | Send and receive objects simultaneously, without returning a+-- status for the received message.+sendrecv_ :: (CanSerialize a, CanSerialize b)+          => a                  -- ^ Object to send+          -> Rank               -- ^ Destination rank+          -> Tag                -- ^ Send message tag+          -> Rank               -- ^ Source rank+          -> Tag                -- ^ Receive message tag+          -> Comm               -- ^ Communicator+          -> IO b               -- ^ Received object+sendrecv_ sendobj sendrank sendtag recvrank recvtag comm =+  snd <$> sendrecv sendobj sendrank sendtag recvrank recvtag comm++-- | Begin to receive an object. Call `test` or `wait` to finish the+-- communication, and to obtain the received object.+irecv :: CanSerialize a+      => Rank                   -- ^ Source rank+      -> Tag                    -- ^ Source tag+      -> Comm                   -- ^ Communicator+      -> IO (Request a)         -- ^ Communication request+irecv recvrank recvtag comm =+  do result <- newEmptyMVar+     _ <- forkIO $+       do res <- recv recvrank recvtag comm+          putMVar result res+     return (Request result)++-- | Begin to send an object. Call 'test' or 'wait' to finish the+-- communication.+isend :: CanSerialize a+      => a                     -- ^ Object to send+      -> Rank                  -- ^ Destination rank+      -> Tag                   -- ^ Message tag+      -> Comm                  -- ^ Communicator+      -> IO (Request ())       -- ^ Communication request+isend sendobj sendrank sendtag comm =+  do result <- newEmptyMVar+     _ <- forkIO $ do send sendobj sendrank sendtag comm+                      putMVar result (Status sendrank sendtag, ())+     return (Request result)++-- | Check whether a communication has finished, and return the+-- communication result if so.+test :: Request a               -- ^ Communication request+     -> IO (Maybe (Status, a))  -- ^ 'Just' communication result, if+                                -- communication has finished, else 'Nothing'+test (Request result) = tryTakeMVar result++-- | Check whether a communication has finished, and return the+-- communication result if so, without returning a message status.+test_ :: Request a       -- ^ Communication request+      -> IO (Maybe a)    -- ^ 'Just' communication result, if+                         -- communication has finished, else 'Nothing'+test_ req = fmap snd <$> test req++-- | Wait for a communication to finish and return the communication+-- result.+wait :: Request a               -- ^ Communication request+     -> IO (Status, a)          -- ^ Message status and communication result+wait (Request result) = takeMVar result++-- | Wait for a communication to finish and return the communication+-- result, without returning a message status.+wait_ :: Request a              -- ^ Communication request+      -> IO a                   -- ^ Communication result+wait_ req = snd <$> wait req++++-- | Broadcast a message from one process (the "root") to all other+-- processes in the communicator. Call this function on all non-root+-- processes. Call 'bcastSend' instead on the root process.+bcastRecv :: CanSerialize a+          => Rank+          -> Comm+          -> IO a+bcastRecv root comm =+  do rank <- MPI.commRank comm+     mpiAssert (rank /= root) "bcastRecv: expected rank /= root"+     lenbuf <- mallocForeignPtr @CLong+     lenreq <- MPI.ibcast (lenbuf, 1::Int) root comm+     whileM_ (not <$> MPI.test_ lenreq) yield+     len <- withForeignPtr lenbuf peek+     ptr <- mallocBytes (fromIntegral len)+     recvbuf <- B.unsafePackMallocCStringLen (ptr, fromIntegral len)+     req <- MPI.ibcast recvbuf root comm               +     whileM_ (not <$> MPI.test_ req) yield+     recvobj <- deserialize recvbuf+     return recvobj++-- | Broadcast a message from one process (the "root") to all other+-- processes in the communicator. Call this function on the root+-- process. Call 'bcastRecv' instead on all non-root processes.+bcastSend :: CanSerialize a+          => a+          -> Rank+          -> Comm+          -> IO ()+bcastSend sendobj root comm =+  do rank <- MPI.commRank comm+     mpiAssert (rank == root) "bcastSend: expected rank == root"+     sendbuf <- serialize sendobj+     lenbuf <- mallocForeignPtr @CLong+     withForeignPtr lenbuf $ \ptr -> poke ptr (fromIntegral (B.length sendbuf))+     lenreq <- MPI.ibcast (lenbuf, 1::Int) root comm+     whileM_ (not <$> MPI.test_ lenreq) yield+     req <- MPI.ibcast sendbuf root comm+     whileM_ (not <$> MPI.test_ req) yield++ibcastRecv :: CanSerialize a+           => Rank+           -> Comm+           -> IO (Request a)+ibcastRecv root comm =+  do result <- newEmptyMVar+     _ <- forkIO $+       do recvobj <- bcastRecv root comm+          putMVar result (Status root MPI.anyTag, recvobj)+     return (Request result)++ibcastSend :: CanSerialize a+           => a+           -> Rank+           -> Comm+           -> IO (Request ())+ibcastSend sendobj root comm =+  do result <- newEmptyMVar+     _ <- forkIO $+       do bcastSend sendobj root comm+          putMVar result (Status root MPI.anyTag, ())+     return (Request result)++-- | Begin a barrier. Call 'test' or 'wait' to finish the+-- communication.+ibarrier :: Comm+         -> IO (Request ())+ibarrier comm =+  do result <- newEmptyMVar+     _ <- forkIO $+       do req <- MPI.ibarrier comm+          whileM_ (not <$> MPI.test_ req) yield+          putMVar result (Status MPI.anySource MPI.anyTag, ())+     return (Request result)
mpi-hs.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.1.+-- This file has been generated from package.yaml by hpack version 0.31.2. -- -- see: https://github.com/sol/hpack ----- hash: 2892e584ed19468e7f909cfad89e55d2e462d95a62b97faba37aa84634bfa800+-- hash: bb746d0a792e8c143d590f5127622e58947f2ebf3f393bca193a0d0a34446f72  name:           mpi-hs-version:        0.5.1.2+version:        0.5.2.0 synopsis:       MPI bindings for Haskell description:    MPI (the [Message Passing Interface](https://www.mpi-forum.org)) is                 widely used standard for distributed-memory programming on HPC (High@@ -56,11 +56,37 @@   type: git   location: https://github.com/eschnett/mpi-hs +flag mpich-macports+  description: Use MPICH on MacPorts+  manual: True+  default: False++flag mpich-ubuntu+  description: Use MPICH on Ubuntu+  manual: True+  default: False++flag openmpi-debian+  description: Use OpenMPI on Debian+  manual: True+  default: True++flag openmpi-macports+  description: Use OpenMPI on MacPorts+  manual: True+  default: True++flag openmpi-ubuntu+  description: Use OpenMPI on Ubuntu+  manual: True+  default: True+ library   exposed-modules:       Control.Distributed.MPI       Control.Distributed.MPI.Binary       Control.Distributed.MPI.Serialize+      Control.Distributed.MPI.Storable       Control.Distributed.MPI.Store   other-modules:       Paths_mpi_hs@@ -69,17 +95,8 @@   ghc-options: -Wall   include-dirs:       c/include-      /usr/lib/x86_64-linux-gnu/openmpi/include-      /opt/local/include/openmpi-mp-      /usr/lib/openmpi/include   c-sources:       c/src/mpihs.c-  extra-lib-dirs:-      /usr/lib/x86_64-linux-gnu/openmpi/lib-      /opt/local/lib/openmpi-mp-      /usr/lib/openmpi/lib-  extra-libraries:-      mpi   build-tools:       c2hs   build-depends:@@ -89,6 +106,41 @@     , cereal     , monad-loops     , store+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich   default-language: Haskell2010  executable example@@ -102,6 +154,41 @@       base     , binary     , mpi-hs+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich   default-language: Haskell2010  test-suite mpi-test@@ -116,6 +203,41 @@       base     , monad-loops     , mpi-hs+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich   default-language: Haskell2010  test-suite mpi-test-binary@@ -129,6 +251,41 @@   build-depends:       base     , mpi-hs+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich   default-language: Haskell2010  test-suite mpi-test-serialize@@ -142,8 +299,91 @@   build-depends:       base     , mpi-hs+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich   default-language: Haskell2010 +test-suite mpi-test-storable+  type: exitcode-stdio-1.0+  main-is: Main.hs+  other-modules:+      Paths_mpi_hs+  hs-source-dirs:+      tests/storable+  ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N+  build-depends:+      base+    , mpi-hs+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich+  default-language: Haskell2010+ test-suite mpi-test-store   type: exitcode-stdio-1.0   main-is: Main.hs@@ -155,6 +395,41 @@   build-depends:       base     , mpi-hs+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich   default-language: Haskell2010  benchmark mpi-hs-benchmarks@@ -169,4 +444,39 @@       base     , criterion     , mpi-hs+  if flag(openmpi-debian)+    include-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+        /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+        mpi+  if flag(openmpi-macports)+    include-dirs:+        /opt/local/include/openmpi-mp+    extra-lib-dirs:+        /opt/local/lib/openmpi-mp+    extra-libraries:+        mpi+  if flag(openmpi-ubuntu)+    include-dirs:+        /usr/lib/openmpi/include+    extra-lib-dirs:+        /usr/lib/openmpi/lib+    extra-libraries:+        mpi+  if flag(mpich-macports)+    include-dirs:+        /opt/local/include/mpich-gcc9+    extra-lib-dirs:+        /opt/local/lib/mpich-gcc9+    extra-libraries:+        mpi+  if flag(mpich-ubuntu)+    include-dirs:+        /usr/lib/mpich/include+    extra-lib-dirs:+        /usr/lib/mpich/lib+    extra-libraries:+        mpich   default-language: Haskell2010
package.yaml view
@@ -1,5 +1,5 @@ name: mpi-hs-version: '0.5.1.2'+version: '0.5.2.0' github: "eschnett/mpi-hs" license: Apache-2.0 author: "Erik Schnetter <schnetter@gmail.com>"@@ -35,6 +35,28 @@   [Stackage](https://www.stackage.org) should succeed -- if not, there   is an error in this package. +flags:+  openmpi-debian:+    description: Use OpenMPI on Debian+    manual: true+    default: true+  openmpi-macports:+    description: Use OpenMPI on MacPorts+    manual: true+    default: true+  openmpi-ubuntu:+    description: Use OpenMPI on Ubuntu+    manual: true+    default: true+  mpich-macports:+    description: Use MPICH on MacPorts+    manual: true+    default: false+  mpich-ubuntu:+    description: Use MPICH on Ubuntu+    manual: true+    default: false+ extra-source-files:   - LICENSE   - README.md@@ -61,16 +83,44 @@     - c/src/mpihs.c   include-dirs:     - c/include-    - /usr/lib/x86_64-linux-gnu/openmpi/include # Debian-    - /opt/local/include/openmpi-mp             # MacPorts-    - /usr/lib/openmpi/include                  # Ubuntu-  extra-lib-dirs:-    - /usr/lib/x86_64-linux-gnu/openmpi/lib # Debian-    - /opt/local/lib/openmpi-mp             # MacPorts-    - /usr/lib/openmpi/lib                  # Ubuntu-  extra-libraries:-    - mpi +when:+  - condition: flag(openmpi-debian)+    include-dirs:+      - /usr/lib/x86_64-linux-gnu/openmpi/include+    extra-lib-dirs:+      - /usr/lib/x86_64-linux-gnu/openmpi/lib+    extra-libraries:+      - mpi+  - condition: flag(openmpi-macports)+    include-dirs:+      - /opt/local/include/openmpi-mp+    extra-lib-dirs:+      - /opt/local/lib/openmpi-mp+    extra-libraries:+      - mpi+  - condition: flag(openmpi-ubuntu)+    include-dirs:+      - /usr/lib/openmpi/include+    extra-lib-dirs:+      - /usr/lib/openmpi/lib+    extra-libraries:+      - mpi+  - condition: flag(mpich-macports)+    include-dirs:+      - /opt/local/include/mpich-gcc9+    extra-lib-dirs:+      - /opt/local/lib/mpich-gcc9+    extra-libraries:+      - mpi+  - condition: flag(mpich-ubuntu)+    include-dirs:+      - /usr/lib/mpich/include+    extra-lib-dirs:+      - /usr/lib/mpich/lib+    extra-libraries:+      - mpich+ executables:   example:     source-dirs: src@@ -129,6 +179,20 @@       - -with-rtsopts=-N   mpi-test-serialize:     source-dirs: tests/serialize+    main: Main.hs+    dependencies:+      - base+      - mpi-hs+      # - tasty+      # - tasty-hunit+      # - tasty-hspec+      # - unix+    ghc-options:+      - -rtsopts+      - -threaded+      - -with-rtsopts=-N+  mpi-test-storable:+    source-dirs: tests/storable     main: Main.hs     dependencies:       - base
stack.yaml view
@@ -1,5 +1,6 @@ # Resolver to choose a 'specific' stackage snapshot or a compiler version.-resolver: lts-13.7+resolver: lts-14.4+# resolver: nightly-2019-09-02  # User packages to be built. packages:
tests/mpi/Main.hs view
@@ -122,21 +122,27 @@ pointToPoint = testGroup "point-to-point"   [ testCase "send and recv" $     do rank <- MPI.commRank MPI.commWorld-+       size <- MPI.commSize MPI.commWorld+               let msg = 42        buf <- mallocForeignPtr @CInt        withForeignPtr buf $ \ptr -> poke ptr msg--       MPI.send (buf, 1::Int) rank MPI.unitTag MPI.commWorld--       buf' <- mallocForeignPtr @CInt-       st <- MPI.recv (buf', 1::Int) rank MPI.unitTag MPI.commWorld-       msg' <- withForeignPtr buf' peek--       source <- MPI.getSource st-       tag <- MPI.getTag st-       count <- MPI.getCount st MPI.datatypeInt-       (msg' == msg && source == rank && tag == MPI.unitTag && count == 1) @? ""+       +       if rank + 1 < size+         then MPI.send (buf, 1::Int) (rank + 1) MPI.unitTag MPI.commWorld+         else return ()+       +       if rank - 1 >= 0 then+         do buf' <- mallocForeignPtr @CInt+            st <- MPI.recv (buf', 1::Int) (rank - 1) MPI.unitTag MPI.commWorld+            msg' <- withForeignPtr buf' peek+            +            source <- MPI.getSource st+            tag <- MPI.getTag st+            count <- MPI.getCount st MPI.datatypeInt+            (msg' == msg && source == rank - 1 && tag == MPI.unitTag &&+             count == 1) @? ""+         else True @? ""   , testCase "sendrecv" $     do rank <- MPI.commRank MPI.commWorld        size <- MPI.commSize MPI.commWorld
+ tests/storable/Main.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++import Data.String+import Foreign+import System.IO+import System.Exit++import qualified Control.Distributed.MPI.Storable as MPI++default (Int)++++--------------------------------------------------------------------------------++infix 1 @?+(@?) :: Bool -> String -> IO ()+x @? msg = if not x then die msg else return ()++infix 1 @?=+(@?=) :: Eq a => a -> a -> IO ()+x @?= y = x == y @? "test failed"++++type TestTree = IO ()++testCase :: String -> IO () -> TestTree+testCase name test =+  do rank <- MPI.commRank MPI.commWorld+     if rank == 0+       then do putStrLn $ "  " ++ name ++ "..."+               hFlush stdout+       else return ()+     MPI.barrier MPI.commWorld+     test+     MPI.barrier MPI.commWorld++++testGroup :: String -> [TestTree] -> TestTree+testGroup name cases =+  do rank <- MPI.commRank MPI.commWorld+     if rank == 0+       then do putStrLn $ name ++ ":"+               hFlush stdout+       else return ()+     sequence_ cases++++defaultMain :: TestTree -> IO ()+defaultMain tree =+  do rank <- MPI.commRank MPI.commWorld+     size <- MPI.commSize MPI.commWorld+     if rank == 0+       then do putStrLn $ "MPI Tests: running on " ++ show size ++ " processes"+               hFlush stdout+       else return ()+     tree++++--------------------------------------------------------------------------------++++main :: IO ()+main = MPI.mainMPI $ defaultMain tests++tests :: TestTree+tests = testGroup "MPI"+  [ rankSize+  , pointToPoint+  , pointToPointNonBlocking+  , collective+  , collectiveNonBlocking+  ]++++data V16 a = V16 a a a a a a a a a a a a a a a a+  deriving (Eq, Ord, Read, Show)++instance Storable a => Storable (V16 a) where+  sizeOf _ = 16 * sizeOf (undefined::a)+  alignment _ = alignment (undefined::a)+  poke ptr (V16 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf) =+    do pokeElemOff (castPtr ptr) 0x0 c0+       pokeElemOff (castPtr ptr) 0x1 c1+       pokeElemOff (castPtr ptr) 0x2 c2+       pokeElemOff (castPtr ptr) 0x3 c3+       pokeElemOff (castPtr ptr) 0x4 c4+       pokeElemOff (castPtr ptr) 0x5 c5+       pokeElemOff (castPtr ptr) 0x6 c6+       pokeElemOff (castPtr ptr) 0x7 c7+       pokeElemOff (castPtr ptr) 0x8 c8+       pokeElemOff (castPtr ptr) 0x9 c9+       pokeElemOff (castPtr ptr) 0xa ca+       pokeElemOff (castPtr ptr) 0xb cb+       pokeElemOff (castPtr ptr) 0xc cc+       pokeElemOff (castPtr ptr) 0xd cd+       pokeElemOff (castPtr ptr) 0xe ce+       pokeElemOff (castPtr ptr) 0xf cf+  peek ptr = do c0 <- peekElemOff (castPtr ptr) 0x0+                c1 <- peekElemOff (castPtr ptr) 0x1+                c2 <- peekElemOff (castPtr ptr) 0x2+                c3 <- peekElemOff (castPtr ptr) 0x3+                c4 <- peekElemOff (castPtr ptr) 0x4+                c5 <- peekElemOff (castPtr ptr) 0x5+                c6 <- peekElemOff (castPtr ptr) 0x6+                c7 <- peekElemOff (castPtr ptr) 0x7+                c8 <- peekElemOff (castPtr ptr) 0x8+                c9 <- peekElemOff (castPtr ptr) 0x9+                ca <- peekElemOff (castPtr ptr) 0xa+                cb <- peekElemOff (castPtr ptr) 0xb+                cc <- peekElemOff (castPtr ptr) 0xc+                cd <- peekElemOff (castPtr ptr) 0xd+                ce <- peekElemOff (castPtr ptr) 0xe+                cf <- peekElemOff (castPtr ptr) 0xf+                return (V16 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf)++type FixedString = V16 Char++instance IsString FixedString where+  fromString s =+    let c0:c1:c2:c3:c4:c5:c6:c7:c8:c9:ca:cb:cc:cd:ce:cf:_ = s ++ repeat '\NUL'+    in (V16 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf)++++rankSize :: TestTree+rankSize = testGroup "rank and size"+  [ testCase "commSelf" $+    do rank <- MPI.commRank MPI.commSelf+       size <- MPI.commSize MPI.commSelf+       rank == 0 && size == 1 @? ""+  , testCase "commWorld" $+    do rank <- MPI.commRank MPI.commWorld+       size <- MPI.commSize MPI.commWorld+       rank >= 0 && rank < size @? ""+  ]++++pointToPoint :: TestTree+pointToPoint = testGroup "point-to-point"+  [ testCase "sendrecv" $+    do rank <- MPI.commRank MPI.commWorld+       size <- MPI.commSize MPI.commWorld+       let sendmsg :: FixedString = "Hello, World!"+       let sendrank = (rank + 1) `mod` size+       let recvrank = (rank - 1) `mod` size+       (status, recvmsg :: FixedString) <-+         MPI.sendrecv sendmsg sendrank MPI.unitTag recvrank MPI.unitTag+         MPI.commWorld+       (recvmsg == sendmsg &&+        MPI.msgRank status == recvrank &&+        MPI.msgTag status == MPI.unitTag) @? ""+  ]++++pointToPointNonBlocking :: TestTree+pointToPointNonBlocking = testGroup "point-to-point non-blocking"+  [ testCase "send and recv" $+    do rank <- MPI.commRank MPI.commWorld+       size <- MPI.commSize MPI.commWorld+       let sendmsg :: FixedString = "Hello, World!"+       let sendrank = (rank + 1) `mod` size+       sendreq <- MPI.isend sendmsg sendrank MPI.unitTag MPI.commWorld+       let recvrank = (rank - 1) `mod` size+       recvreq <- MPI.irecv recvrank MPI.unitTag MPI.commWorld+       (sendstatus, ()) <- MPI.wait sendreq+       (recvstatus, recvmsg :: FixedString) <- MPI.wait recvreq+       (recvmsg == sendmsg &&+        MPI.msgRank sendstatus == sendrank &&+        MPI.msgTag sendstatus == MPI.unitTag &&+        MPI.msgRank recvstatus == recvrank &&+        MPI.msgTag recvstatus == MPI.unitTag) @? ""+  ]++++collective :: TestTree+collective = testGroup "collective"+  [ testCase "barrier" $+    do MPI.barrier MPI.commWorld+  , testCase "bcast" $+    do rank <- MPI.commRank MPI.commWorld+       let sendmsg :: FixedString = "Hello, World!"+       recvmsg :: FixedString <-+         if rank == MPI.rootRank+         then do MPI.bcastSend sendmsg MPI.rootRank MPI.commWorld+                 return sendmsg+         else do MPI.bcastRecv MPI.rootRank MPI.commWorld+       recvmsg == sendmsg @? ""+  ]++++collectiveNonBlocking :: TestTree+collectiveNonBlocking = testGroup "collective non-blocking"+  [ testCase "barrier" $+    do req <- MPI.ibarrier MPI.commWorld+       MPI.wait_ req+  , testCase "bcast" $+    do rank <- MPI.commRank MPI.commWorld+       let sendmsg :: FixedString = "Hello, World!"+       recvmsg :: FixedString <-+         if rank == MPI.rootRank+         then do req <- MPI.ibcastSend sendmsg MPI.rootRank MPI.commWorld+                 MPI.wait_ req+                 return sendmsg+         else do req <- MPI.ibcastRecv MPI.rootRank MPI.commWorld+                 MPI.wait_ req+       recvmsg == sendmsg @? ""+  ]