/hdph/src/Test/HdpH/sumeuler.hs
http://github.com/PatrickMaier/HdpH · Haskell · 334 lines · 234 code · 62 blank · 38 comment · 14 complexity · 0c898d7b45efd3389a4dc939d91b2ab1 MD5 · raw file
- -- Sum of totients in HdpH
- --
- -- Author: Patrick Maier
- -----------------------------------------------------------------------------
- {-# LANGUAGE FlexibleInstances #-} -- req'd for some ToClosure instances
- {-# LANGUAGE TemplateHaskell #-} -- req'd for mkClosure, etc
- {-# OPTIONS_GHC -fno-warn-orphans #-}
- module Main where
- import Prelude
- import Control.Exception (evaluate)
- import Control.Monad (when, (<=<))
- import Data.List (stripPrefix)
- import Data.Functor ((<$>))
- import Data.List (transpose)
- import Data.Monoid (mconcat)
- import Data.Time.Clock (NominalDiffTime, diffUTCTime, getCurrentTime)
- import System.Environment (getArgs)
- import System.IO (stdout, stderr, hSetBuffering, BufferMode(..))
- import System.Random (mkStdGen, setStdGen)
- import Control.Parallel.HdpH
- (RTSConf(..), defaultRTSConf, updateConf,
- Par, runParIO,
- force, fork, spark, new, get, put, glob, rput,
- IVar, GIVar,
- Thunk(Thunk), Closure, unClosure, mkClosure,
- toClosure, ToClosure(locToClosure),
- static, StaticToClosure, staticToClosure,
- StaticDecl, declare, register, here)
- import qualified Control.Parallel.HdpH as HdpH (declareStatic)
- import Control.Parallel.HdpH.Dist (one)
- import Control.Parallel.HdpH.Strategies
- (parMapNF, parMapChunkedNF, parMapSlicedNF,
- ForceCC(locForceCC), StaticForceCC, staticForceCC)
- import qualified Control.Parallel.HdpH.Strategies as Strategies (declareStatic)
- -----------------------------------------------------------------------------
- -- Euler's totient function (for positive integers)
- totient :: Int -> Integer
- totient n = toInteger $ length $ filter (\ k -> gcd n k == 1) [1 .. n]
- -----------------------------------------------------------------------------
- -- sequential sum of totients
- sum_totient :: [Int] -> Integer
- sum_totient = sum . map totient
- -----------------------------------------------------------------------------
- -- parallel sum of totients; shared memory
- par_sum_totient_chunked :: Int -> Int -> Int -> Par Integer
- par_sum_totient_chunked lower upper chunksize =
- sum <$> (mapM get =<< (mapM fork_sum_euler $ chunked_list))
- where
- chunked_list = chunk chunksize [upper, upper - 1 .. lower] :: [[Int]]
- par_sum_totient_sliced :: Int -> Int -> Int -> Par Integer
- par_sum_totient_sliced lower upper slices =
- sum <$> (mapM get =<< (mapM fork_sum_euler $ sliced_list))
- where
- sliced_list = slice slices [upper, upper - 1 .. lower] :: [[Int]]
- fork_sum_euler :: [Int] -> Par (IVar Integer)
- fork_sum_euler xs = do v <- new
- fork $ force (sum_totient xs) >>= put v
- return v
- -----------------------------------------------------------------------------
- -- parallel sum of totients; distributed memory
- dist_sum_totient_chunked :: Int -> Int -> Int -> Par Integer
- dist_sum_totient_chunked lower upper chunksize = do
- sum <$> (mapM get_and_unClosure =<< (mapM spark_sum_euler $ chunked_list))
- where
- chunked_list = chunk chunksize [upper, upper - 1 .. lower] :: [[Int]]
- dist_sum_totient_sliced :: Int -> Int -> Int -> Par Integer
- dist_sum_totient_sliced lower upper slices = do
- sum <$> (mapM get_and_unClosure =<< (mapM spark_sum_euler $ sliced_list))
- where
- sliced_list = slice slices [upper, upper - 1 .. lower] :: [[Int]]
- spark_sum_euler :: [Int] -> Par (IVar (Closure Integer))
- spark_sum_euler xs = do
- v <- new
- gv <- glob v
- spark one $(mkClosure [| spark_sum_euler_abs (xs, gv) |])
- return v
- spark_sum_euler_abs :: ([Int], GIVar (Closure Integer)) -> Thunk (Par ())
- spark_sum_euler_abs (xs, gv) =
- Thunk $ force (sum_totient xs) >>= rput gv . toClosure
- get_and_unClosure :: IVar (Closure a) -> Par a
- get_and_unClosure = return . unClosure <=< get
- -----------------------------------------------------------------------------
- -- parallel sum of totients; distributed memory (using plain task farm)
- farm_sum_totient_chunked :: Int -> Int -> Int -> Par Integer
- farm_sum_totient_chunked lower upper chunksize =
- sum <$> parMapNF $(mkClosure [| sum_totient |]) chunked_list
- where
- chunked_list = chunk chunksize [upper, upper - 1 .. lower] :: [[Int]]
- farm_sum_totient_sliced :: Int -> Int -> Int -> Par Integer
- farm_sum_totient_sliced lower upper slices =
- sum <$> parMapNF $(mkClosure [| sum_totient |]) sliced_list
- where
- sliced_list = slice slices [upper, upper - 1 .. lower] :: [[Int]]
- -----------------------------------------------------------------------------
- -- parallel sum of totients; distributed memory (chunking/slicing task farms)
- chunkfarm_sum_totient :: Int -> Int -> Int -> Par Integer
- chunkfarm_sum_totient lower upper chunksize =
- sum <$> parMapChunkedNF chunksize $(mkClosure [| totient |]) list
- where
- list = [upper, upper - 1 .. lower] :: [Int]
- slicefarm_sum_totient :: Int -> Int -> Int -> Par Integer
- slicefarm_sum_totient lower upper slices =
- sum <$> parMapSlicedNF slices $(mkClosure [| totient |]) list
- where
- list = [upper, upper - 1 .. lower] :: [Int]
- -----------------------------------------------------------------------------
- -- chunking up lists; inverse of 'chunk n' is 'concat'
- chunk :: Int -> [a] -> [[a]]
- chunk _ [] = []
- chunk n xs = ys : chunk n zs where (ys,zs) = splitAt n xs
- -----------------------------------------------------------------------------
- -- slicing lists; inverse of 'slice n' is 'unslice'
- slice :: Int -> [a] -> [[a]]
- slice n = transpose . chunk n
- unslice :: [[a]] -> [a]
- unslice = concat . transpose
- -----------------------------------------------------------------------------
- -- Static declaration (just before 'main')
- -- Empty splice; TH hack to make all environment abstractions visible.
- $(return [])
- -- orphan ToClosure and ForceCC instances (unavoidably so)
- instance ToClosure Int where locToClosure = $(here)
- instance ToClosure [Int] where locToClosure = $(here)
- instance ToClosure Integer where locToClosure = $(here)
- instance ForceCC Integer where locForceCC = $(here)
- declareStatic :: StaticDecl
- declareStatic =
- mconcat
- [HdpH.declareStatic, -- declare Static deserialisers
- Strategies.declareStatic, -- from imported modules
- declare (staticToClosure :: StaticToClosure Int),
- declare (staticToClosure :: StaticToClosure [Int]),
- declare (staticToClosure :: StaticToClosure Integer),
- declare (staticForceCC :: StaticForceCC Integer),
- declare $(static 'spark_sum_euler_abs),
- declare $(static 'sum_totient),
- declare $(static 'totient)]
- -----------------------------------------------------------------------------
- -- initialisation, argument processing and 'main'
- -- time an IO action
- timeIO :: IO a -> IO (a, NominalDiffTime)
- timeIO action = do t0 <- getCurrentTime
- x <- action
- t1 <- getCurrentTime
- return (x, diffUTCTime t1 t0)
- -- initialize random number generator
- initrand :: Int -> IO ()
- initrand seed = do
- when (seed /= 0) $ do
- setStdGen (mkStdGen seed)
- -- parse runtime system config options (+ seed for random number generator)
- -- abort if there is an error
- parseOpts :: [String] -> IO (RTSConf, Int, [String])
- parseOpts args = do
- either_conf <- updateConf args defaultRTSConf
- case either_conf of
- Left err_msg -> error $ "parseOpts: " ++ err_msg
- Right (conf, []) -> return (conf, 0, [])
- Right (conf, arg':args') ->
- case stripPrefix "-rand=" arg' of
- Just s -> return (conf, read s, args')
- Nothing -> return (conf, 0, arg':args')
- -- parse (optional) arguments in this order:
- -- * version to run
- -- * lower bound for Euler's totient function
- -- * upper bound for Euler's totient function
- -- * size of chunks (evaluated sequentially)
- parseArgs :: [String] -> (Int, Int, Int, Int)
- parseArgs [] = (defVers, defLower, defUpper, defChunk)
- parseArgs (s:ss) =
- let go :: Int -> [String] -> (Int, Int, Int, Int)
- go v [] = (v, defLower, defUpper, defChunk)
- go v [s1] = (v, defLower, read s1, defChunk)
- go v [s1,s2] = (v, read s1, read s2, defChunk)
- go v (s1:s2:s3:_) = (v, read s1, read s2, read s3)
- in case stripPrefix "v" s of
- Just s' -> go (read s') ss
- Nothing -> go defVers (s:ss)
- defVers, defLower, defUpper, defChunk :: Int
- defVers = 7
- defLower = 1
- defUpper = 20000
- defChunk = 100
- main :: IO ()
- main = do
- hSetBuffering stdout LineBuffering
- hSetBuffering stderr LineBuffering
- register declareStatic
- opts_args <- getArgs
- (conf, seed, args) <- parseOpts opts_args
- let (version, lower, upper, gran_arg) = parseArgs args
- initrand seed
- case version of
- 0 -> do (x, t) <- timeIO $ evaluate
- (sum_totient [upper, upper - 1 .. lower])
- putStrLn $
- "{v0} sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- 1 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (par_sum_totient_chunked lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v1, chunksize=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- 2 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (dist_sum_totient_chunked lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v2, chunksize=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- 3 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (farm_sum_totient_chunked lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v3, chunksize=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- 4 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (chunkfarm_sum_totient lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v4, chunksize=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- 5 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (par_sum_totient_sliced lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v5, slices=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- 6 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (dist_sum_totient_sliced lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v6, slices=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- 7 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (farm_sum_totient_sliced lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v7, slices=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- 8 -> do (output, t) <- timeIO $ evaluate =<< runParIO conf
- (slicefarm_sum_totient lower upper gran_arg)
- case output of
- Just x -> putStrLn $
- "{v8, slices=" ++ show gran_arg ++ "} " ++
- "sum $ map totient [" ++ show lower ++ ".." ++
- show upper ++ "] = " ++ show x ++
- " {runtime=" ++ show t ++ "}"
- Nothing -> return ()
- _ -> return ()