haskellrepa

Nested Parallelism in Repa


The following code produces the (dreaded) "nested parallelism" error with repa-3.4.0.1:

import Control.Monad.Identity (runIdentity, liftM)
import Data.Array.Repa              as R
import Data.Array.Repa.Repr.Unboxed
import Data.Vector.Unboxed
import Test.Framework
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck hiding (generate,output)

main :: IO ()
main = defaultMainWithArgs [prop,prop] ["--maximum-generated-tests=1"]

prop = testProperty "Test" $ property prop_fmap

prop_fmap :: Arr Int -> Bool
prop_fmap x = fmapT id x == x




newtype Arr r = Arr (Array U DIM1 r) deriving (Eq, Show)

instance (Arbitrary r, Unbox r) => Arbitrary (Arr r) where
    arbitrary = replM arbitrary
    shrink = shrinkNothing

replM :: (Unbox r, Monad mon) => mon r -> mon (Arr r)
replM = let n = 6
        in liftM (Arr . fromUnboxed (Z:.n)) . replicateM n

fmapT :: (Unbox a, Unbox b) => (a -> b) -> Arr a -> Arr b
fmapT f (Arr v) = Arr $ force' $ R.map f $ v

force' :: (Shape sh, Unbox r) => Array D sh r -> Array U sh r
force' = runIdentity . computeP

The exact error is:

Performing nested parallel computation sequentially.   You've probably
called the 'compute' or 'copy' function while another   instance was
already running. This can happen if the second version   was suspended
due to lazy evaluation. Use 'deepSeqArray' to ensure   that each array
is fully evaluated before you 'compute' the next one. 

I'm compiling with ghc Main -threaded and running with Main +RTS -N2. I've tried using deepSeqArray in the definition of fmapT, but it doesn't help. Since the tests are independent (aside from sequencing the randomness), it's not clear how nested parallelism is even possible in this example.

Interestingly, if I change main to just quickCheck prop_fmap, it successfully completes 100 tests. So it seems there's something going on with test-framework (probably a more general problem with monad sequencing) that is different from QuickCheck.

Any ideas on why I'm getting this error and how I can avoid it while still doing a parallel computation?

Note: using the Identity monad: ref1, ref2


Solution

  • The problem is that test-framework is implicitly multi-threaded (see this for example.)

    The solution that works for me is to run defaultMainWithArgs with the option --threads=1.