{-# LANGUAGE CPP, BangPatterns, ForeignFunctionInterface, MagicHash, UnboxedTuples #-} ----------------------------------------------------------------------------- -- | -- Module : Control.Parallel.Eden.ParPrim -- Copyright : (c) Philipps Universitaet Marburg 2005-2010 -- License : BSD-style (see the file LICENSE) -- -- Maintainer : eden@mathematik.uni-marburg.de -- Stability : beta -- Portability : not portable -- -- Provides primitive functions for explicit distributed functional programming. -- Base module, importing PrimOps => exporting IO actions -- -- Depends on GHC. Using standard GHC, you will get a threaded simulation of the -- parallel primitives. -- 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 ) -- ----------------------------------------------- #if defined(NOT_PARALLEL) #warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\ BUILDING A CONCURRENT HASKELL SIMULATION OF THE PARALLEL PRIMITIVES,\ DON'T EXPECT BIG SPEEDUPS! USE THE EDEN VERSION OF GHC FROM \ http://www.mathematik.uni-marburg.de/~eden \ FOR A PARALLEL BUILD.\ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' #ifndef __GLASGOW_HASKELL__ #error Need GHC to compile this simulation. #endif module Control.Parallel.Eden.ParPrim(module Control.Parallel.Eden.ParPrimConcHs) where import Control.Parallel.Eden.ParPrimConcHs #else -- whole rest of the file module Control.Parallel.Eden.ParPrim( noPe, selfPe -- system information :: Int , ChanName' -- primitive channels (abstract in Eden module and outside) , fork -- forking conc. threads :: IO () -> IO () , createC -- creating placeholders :: IO (ChanName' a, a) , connectToPort -- set thread's receiver :: ChanName' a -> IO () , sendData -- sending data to recv. :: Mode -> a -> IO () , Mode(..) -- send modes: implemented: -- 1 - connect (no graph needed) -- 2 - stream (list element) -- 3 - single (single value) -- 4 - rFork (receiver creates a thread, different ports) -- additional payload (currently only for rFork) in high bits ) where import GHC.IO(IO(..)) import GHC.Base(Int#, Int(..), (+#), fork#, expectData#, connectToPort#, sendData# ) import Foreign.C(CInt) import GHC.Ptr(Ptr) import Foreign.Storable(Storable(peek)) ---------------------------------------------------------- -- IO wrappers for primitive operations: -- -- all primitives are implemented out-of-line, -- wrappers should all be of type * -> IO (...) -- -- (eden implementation can work with unsafePerformIO) --------- -- system information {-# NOINLINE noPe #-} noPe :: IO Int {-# NOINLINE selfPe #-} selfPe :: IO Int foreign import ccall "&nPEs" nPEs :: Ptr CInt foreign import ccall "&thisPE" thisPE :: Ptr CInt noPe = do n <- peek nPEs return (fromIntegral n) selfPe = do n <- peek thisPE return (fromIntegral n) ------------------------- -- not for export, only abstract type visible outside data ChanName' a = Chan Int# Int# Int# deriving Show -- tweaking fork primop from concurrent haskell... (not returning threadID) {-# NOINLINE fork #-} fork :: IO () -> IO () fork action = IO (\s -> case (fork# action s) of (# s' , _ #) -> (# s' , () #) ) -- creation of one placeholder and one new inport {-# NOINLINE createC #-} -- returns consistent channel type (channel of same type as data) createC :: IO ( ChanName' a, a ) createC = IO (\s -> case (expectData# s) of (# s',i,p, bh #) -> case selfPe_ s' of (# s'', I# pe #) -> (# s'',(Chan pe p i, bh) #) ) where (IO selfPe_) = selfPe -- TODO: wrap creation of several channels in RTS? (see eden5::createDC# ) -- (would save foreign call overhead, but hard-wire more into RTS) {-# NOINLINE connectToPort #-} connectToPort_ :: Int# -> Int# -> Int# -> IO () connectToPort_ pe proc i = IO (\s -> case (connectToPort# pe proc i s) of s' -> (# s', () #) ) connectToPort :: ChanName' a -> IO () connectToPort (Chan p proc i) = connectToPort_ p proc i -- send modes for sendData data Mode = Connect -- announce sender at receiver side (no graph needed) | Data -- data to send is single value | Stream -- data to send is element of a list/stream | Instantiate Int -- data is IO(), receiver to create a thread for it decodeMode :: Mode -> Int decodeMode Connect = 1 decodeMode Stream = 2 decodeMode Data = 3 decodeMode (Instantiate n) = let k = 4 + n*8 in -- k `seq` -- needed to pass NF to PrimOp? k -- decodeMode other = error "sendData: no such mode" {-# NOINLINE sendData #-} sendData :: Mode -> a -> IO () sendData mode d = IO (\s -> case (sendData# m d s) of s' -> (# s', () #) ) where !(I# m) = decodeMode mode #endif --NOT_PARALLEL