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?
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
.