[Haskell-cafe] I killed performance of my code with Eval and Strategies

Bertram Felgenhauer bertram.felgenhauer at googlemail.com
Sun Nov 18 02:41:21 CET 2012


Dear Janek,

> I am reading Simon Marlow's tutorial on parallelism and I have problems
> with correctly using Eval monad and Strategies. I *thought* I understand
> them but after writing some code it turns out that  obviously I don't
> because parallelized code is about 20 times slower. Here's a short
> example  (code + criterion benchmarks):

Actually, (sin . sqrt) is simply too cheap. The overhead of constructing
chunks (which have to be constructed on the heap) and concatenating the
results far outweighs the cost of computing the list elements.

If, for example, you replace sin . sqrt by f defined by

    f :: Double -> Double
    f x | x < 10 = x*x
        | otherwise = sin x * f (x-100)

the picture will change. The loss also becomes far less dramatic if
you construct the chunks outside of the benchmark:

    main :: IO ()
    main = defaultMain [
            bench "Seq" $ nf (map calculateSeq) xs
          , bench "Par" $ nf calculatePar xs ]
        where xs = chunk 2048 [1..16384]
    
    f, f' :: Double -> Double
    f x = sqrt (sin x)
    f' x | x < 10 = x*x
        | otherwise = sin x * f' (x-100)
    
    
    calculateSeq :: [Double] -> [Double]
    calculateSeq [] = []
    calculateSeq (x:xs) = f x : calculateSeq xs
    
    calculatePar :: [[Double]] -> [[Double]]
    calculatePar xss = runEval $ parList (rdeepseq . calculateSeq) xss
    
    chunk :: Int -> [a] -> [[a]]
    chunk _ [] = []
    chunk n xs = as : chunk n bs where !(as, bs) = splitAt n xs

The parallel version (with f = sqrt . sin) is still somewhat slower
than the sequential version with -N1 -- probably due to rdeepseq.

Best regards,

Bertram



More information about the Haskell-Cafe mailing list