edenmodules-1.1.0.1: Semi-explicit parallel programming library

Portabilitynot portable
Stabilitybeta
Maintainereden@mathematik.uni-marburg.de
Safe HaskellSafe-Infered

Control.Parallel.Eden

Contents

Description

Provides functions for semi-explicit distributed functional programming. Defines high-level coordination concepts via Prim.Op.s (which are wrapped inside ParPrim.hs).

Depends on GHC. Using standard GHC, you will get a threaded simulation of Eden. Use the special GHC-Eden compiler from http://www.mathematik.uni-marburg.de/~eden for parallel execution with distributed heaps.

Eden Group Marburg ( http://www.mathematik.uni-marburg.de/~eden )

Synopsis

Basic Eden

Process definition

data Process a b Source

Process abstractions of type Process a b can be created with function process. Process abstractions define remote functions similar to lambda abstractions, which define local functions.

processSource

Arguments

:: (Trans a, Trans b) 
=> (a -> b)

Input function

-> Process a b

Process abstraction from input function

Creates a process abstraction Process a b from a function a -> b.

rfiSource

Arguments

:: Trans b 
=> (a -> b)

Input function

-> a

Offline input

-> Process () b

Process abstraction; process takes unit input

Remote function invocation, evaluating a function application remotely without communicating the input argument

Parallel Action

data PA a Source

Instances

runPA :: PA a -> aSource

Process instantiation

The operator # is the standard operator for process instantiation in Eden. Similar to applying a function f to an argument x (f x), it instantiates a process for f with the argument x (process f # x). The computation is the same from a denotational point of view. The operational semantics, however, is different because the operation is executed remotely. If you prefer to expose the side effects of such an operation explicitly with the IO-Monad wrapped in the parallel action monad, you can use function instantiate (p # x = runPA (instantiate p x)). It is non-trivial to instantiate a list of processes such that all instantiations take place immediately. Therefore Eden provides function spawn which wraps this commonly used pattern.

The Eden runtime system handles process placementfor the basic instantiation functions. In the default setting, process placement is done round robin, where the distribution is decided locally by each machine. The runtime option qrnd enables random process placement. Eden further offers functions instantiateAt and spawnAt with an additional placement parameter. instantiateAt i instantiates the process at machine i mod noPe for a positive i and instantiateAt 0 = instantiate. This is similar for spawnAt.

All instantiation functions are also provided in versions which take functions instead of process abstractions as parameters. In this case, the process abstractions are implicitly created prior to instantiation. The function version of , the names of other instantiation functions of this kind contain an F.

(#)Source

Arguments

:: (Trans a, Trans b) 
=> Process a b

Process abstraction

-> a

Process input

-> b

Process output

Instantiates a process abstraction on a remote machine, sends the input of type a and returns the process output of type b.

($#)Source

Arguments

:: (Trans a, Trans b) 
=> (a -> b)

Process abstraction

-> a

Process input

-> b

Process output

Instantiates a process defined by the given function on a remote machine, sends the input of type a and returns the process output of type b.

spawnSource

Arguments

:: (Trans a, Trans b) 
=> [Process a b]

Process abstractions

-> [a]

Process inputs

-> [b]

Process outputs

Instantiates a list of process abstractions on remote machines with corresponding inputs of type a and returns the processes outputs, each of type b. The i-th process is supplied with the i-th input generating the i-th output. The number of processes (= length of output list) is determined by the length of the shorter input list (thus one list may be infinite).

spawnFSource

Arguments

:: (Trans a, Trans b) 
=> [a -> b]

Process abstractions

-> [a]

Process inputs

-> [b]

Process outputs

Instantiates processes defined by the given list of functions on remote machines with corresponding inputs of type a and returns the processes outputs, each of type b. The i-th process is supplied with the i-th input generating the i-th output. The number of processes (= length of output list) is determined by the length of the shorter input list (thus one list may be infinite).

spawnAtSource

Arguments

:: (Trans a, Trans b) 
=> [Int]

Machine numbers

-> [Process a b]

Process abstractions

-> [a]

Process inputs

-> [b]

Process outputs

Same as spawn , but with an additional [Int] argument that specifies where to instantiate the processes.

spawnFAtSource

Arguments

:: (Trans a, Trans b) 
=> [Int]

Machine numbers

-> [a -> b]

Process abstractions

-> [a]

Process inputs

-> [b]

Process outputs

Same as spawnF , but with an additional [Int] argument that specifies where to instantiate the processes.

instantiateSource

Arguments

:: (Trans a, Trans b) 
=> Process a b

Process abstraction

-> a

Process input

-> PA b

Process output

Instantiates a process on a remote machine, sends the input of type a and returns the process output of type b in the parallel action monad, thus it can be combined to a larger parallel action.

instantiateFSource

Arguments

:: (Trans a, Trans b) 
=> (a -> b)

Function for Process

-> a

Process input

-> PA b

Process output

Instantiates a process defined by the given function on a remote machine, sends the input of type a and returns the process output of type b in the parallel action monad, thus it can be combined to a larger parallel action.

instantiateAtSource

Arguments

:: (Trans a, Trans b) 
=> Int

Machine number

-> Process a b

Process abstraction

-> a

Process input

-> PA b

Process output

Instantiation with explicit placement (see instantiate).

instantiateFAtSource

Arguments

:: (Trans a, Trans b) 
=> Int

Machine number

-> (a -> b)

Process abstraction

-> a

Process input

-> PA b

Process output

Instantiation with explicit placement (see instantiate).

Overloaded Communication

Communication of process inputs and outputs is done implicitly by the Eden runtime system. The sent data has to be transmissible i.e. it has to be an instance of type class Trans. All data will be evaluated to normal form before it is sent in one message. Communication is overloaded for lists which are sent as streams element by element, and for tuples which are sent using concurrent channel connections for each tuple element. Note that lists in tuples are streamed concurrently, but a list of tuples is streamed element-wise, with each tuple elements evaluated as a whole. The inner list of nested lists will also be sent in one packet.

class NFData a => Trans a whereSource

Trans class: overloads communication for streams and tuples. You need to declare normal-form evaluation in an instance declaration of NFData. Use the default implementation for write and createComm for instances of Trans.

Methods

write :: a -> IO ()Source

createComm :: IO (ChanName a, a)Source

Instances

Trans Bool 
Trans Char 
Trans Double 
Trans Float 
Trans Int 
Trans Integer 
Trans () 
Trans a => Trans [a] 
Trans a => Trans (Maybe a) 
(NFData a, Trans a) => Trans (Comm a) 
(Trans a, Trans b) => Trans (a, b) 
(Trans a, Trans b, Trans c) => Trans (a, b, c) 
(Trans a, Trans b, Trans c, Trans d) => Trans (a, b, c, d) 
(Trans a, Trans b, Trans c, Trans d, Trans e) => Trans (a, b, c, d, e) 
(Trans a, Trans b, Trans c, Trans d, Trans e, Trans f) => Trans (a, b, c, d, e, f) 
(Trans a, Trans b, Trans c, Trans d, Trans e, Trans f, Trans g) => Trans (a, b, c, d, e, f, g) 
(Trans a, Trans b, Trans c, Trans d, Trans e, Trans f, Trans g, Trans h) => Trans (a, b, c, d, e, f, g, h) 
(Trans a, Trans b, Trans c, Trans d, Trans e, Trans f, Trans g, Trans h, Trans i) => Trans (a, b, c, d, e, f, g, h, i) 

Explicit placement

noPe :: IntSource

Number of (logical) machines in the system

selfPe :: IntSource

Local machine number (ranges from 1 to noPe)

type Places = [Int]Source

Places where to instantiate lists of processes

Remote Data

A remote data handle RD a represents data of type a which may be located on a remote machine. Such a handle is very small and can be passed via intermediate machines with only little communication overhead. You can create a remote data using the function release and access a remote value using the function fetch.

Notice that a remote value may only be fetched exactly once!

releaseSource

Arguments

:: Trans a 
=> a

The original data

-> RD a

The Remote Data handle

Converts local data into corresponding remote data.

releasePASource

Arguments

:: Trans a 
=> a

The original data

-> PA (RD a)

The Remote Data handle

Converts local data into corresponding remote data. The result is in the parallel action monad and can be combined to a larger parallel action.

fetchSource

Arguments

:: Trans a 
=> RD a

The Remote Data handle

-> a

The original data

This establishes a direct connection to the process which released the data in the first place. Notice that a remote value may only be fetched exactly once!

fetchPA :: Trans a => RD a -> PA aSource

This establishes a direct connection to the process which released the data in the first place. The result is in the parallel action monad and can be combined to a larger parallel action. Notice that you have to fetch a remote value exactly once!

releaseAllSource

Arguments

:: Trans a 
=> [a]

The original data

-> [RD a]

The Remote Data handles, one for each list element

Transforms a list of local data into a corresponding remote data list.

fetchAllSource

Arguments

:: Trans a 
=> [RD a]

The Remote Data handles

-> [a]

The original data

Transforms a list of remote data into a corresponding local data list. map fetch would wait for each list element until fetching the next one. Function fetchAll blocks only on partial defined list structure, not on content.

liftRDSource

Arguments

:: (Trans a, Trans b) 
=> (a -> b)

Function to be lifted

-> RD a

Remote input

-> RD b

Remote output

Function liftRD is used to lift functions acting on normal data to function performing the same computation on Remote Data.

liftRD2Source

Arguments

:: (Trans a, Trans b, Trans c) 
=> (a -> b -> c)

Function to be lifted

-> RD a

First remote input

-> RD b

Second remote input

-> RD c

Remote output

see liftRD

liftRD3 :: (Trans a, Trans b, Trans c, Trans d) => (a -> b -> c -> d) -> RD a -> RD b -> RD c -> RD dSource

see liftRD

liftRD4 :: (Trans a, Trans b, Trans c, Trans d, Trans e) => (a -> b -> c -> d -> e) -> RD a -> RD b -> RD c -> RD d -> RD eSource

see liftRD

Dynamic Channels

type ChanName a = Comm aSource

A channel name ChanName a is a handle for a reply channel. The channel can be created with the function new and you can connect to such a channel with the function parfill.

newSource

Arguments

:: Trans a 
=> (ChanName a -> a -> b)

Parameter function that takes a channel name and a substitute for the lazily received value.

-> b

Forwarded result

A channel can be created with the function new (this is an unsafe side effect!). It takes a function whose first parameter is the channel name ChanName a and whose second parameter is the value of type a that will be received lazily in the future. The ChanName and the value of type a can be used in the body of the parameter function to create the output of type b. The output of the parameter function will be forwarded to the output of new .

Example: new (channame val -> (channame,val)) returns the tuple (channame, value) .

parfillSource

Arguments

:: Trans a 
=> ChanName a

ChanName to connect with

-> a

Data that will be send

-> b

Forwarded to result

-> b

Result (available after sending)

You can connect to a reply channel with function parfill (this is an unsafe side effect!). The first parameter is the name of the channel, the second parameter is the value to be send. The third parameter will be the functions result after the concurrent sending operation is initiated. The sending operation will be triggered as soon as the result of type b is demanded. Take care not to make the result of parfill depend on the sent value, as this will create a deadlock.

Nondeterminism

mergeSource

Arguments

:: [[a]]

Input lists

-> [a]

Nondeterministically merged output list

Non-deterministically merges a list of lists (usually input streams) into a single list. The order of the output list is determined by the availability of the inner lists constructors. (Function merge is defined using Concurrent Haskell's function nmergeIO)

mergeProcSource

Arguments

:: [[a]]

Input lists

-> [a]

Nondeterministically merged output list

same as merge

Deprecated legacy code for Eden 5

data Lift a Source

Constructors

Lift a 

deLift :: Lift a -> aSource

createProcess :: (Trans a, Trans b) => Process a b -> a -> Lift bSource

cpAt :: (Trans a, Trans b) => Int -> Process a b -> a -> Lift bSource

Reexported functions from Control.Deepseq

class NFData a where

A class of types that can be fully evaluated.

Methods

rnf :: a -> ()

rnf should reduce its argument to normal form (that is, fully evaluate all sub-components), and then return '()'.

The default implementation of rnf is

 rnf a = a `seq` ()

which may be convenient when defining instances for data types with no unevaluated fields (e.g. enumerations).

Instances

NFData Bool 
NFData Char 
NFData Double 
NFData Float 
NFData Int 
NFData Int8 
NFData Int16 
NFData Int32 
NFData Int64 
NFData Integer 
NFData Word 
NFData Word8 
NFData Word16 
NFData Word32 
NFData Word64 
NFData () 
NFData Version 
NFData a => NFData [a] 
(Integral a, NFData a) => NFData (Ratio a) 
NFData (Fixed a) 
(RealFloat a, NFData a) => NFData (Complex a) 
NFData a => NFData (Maybe a) 
NFData (ChanName' a) 
NFData (Comm a) 
NFData (Comm a) 
NFData (a -> b)

This instance is for convenience and consistency with seq. This assumes that WHNF is equivalent to NF for functions.

(NFData a, NFData b) => NFData (Either a b) 
(NFData a, NFData b) => NFData (a, b) 
(Ix a, NFData a, NFData b) => NFData (Array a b) 
(NFData k, NFData a) => NFData (Map k a) 
(NFData a, NFData b, NFData c) => NFData (a, b, c) 
(NFData a, NFData b, NFData c, NFData d) => NFData (a, b, c, d) 
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5) => NFData (a1, a2, a3, a4, a5) 
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6) => NFData (a1, a2, a3, a4, a5, a6) 
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7) => NFData (a1, a2, a3, a4, a5, a6, a7) 
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8) => NFData (a1, a2, a3, a4, a5, a6, a7, a8) 
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8, NFData a9) => NFData (a1, a2, a3, a4, a5, a6, a7, a8, a9) 

