[Haskell-cafe] Timeout exceptions sometimes don't work, even in pure (non FFI) code
Daniel Fischer
daniel.is.fischer at googlemail.com
Tue Feb 1 17:18:04 CET 2011
On Tuesday 01 February 2011 16:40:43, Job Vranish wrote:
> I'm trying to test some properties with quickcheck. If these tests fail,
> they will almost certainly fail by nontermination.
> I've been using the 'within' function to catch these nontermination
> cases. However, I was surprised to find that this doesn't always work.
> 'within' uses the 'timeout' function under the hood. Here is an example
> that demonstrates the problem:
>
> import System.Timeout
> import Control.Exception
>
> works :: Int -> Int
> works x = sum $ cycle [x]
>
> doesntWork :: Int -> Int
> doesntWork x = last $ cycle [x]
>
> test1 = timeout 1 $ evaluate $ works 5 == 5 -- terminates
> test2 = timeout 1 $ evaluate $ doesntWork 5 == 5 -- never terminates
>
>
> test1 returns Nothing as expected, but test2 never terminates. Why?
When compiled with optimisations, works doesn't terminate either.
I believe it's because works actually does some work and allocations
(without optimisations), while doesntWork is a non-allocating loop.
GHC only makes context switches on allocations, so with a non-allocating
loop, the timeout thread never gets to run to see whether the time limit is
exceeded.
Without optimisations, sum allocates thunks, with optimisations it becomes
a tight loop not hitting the heap. `last $ cycle [x]' becomes a tight loop
even without optimisations.
>
> I thought timeout exceptions are supposed to always work with pure (non
> FFI) Haskell code.
> Is there any way I can work around this?
Make sure your tests always allocate, or write them as IO stuff and call
yield (or threadDelay) within the loops to let GHC make some context
switches.
>
> I'm using ghc 6.12.2
>
> Thanks,
>
> - Job
More information about the Haskell-Cafe
mailing list