module Criterion.Environment
(
Environment(..)
, measureEnvironment
) where
import Control.Monad (replicateM_)
import Control.Monad.Trans (liftIO)
import Criterion.Analysis (analyseMean)
import Criterion.IO (note)
import Criterion.Measurement (getTime, runForAtLeast, time_)
import Criterion.Monad (Criterion)
import qualified Data.Vector.Unboxed as U
import Data.Typeable (Typeable)
import Statistics.Function (create)
data Environment = Environment {
envClockResolution :: !Double
, envClockCost :: !Double
} deriving (Eq, Read, Show, Typeable)
measureEnvironment :: Criterion Environment
measureEnvironment = do
_ <- note "warming up\n"
(_, seed, _) <- liftIO $ runForAtLeast 0.1 10000 resolution
_ <- note "estimating clock resolution...\n"
clockRes <- thd3 `fmap` liftIO (runForAtLeast 0.5 seed resolution) >>=
uncurry analyseMean
_ <- note "estimating cost of a clock call...\n"
clockCost <- cost (min (100000 * clockRes) 1) >>= uncurry analyseMean
return $ Environment {
envClockResolution = clockRes
, envClockCost = clockCost
}
where
resolution k = do
times <- create (k+1) (const getTime)
return (U.tail . U.filter (>=0) . U.zipWith () (U.tail times) $ times,
U.length times)
cost timeLimit = liftIO $ do
let timeClock k = time_ (replicateM_ k getTime)
_ <- timeClock 1
(_, iters, elapsed) <- runForAtLeast 0.01 10000 timeClock
times <- create (ceiling (timeLimit / elapsed)) $ \_ -> timeClock iters
return (U.map (/ fromIntegral iters) times, U.length times)
thd3 (_, _, c) = c