Reexported functions from Control.Seq (strategies differ from those in Control.Parallel!)

type Strategy a = a -> ()

The type Strategy a is a -> (). Thus, a strategy is a function whose sole purpose it is to evaluate its argument (either in full or in part).

using :: a -> Strategy a -> a

Evaluate a value using the given strategy.

r0 :: Strategy a

r0 performs *no* evaluation.

rseq :: Strategy a

rseq evaluates its argument to weak head normal form.

rdeepseq :: NFData a => Strategy a

rdeepseq fully evaluates its argument. Relies on class NFData from module Control.DeepSeq.

seqList :: Strategy a -> Strategy [a]

Evaluate each element of a list according to the given strategy. This function is a specialisation of seqFoldable to lists.

seqFoldable :: Foldable t => Strategy a -> Strategy (t a)

Evaluate the elements of a foldable data structure according to the given strategy.

Reexported functions from Control.Parallel

pseq :: a -> b -> b

Semantically identical to seq, but with a subtle operational difference: seq is strict in both its arguments, so the compiler may, for example, rearrange a `seq` b into b `seq` a `seq` b. This is normally no problem when using seq to express strictness, but it can be a problem when annotating code for parallelism, because we need more control over the order of evaluation; we may want to evaluate a before b, because we know that b has already been sparked in parallel with par.

This is why we have pseq. In contrast to seq, pseq is only strict in its first argument (as far as the compiler is concerned), which restricts the transformations that the compiler can do, and ensures that the user can retain control of the evaluation order.