I'm trying to learn how to use the Control.Parallel module but I think I didn't get it right.
I'm trying to run the following code (fibs.hs): import Control.Parallel
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = p `par` (q `pseq` (p + q))
where
p = fib (n-1)
q = fib (n-2)
main = print $ fib 30
I compiled this with:
ghc -O2 --make -threaded fibs.hs
And then I get the following results executing this program (output of a python script that runs 100 times each program and returns average and standard deviation of the execution time):
./fibs +RTS -N1 -> avg= 0.060203 s, deviation = 0.004112 s
./fibs +RTS -N2 -> avg= 0.052335 s, deviation = 0.006713 s
./fibs +RTS -N3 -> avg= 0.052935 s, deviation = 0.006183 s
./fibs +RTS -N4 -> avg= 0.053976 s, deviation = 0.007106 s
./fibs +RTS -N5 -> avg= 0.055227 s, deviation = 0.008598 s
./fibs +RTS -N6 -> avg= 0.055703 s, deviation = 0.006537 s
./fibs +RTS -N7 -> avg= 0.058327 s, deviation = 0.007526 s
My questions are:
What exactly is happening when I evaluate:
a `par` (b `pseq` (a + b)) ?
I understand that a
par
b is supposed to hint the compiler about calculating a in parallel with b and return b. Ok. But what doespseq
do?Why I see such a small performance increase? I'm running this in a Core2 Quad machine. I'd expect that running with -N5 or -N6 wouldn't make a real difference in performance or that the program would actually start to perform very badly. But why I see no improvement from -N2 to -N3 and why the initial improvement is so small?