[Haskell-cafe] Re: GHC threads and SMP
Paul L
ninegua at gmail.com
Fri Jul 6 18:18:27 EDT 2007
replying to my own message... the behavior is only when -O is used
during compilation, otherwise they both run on 2 cores but at a much
lower (1/100) speed.
On 7/6/07, Paul L <ninegua at gmail.com> wrote:
> I have two parallel algorithms that use the lightweight GHC thread and
> forkIO. I compile them using the -threaded (or -smp) option, and run
> both with +RTS -N2 -RTS command line option.
>
> QSort is able to make use of the dual cores on my laptop -- "top"
> shows that two threads show up and both CPUs are utilized, and "time"
> it will give something like this:
>
> real 0m0.502s
> user 0m0.872s
> sys 0m0.004s
>
> But Prime can only make use of one core, as shown by "top". "time" gives
>
> real 0m9.112s
> user 0m9.093s
> sys 0m0.028s
>
> Because forkOS is not used anywhere, the decision of running them on 1
> or 2 OS threads seem rather arbitary. Why?
>
> Regards,
> Paul L
>
>
>
> > import Control.Concurrent
> > import System.Random
> > import Data.Array.MArray
> > import Data.Array.IO
> > import System.IO.Unsafe
> > import Control.Exception
>
> 1. Quick Sort
>
> > testQSort' n verbose = do
> > let b = (0, n - 1)
> > arr <- newArray b 0 :: IO (IOUArray Int Int)
> > initM' (mkStdGen 0) b arr
> > waitForChildren
> > qsortM' b arr
> > waitForChildren
> > if verbose then getElems arr >>= putStrLn . show else return ()
>
> Initialize an array with random numbers.
>
> > initM' g (i, j) arr | j - i < 10000 = fillArr g i j
> > where
> > fillArr g i j = if i > j then return () else do
> > let (v, g') = next g
> > writeArray arr i v >> fillArr g' (i + 1) j
> > initM' g (i, j) arr = do
> > let k = (i + j) `div` 2
> > (g1, g2) = split g
> > forkChild $ initM' g1 (i, k) arr
> > forkChild $ initM' g2 (k + 1, j) arr
> > return ()
>
> > qsortM' (i, j) arr = qsort' (i, j)
> > where
> > qsort' (i, j) =
> > if j <= i then return () else do
> > k <- split i j
> > if j - i > 10000 then (forkChild $ qsort' (i, k - 1)) >> return ()
> > else qsort' (i, k - 1)
> > qsort' (k + 1, j)
> > split left right = do
> > v <- readArray arr right
> > let split' i j = if j == right then swap i right v >> return i else do
> > b <- readArray arr j
> > if b <= v
> > then (swap i j b) >> split' (i + 1) (j + 1)
> > else split' i (j + 1)
> > split' left left
> > swap i j b = do
> > a <- readArray arr i
> > writeArray arr i b
> > writeArray arr j a
>
> 2. Prime
>
> > testPrime' n verbose = do
> > arr <- newArray (0, n) True :: IO (IOUArray Int Bool)
> > primeM' arr n
> > waitForChildren
> > if verbose
> > then getElems arr >>= putStrLn . show . map fst . filter snd . zip [0..]
> > else return ()
>
> > primeM' arr n = do
> > let p = truncate $ sqrt (fromIntegral n) + 1
> > remove i = if i > p then return () else do
> > spawnRemover (i + 1)
> > remove' (i + i)
> > where
> > remove' j = if j > n then return () else do
> > writeArray arr j False
> > remove' (j + i)
> > spawnRemover j = if j > n then return () else do
> > t <- readArray arr j
> > if t then forkChild (remove j) else spawnRemover (j + 1)
> > remove 2
>
> Manage thread termination
>
> > children :: MVar [MVar ()]
> > children = unsafePerformIO (newMVar [])
>
> > waitForChildren :: IO ()
> > waitForChildren = do
> > cs <- takeMVar children
> > case cs of
> > [] -> putMVar children cs
> > m:ms -> do
> > putMVar children ms
> > takeMVar m
> > waitForChildren
> >
> > forkChild :: IO () -> IO ()
> > forkChild io = do
> > mvar <- newEmptyMVar
> > childs <- takeMVar children
> > putMVar children (mvar:childs)
> > forkIO (io `finally` putMVar mvar ())
> > return ()
>
More information about the Haskell-Cafe
mailing list