{-# LANGUAGE BangPatterns #-} {-# OPTIONS_GHC -fno-full-laziness #-} -- | -- Module : Criterion.Types.Internal -- Copyright : (c) 2017 Ryan Scott -- -- License : BSD-style -- Maintainer : bos@serpentine.com -- Stability : experimental -- Portability : GHC -- -- Exports 'fakeEnvironment'. module Criterion.Measurement.Types.Internal (fakeEnvironment, nf', whnf') where import Data.Int (Int64) -- | A dummy environment that is passed to functions that create benchmarks -- from environments when no concrete environment is available. fakeEnvironment :: env fakeEnvironment = error $ unlines [ "Criterion atttempted to retrieve a non-existent environment!" , "\tPerhaps you forgot to use lazy pattern matching in a function which" , "\tconstructs benchmarks from an environment?" , "\t(see the documentation for `env` for details)" ] -- Along with Criterion.Types.nfIO' and Criterion.Types.whnfIO', the following -- two functions are the core benchmarking loops. They have been carefully -- constructed to avoid allocation while also evaluating @f x@. -- -- Because these functions are pure, GHC is particularly smart about optimizing -- them. We must turn off @-ffull-laziness@ to prevent the computation from -- being floated out of the loop. -- -- For a similar reason, these functions must not be inlined. There are two -- possible issues that can arise if they are inlined. First, the work is often -- floated out of the loop, which creates a nonsense benchmark. Second, the -- benchmark code itself could be changed by the user's optimization level. By -- marking them @NOINLINE@, the core benchmark code is always the same. -- -- See #183 and #184 for discussion. -- | Generate a function which applies an argument to a function a -- given number of times, reducing the result to normal form. nf' :: (b -> ()) -> (a -> b) -> a -> (Int64 -> IO ()) nf' reduce f x = go where go n | n <= 0 = return () | otherwise = let !y = f x in reduce y `seq` go (n-1) {-# NOINLINE nf' #-} -- | Generate a function which applies an argument to a function a -- given number of times. whnf' :: (a -> b) -> a -> (Int64 -> IO ()) whnf' f x = go where go n | n <= 0 = return () | otherwise = f x `seq` go (n-1) {-# NOINLINE whnf' #-}