{-# LANGUAGE BangPatterns #-} {-# LANGUAGE ScopedTypeVariables #-} -- | -- Module : System.Microtimer -- Copyright : (c) 2009, 2010 Bryan O'Sullivan -- (c) 2013 Austin Seipp -- License : BSD-style -- Maintainer : aseipp@pobox.com -- Stability : experimental -- Portability : GHC -- -- A tiny module for measuring the time taken by an 'IO' action. -- -- This module is a almost a direct copy of the -- @Criterion.Measurement@ module from the @criterion@ package, -- written by Bryan O'Sullivan. -- module System.Microtimer ( -- * Timing 'IO' actions. time -- :: IO a -> IO (Double, a) , time_ -- :: IO a -> IO Double -- * Formatting timing results. , formatSeconds -- :: Double -> String ) where import Control.Monad (liftM) import Data.Time.Clock.POSIX (getPOSIXTime) import Text.Printf (printf) -- | Time an 'IO' action and return the time taken for execution, -- as well as the return value. time :: IO a -> IO (Double, a) time act = do start <- getTime result <- act end <- getTime let !delta = end - start return (delta, result) -- | Time an 'IO' action, throwing away the result and returning -- the time taken for execution. time_ :: IO a -> IO Double time_ act = fst `liftM` (time act) -- | Convert a 'Double' value into a 'String' which specifies -- how long something took in seconds. formatSeconds :: Double -> String formatSeconds k | k < 0 = '-' : formatSeconds (-k) | k >= 1 = k `with` "s" | k >= 1e-3 = (k*1e3) `with` "ms" | k >= 1e-6 = (k*1e6) `with` "us" | k >= 1e-9 = (k*1e9) `with` "ns" | k >= 1e-12 = (k*1e12) `with` "ps" | otherwise = printf "%g s" k where with (t :: Double) (u :: String) | t >= 1e9 = printf "%.4g %s" t u | t >= 1e6 = printf "%.0f %s" t u | t >= 1e5 = printf "%.1f %s" t u | t >= 1e4 = printf "%.2f %s" t u | t >= 1e3 = printf "%.3f %s" t u | t >= 1e2 = printf "%.4f %s" t u | t >= 1e1 = printf "%.5f %s" t u | otherwise = printf "%.6f %s" t u -------------------------------------------------------------------------------- -- Miscellaneous getTime :: IO Double getTime = realToFrac `fmap` getPOSIXTime {-- TODO: perhaps export this one day runForAtLeast :: Double -> Int -> (Int -> IO a) -> IO (Double, Int, a) runForAtLeast howLong initSeed act = loop initSeed (0::Int) =<< getTime where loop !seed !iters initTime = do now <- getTime when (now - initTime > howLong * 10) $ fail (printf "took too long to run: seed %d, iters %d" seed iters) (elapsed,result) <- time (act seed) if elapsed < howLong then loop (seed * 2) (iters+1) initTime else return (elapsed, seed, result) --}