[Haskell-beginners] Parallelism?

Edward Z. Yang ezyang at MIT.EDU
Thu Dec 1 17:40:17 CET 2011


Simon Marlow investigated, and we got this patch out:

commit 6d18141d880d55958c3392f6a7ae621dc33ee5c1
Author: Simon Marlow <marlowsd at gmail.com>
Date:   Thu Dec 1 10:53:28 2011 +0000

    Fix a scheduling bug in the threaded RTS

    The parallel GC was using setContextSwitches() to stop all the other
    threads, which sets the context_switch flag on every Capability.  That
    had the side effect of causing every Capability to also switch
    threads, and since GCs can be much more frequent than context
    switches, this increased the context switch frequency.  When context
    switches are expensive (because the switch is between two bound
    threads or a bound and unbound thread), the difference is quite
    noticeable.

    The fix is to have a separate flag to indicate that a Capability
    should stop and return to the scheduler, but not switch threads.  I've
    called this the "interrupt" flag.

Thanks for constructing this lovely test-case!

Cheers,
Edward

P.S. When you run in single-threaded runtime, the second thread never
actually finishes. You need to manually wait on it for an MVar.
Also, note that putStrLn is synchronized by an MVar, to avoid interleaved
output.

Excerpts from Michael Craig's message of Thu Dec 01 00:50:15 -0500 2011:
> I was writing some parallel code (asynchronous database writes for an event
> logger, but that's besides the point), and it seemed like the parallelized
> version (i.e. compiled with -threaded -with-rtsopts=-N2) wasn't running
> fast enough. I boiled it down to a dead-simple test:
> 
>     import Control.Concurrent
>     import Data.Time.Clock.POSIX
>     import System.Environment
> 
>     main :: IO ()
>     main = do
>         n <- getArgs >>= return . read . head
>         t1 <- getPOSIXTime
>         work n
>         t2 <- getPOSIXTime
>         putStrLn $ show $ t2 - t1
>         putStrLn $ show $ (fromIntegral n :: Double)
>                         / (fromRational . toRational $ t2 - t1)
> 
>     work :: Integer -> IO ()
>     work n = do
>       forkIO $ putStrLn $ seq (fact n) "Done"
>       putStrLn $ seq (fact n) "Done"
> 
>     fact :: Integer -> Integer
>     fact 1 = 1
>     fact n = n * fact (n - 1)
> 
> (I know this is not the best way to time things but I think it suffices for
> this test.)
> 
> Compiled with ghc --make -O3 test.hs, ./test 500000 runs for 74 seconds.
> Compiling with ghc --make -O3 -threaded -with-rtsopts=-N, ./test 500000
> runs for 82 seconds (and seems to be using 2 cpu cores instead of just 1,
> on a 4-core machine). What gives?
> 
> Mike S Craig



More information about the Beginners mailing list