Safe Haskell | None |
---|
Data.Array.Parallel.Unlifted.Distributed.Primitive
Description
Standard combinators for distributed types.
- data Gang
- gangSize :: Gang -> Int
- seqGang :: Gang -> Gang
- forkGang :: Int -> IO Gang
- theGang :: Gang
- class DT a where
- data Dist a
- data MDist a :: * -> *
- indexD :: String -> Dist a -> Int -> a
- newMD :: Gang -> ST s (MDist a s)
- readMD :: MDist a s -> Int -> ST s a
- writeMD :: MDist a s -> Int -> a -> ST s ()
- unsafeFreezeMD :: MDist a s -> ST s (Dist a)
- deepSeqD :: a -> b -> b
- sizeD :: Dist a -> Int
- sizeMD :: MDist a s -> Int
- measureD :: a -> String
- newD :: DT a => Gang -> (forall s. MDist a s -> ST s ()) -> Dist a
- debugD :: DT a => Dist a -> String
- checkGangD :: DT a => String -> Gang -> Dist a -> b -> b
- generateD :: DT a => What -> Gang -> (Int -> a) -> Dist a
- generateD_cheap :: DT a => What -> Gang -> (Int -> a) -> Dist a
- imapD' :: (DT a, DT b) => What -> Gang -> (Int -> a -> b) -> Dist a -> Dist b
- foldD :: DT a => What -> Gang -> (a -> a -> a) -> Dist a -> a
- scanD :: forall a. DT a => What -> Gang -> (a -> a -> a) -> a -> Dist a -> (Dist a, a)
The Gang
DPH programs use this single, shared gang of threads. The gang exists at top level, and is initialised at program start.
The vectoriser guarantees that the gang is only used by a single computation at a time. This is true because the program produced by the vector only uses flat parallelism, so parallel computations don't invoke further parallel computations. If the vectorised program tries to use nested parallelism then there is a bug in the vectoriser, and the code will run sequentially.
Distributed Types
class DT a where
Class of distributable types. Instances of DT
can be
distributed across all workers of a Gang
.
All such types must be hyperstrict as we do not want to pass thunks
into distributed computations.
Methods
indexD :: String -> Dist a -> Int -> a
Extract a single element of an immutable distributed value.
newMD :: Gang -> ST s (MDist a s)
Create an unitialised distributed value for the given Gang
.
The gang is used (only) to know how many elements are needed
in the distributed value.
readMD :: MDist a s -> Int -> ST s a
Extract an element from a mutable distributed value.
writeMD :: MDist a s -> Int -> a -> ST s ()
Write an element of a mutable distributed value.
unsafeFreezeMD :: MDist a s -> ST s (Dist a)
Unsafely freeze a mutable distributed value.
deepSeqD :: a -> b -> b
Ensure a distributed value is fully evaluated.
Number of elements in the distributed value.
- For debugging only, as code shouldn't be sensitive to the return value.
Number of elements in the mutable distributed value.
- For debugging only, as code shouldn't be sensitive to the return value.
Show a distributed value.
- For debugging only.
newD :: DT a => Gang -> (forall s. MDist a s -> ST s ()) -> Dist a
Given a computation that can write its result to a mutable distributed value, run the computation to generate an immutable distributed value.
checkGangD :: DT a => String -> Gang -> Dist a -> b -> b
Check that the sizes of the Gang
and of the distributed value match.
Primitive Distributed Operators.
Create a distributed value, given a function to create the instance for each thread.
Create a distributed value, but do it sequentially.
This function is used when we want to operate on a distributed value, but there isn't much data involved. For example, if we want to distribute a single integer to each thread, then there's no need to fire up the gang for this.
imapD' :: (DT a, DT b) => What -> Gang -> (Int -> a -> b) -> Dist a -> Dist b
Map a function across all elements of a distributed value. The worker function also gets the current thread index.