3

Good day. Given code

import           Control.DeepSeq
import           Control.Exception
import           Control.Parallel
import           Control.Parallel.Strategies
import           System.Environment
import           Text.Printf

l = [34,56,43,1234,456,765,345,4574,58,878,978,456,34,234,1234123,1234,12341234]
f x = Just (sum [1..x])

fun1 :: [Maybe Integer]
fun1 = map f l `using` parList rdeepseq
fun2 :: [Maybe Integer]
fun2 = map f l `using` evalList (rparWith rdeepseq)
fun3 :: [Maybe Integer]
fun3 = map f l `using` evalList (rpar . force)

main :: IO ()
main = print fun1

Why fun1 and fun2 run sequentially? From what I understood, rparWith should spark its argument. Answer here states the same. But for fun1 and fun2 I'm getting output like "SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)". So Sparks were not even created. fun3 works as expected with sparks being created. Ty for help

UPD: And I found that rdeepseq makes example from book (Parallel and Concurrent Programming in Haskell) works in sequence. Book says:

And we can use parPair to write a Strategy that fully evaluates both components of a pair in parallel:

parPair rdeepseq rdeepseq :: (NFData a, NFData b) => Strategy (a,b)

To break down what happens when this Strategy is applied to a pair: parPair calls, and evalPair calls rparWith rdeepseq on each component of the pair. So the effect is that each component will be fully evaluated to normal form in parallel.

But if I run

(Just (fib 35), Just (fib 36)) `using` parPair rdeepseq rdeepseq

or even

(fib 35, fib 36) `using` parPair rdeepseq rdeepseq

Threadscope shows only one core running and 0 sparks created.

fib implemented like this (from book too)

fib :: Integer -> Integer
fib 0 = 1
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
Mikekekeke
  • 89
  • 1
  • 9
  • How are you compiling and running this? – Carl May 27 '18 at 15:46
  • You need to use the GHC option `-threaded` and run the executable with `+RTS -Nx` where `x` is the number of cores to use. Are you doing this in your testing? – AJF May 27 '18 at 17:10
  • Yes, compile with "ghc -O2 [filename.hs] -threaded -rtsopts -eventlog". Then run with "[filename] +RTS -N2 -l" – Mikekekeke May 27 '18 at 17:57
  • Also `(Just (fib 35), Just (fib 36)) \`using\` evalPair (rparWith (rseq . force)) (rparWith (rseq . force))` shows 2 core busy, but `(Just (fib 35), Just (fib 36)) \`using\` parPair rdeepseq rdeepseq` only one. As far as I understood, those should be sort of equivalent – Mikekekeke May 27 '18 at 18:03

2 Answers2

0

The original paper describes rdeepseq as

rdeepseq :: NFData a => Strategy a
rdeepseq x = rnf x ‘pseq‘ return x

And indeed, if you use this definition, it will create sparks, like you'd expect. Looks like rdeepseq sematrics was changes (probably here), intentionally or incidentally. I don't see any note neither in the documentation, nor in the changelog, so it is probably a bug. Please create at issue on their bug tracker and ask maintainers for clarification.

Yuras
  • 13,856
  • 1
  • 45
  • 58
  • 2
    Looks like this is some known issue, so I just commented here https://github.com/haskell/parallel/issues/17 – Mikekekeke May 30 '18 at 08:43
  • 1
    The actual issue turned out to have nothing whatsoever to do with `rdeepseq` and everything to do with `rparWith`. See the ultimate ticket resolution. – dfeuer Jul 17 '18 at 23:59
0

rparWith was defined using realWorld#, a deeply magical GHC internal value. The way it was used is essentially the same as applying a "function" sometimes called accursedUnutterablePerformIO (more officially, unsafeInlinePerformIO). Using it is only legitimate when the IO in question is actually exceptionally pure. The thinking was that since Eval is just for calculation, that should be fine. But in fact, sparking threads is an IO effect, and one we care about! The optimizer was rearranging those effects in an unfortunate way, causing them ultimately to be dropped. The fix was to use unsafeDupablePerformIO instead. That's a much better-behaved "function", and seems to do the trick. See the ticket for details.

Note: my initial fix turned out to be a bit wrong; it's now been modified once again.

dfeuer
  • 48,079
  • 5
  • 63
  • 167