File: ParTests_shared.hs

package info (click to toggle)
haskell-monad-par 0.3.6-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 208 kB
  • sloc: haskell: 1,583; makefile: 19
file content (206 lines) | stat: -rw-r--r-- 6,343 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206

import Control.Monad.Par.Combinator 
-- import Control.Concurrent.Chan  ()
import GHC.Conc (numCapabilities)
import Control.Exception (evaluate)
-- import System.IO.Unsafe
-- import Data.IORef
import Test.HUnit        (Assertion, (@=?))
import Test.Framework.TH (testGroupGenerator)
-- import Test.Framework (defaultMain, testGroup)
import qualified Test.Framework as TF
import           Test.Framework.Providers.HUnit 
-- import Test.Framework.Providers.QuickCheck2 (testProperty)
import System.Timeout (timeout)

import TestHelpers (assertException, prnt, _prnt, _unsafeio, waste_time, collectOutput)

-- -----------------------------------------------------------------------------

-- Testing

three :: Int
three = 3

par :: (Eq a, Show a) => a -> Par a -> Assertion
par res m = res @=? runPar m

-- From https://github.com/simonmar/monad-par/pull/49
case_parallelFilter :: Assertion
case_parallelFilter = run 200 where
  run 0 = pure ()
  run i = do
    par result (parfilter p xs)
    run (i-1)

  p x = x `mod` 2 == 0
  xs = [0..10] :: [Int]
  result = filter p xs

  parfilter _ []  = pure []
  parfilter f [x] = pure (if f x then [x] else [])
  parfilter f xs  = do
    let (as, bs) = halve xs
    v1 <- spawn $ parfilter f as
    v2 <- spawn $ parfilter f bs
    left  <- get v1
    right <- get v2
    pure (left ++ right)

  halve xs = splitAt (length xs `div` 2) xs

-- | Make sure there's no problem with bringing the worker threads up and down many
-- times.  10K runPar's takes about 6.3 seconds.
case_lotsaRunPar :: Assertion
case_lotsaRunPar = loop 2000
  where 
  loop 0 = putStrLn ""
  loop i = do
    -- We need to do runParIO to make sure the compiler does the runPar each time.
    runParIO (return ())
    putStr "."
    loop (i-1)
    
case_justReturn :: Assertion
case_justReturn = par three (return 3)

case_oneIVar :: Assertion
case_oneIVar    = par three (do r <- new; put r 3; get r)


-- [2012.01.02] Apparently observing divergences here too:
case_forkNFill :: Assertion
case_forkNFill  = par three (do r <- new; fork (put r 3); get r)

-- [2012.05.02] The nested Trace implementation sometimes fails to
-- throw this exception, so we expect either the exception or a
-- timeout. This is reasonable since we might expect a deadlock in a
-- non-Trace scheduler. --ACF
-- 
-- [2013.05.17] Update, it's also possible to get a blocked-indefinitely error here
--   --RRN
--
-- [2013.09.08] Yep, I'm nondeterministically seeing this fail using
-- Direct.  But this is actually a failure of the exception handling
-- setup.  `assertException` should be catching blocked-indefinitely
-- error and it's NOT always.  Running this test ALONE, I cannot trip
-- it, but running it with others I do.  In fact, running it with
-- through test-framework's "-j1" I cannot reproduce the error. It is
-- probably just the perturbation to timing caused by this, after all,
-- WAIT_WORKERS is not currently on for Direct.  Still, I thought that
-- wouldn't matter here because the *main* thread can't return.
--
-- Also, it seems like this test can just hang indefinitely, with the
-- timeout failing to do the trick....  
-- 
case_getEmpty :: IO ()
case_getEmpty   = do
  -- Microseconds:
  _ <- timeout (100 * 1000) $ assertException ["no result", "timeout", "thread blocked indefinitely"] $ 
         runPar $ do r <- new; get r
  return ()


-- [2012.01.02] Observed a blocked-indef-on-MVar failure here on
-- master branch with 16 threads:
-- 
-- | Simple diamond test.
case_test_diamond :: Assertion
case_test_diamond = 9 @=? (m :: Int)
 where 
  m = runPar $ do
      abcd <- sequence [new,new,new,new]
      case abcd of
          [a,b,c,d] -> do
              fork $ do x <- get a; put b (x+1)
              fork $ do x <- get a; put c (x+2)
              fork $ do x <- get b; y <- get c; put d (x+y)
              fork $ do put a 3
              get d
          _ -> error "Oops"

-- | Violate IVar single-assignment:
--
-- NOTE: presently observing termination problems here.
-- runPar is failing to exist after the exception?
disabled_case_multiput :: IO ()
disabled_case_multiput = assertException ["multiple put"] $ 
  runPar $ do
   a <- new
   put a (3::Int)
   put a (4::Int)
   return ()


-- disabled_test3 = assertException "multiple put" $ 
--   runPar $ do
--    a <- new
--    put a (3::Int)
--    both (return 1) (return 2)
--  where 
--   -- both a b >> c  ==   both (a >> c) (b >> c)
--   -- Duplicate the continuation: is this useful for anything?
--   both :: Par a -> Par a -> Par a
--   both a b = Par $ \c -> Fork (runCont a c) (runCont b c)


-- | A reduction test.
case_test_pmrr1 :: Assertion
-- Saw a failure here using Direct:
--   http://tester-lin.soic.indiana.edu:8080/job/HackageReleased_monad-par/GHC_VERS=7.0.4,label=tank.cs.indiana.edu/40/console
-- Exception inside child thread "(worker 0 of originator ThreadId 5)", ThreadId 10: thread blocked indefinitely in an MVar operation
case_test_pmrr1 = 
   par 5050 $ parMapReduceRangeThresh 1 (InclusiveRange 1 100)
	        (return) (return `bincomp` (+)) 0
 where bincomp unary bin a b = unary (bin a b)


------------------------------------------------------------


-- | Observe the real time ordering of events:
--
--   Child-stealing:       
--      A D B <pause> C E
--       
--   Parent-stealing:
--      A B D <pause> C E       
--
--   Sequential:
--      A B <pause> C D E
--       
--   This is only for the TRACE scheduler right now.
--
-- This test is DISABLED because it fails unless you run with +RTS -N2
-- or greater.
--
disabled_case_async_test1 :: IO ()
disabled_case_async_test1 =
  do x <- res
     case (numCapabilities, words x) of
       (1,["A","B","C",_,"D","E"])         -> return ()       
       (n,["A","D","B","C",_,"E"]) | n > 1 -> return ()
       (n,["A","B","D","C",_,"E"]) | n > 1 -> return ()       
       _  -> error$ "Bad temporal pattern: "++ show (words x)
 where 
 res = collectOutput $ \ r -> do
  prnt r "A"
  evaluate$ runPar $
    do iv <- new
       fork $ do _prnt r "B"
                 x <- _unsafeio$ waste_time 0.5
		 _prnt r$ "C "++ show x
--		 _prnt r$ "C "++ show (_waste_time awhile)
                 put iv ()
       _prnt r "D"
       get iv
  prnt r$ "E"
  



------------------------------------------------------------

tests :: [TF.Test]
tests = [ $(testGroupGenerator) ]