PageRenderTime 115ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/TEST/HdpH_IO/sumeuler.hs

http://github.com/PatrickMaier/HdpH
Haskell | 171 lines | 103 code | 38 blank | 30 comment | 1 complexity | 7bc1c73fde152c4e882d86adaf6bae52 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. -- Sum of totients in HdpH_IO
  2. --
  3. -- Visibility: HdpH test suite
  4. -- Author: Patrick Maier <P.Maier@hw.ac.uk>
  5. -- Created: 17 Jul 2011
  6. --
  7. -----------------------------------------------------------------------------
  8. {-# LANGUAGE TemplateHaskell #-}
  9. module Main where
  10. import Prelude
  11. import Control.Concurrent (forkIO)
  12. import Control.DeepSeq (NFData, deepseq)
  13. import Data.List (stripPrefix)
  14. import Data.Functor ((<$>))
  15. import System.Environment (getArgs)
  16. import System.IO (stdout, stderr, hSetBuffering, BufferMode(..))
  17. import MP.MPI (defaultWithMPI)
  18. import HdpH_IO (withHdpH,
  19. NodeId, allNodes,
  20. pushTo,
  21. IVar, new, get, put,
  22. GIVar, glob, rput,
  23. Closure, unClosure, toClosure, mkClosure, static,
  24. StaticId, staticIdTD, register)
  25. -----------------------------------------------------------------------------
  26. -- 'Static' registration
  27. instance StaticId Integer
  28. registerStatic :: IO ()
  29. registerStatic = do
  30. register $ staticIdTD (undefined :: Integer)
  31. register $(static 'dist_sum_totient_abs)
  32. -----------------------------------------------------------------------------
  33. -- Euler's totient function (for positive integers)
  34. totient :: Int -> Integer
  35. totient n = toInteger $ length $ filter (\ k -> gcd n k == 1) [1 .. n]
  36. -----------------------------------------------------------------------------
  37. -- sequential sum of totients
  38. sum_totient :: [Int] -> Integer
  39. sum_totient = sum . map totient
  40. -----------------------------------------------------------------------------
  41. -- parallel sum of totients; shared memory IO threads
  42. par_sum_totient :: Int -> Int -> Int -> IO Integer
  43. par_sum_totient lower upper chunksize =
  44. sum <$> (mapM join =<< (mapM fork_sum_euler $ chunked_list))
  45. where
  46. chunked_list = chunk chunksize [upper, upper - 1 .. lower] :: [[Int]]
  47. fork_sum_euler :: [Int] -> IO (IVar Integer)
  48. fork_sum_euler xs = do v <- new
  49. let job = put v $ force $ sum_totient xs
  50. forkIO job
  51. return v
  52. join :: IVar Integer -> IO Integer
  53. join = get
  54. -----------------------------------------------------------------------------
  55. -- distributed sum of totients; explicit round-robin placement
  56. dist_sum_totient :: Int -> Int -> Int -> IO Integer
  57. dist_sum_totient lower upper chunksize = do
  58. nodes <- allNodes
  59. let chunks_round_robin = zip chunked_list (cycle nodes)
  60. sum <$> (mapM join =<< (mapM push_sum_euler $ chunks_round_robin))
  61. where
  62. chunked_list = chunk chunksize [upper, upper - 1 .. lower] :: [[Int]]
  63. push_sum_euler :: ([Int], NodeId) -> IO (IVar (Closure Integer))
  64. push_sum_euler (xs,node) = do
  65. v <- new
  66. gv <- glob v
  67. let job = $(mkClosure [| dist_sum_totient_abs (xs, gv) |])
  68. pushTo job node
  69. return v
  70. join :: IVar (Closure Integer) -> IO Integer
  71. join v = unClosure <$> get v
  72. dist_sum_totient_abs :: ([Int], GIVar (Closure Integer)) -> IO ()
  73. dist_sum_totient_abs (xs, gv) =
  74. rput gv $ toClosure $ force $ sum_totient xs
  75. -----------------------------------------------------------------------------
  76. -- chunking up lists; inverse of 'chunk n' is 'concat'
  77. chunk :: Int -> [a] -> [[a]]
  78. chunk n [] = []
  79. chunk n xs = ys : chunk n zs where (ys,zs) = splitAt n xs
  80. -----------------------------------------------------------------------------
  81. -- argument processing and 'main'
  82. -- parse (optional) arguments in this order:
  83. -- * version to run
  84. -- * lower bound for Euler's totient function
  85. -- * upper bound for Euler's totient function
  86. -- * size of chunks (evaluated sequentially)
  87. parseArgs :: [String] -> (Int, Int, Int, Int)
  88. parseArgs [] = (defVers, defLower, defUpper, defChunk)
  89. parseArgs (s:ss) =
  90. let go :: Int -> [String] -> (Int, Int, Int, Int)
  91. go v [] = (v, defLower, defUpper, defChunk)
  92. go v [s1] = (v, defLower, read s1, defChunk)
  93. go v [s1,s2] = (v, read s1, read s2, defChunk)
  94. go v (s1:s2:s3:_) = (v, read s1, read s2, read s3)
  95. in case stripPrefix "v" s of
  96. Just s' -> go (read s') ss
  97. Nothing -> go defVers (s:ss)
  98. defVers = 2 :: Int
  99. defLower = 1 :: Int
  100. defUpper = 20000 :: Int
  101. defChunk = 100 :: Int
  102. main :: IO ()
  103. main = do
  104. hSetBuffering stdout LineBuffering
  105. hSetBuffering stderr LineBuffering
  106. registerStatic
  107. defaultWithMPI $ do
  108. args <- getArgs
  109. let (version, lower, upper, chunksize) = parseArgs args
  110. case version of
  111. 0 -> do x <- return $ sum_totient [upper, upper - 1 .. lower]
  112. putStrLn $
  113. "{v0} sum $ map totient [" ++ show lower ++ ".." ++
  114. show upper ++ "] = " ++ show x
  115. 1 -> do x <- par_sum_totient lower upper chunksize
  116. putStrLn $
  117. "{v1, chunksize=" ++ show chunksize ++ "} " ++
  118. "sum $ map totient [" ++ show lower ++ ".." ++
  119. show upper ++ "] = " ++ show x
  120. 2 -> do output <- withHdpH $
  121. dist_sum_totient lower upper chunksize
  122. case output of
  123. Just x -> putStrLn $
  124. "{v2, chunksize=" ++ show chunksize ++ "} " ++
  125. "sum $ map totient [" ++ show lower ++ ".." ++
  126. show upper ++ "] = " ++ show x
  127. Nothing -> return ()
  128. _ -> return ()
  129. -----------------------------------------------------------------------------
  130. -- auxiliaries
  131. -- force to normal form; taken from deepseq-1.2.0.1
  132. force :: (NFData a) => a -> a
  133. force x = x `deepseq` x