{-# LANGUAGE CPP #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Serokell.Util.Bench
#if ( __GLASGOW_HASKELL__ < 802 )
( ) where
#else
( getWallTime
, getCpuTime
, ElapsedTime (..)
, measureTime
, measureTime_
, perSecond
) where
import Universum
import Fmt (Buildable (build), (+||), (||+))
import System.Clock (Clock (..), TimeSpec, diffTimeSpec, getTime, toNanoSecs)
import Time (KnownRat, Time, ns, toUnit)
getWallTime :: forall unit m . (MonadIO m, KnownRat unit) => m (Time unit)
getWallTime = timeSpecToUnit <$> getTime' Realtime
getCpuTime :: forall unit m . (MonadIO m, KnownRat unit) => m (Time unit)
getCpuTime = timeSpecToUnit <$> getTime' ProcessCPUTime
timeSpecToUnit :: forall unit . KnownRat unit => TimeSpec -> Time unit
timeSpecToUnit = toUnit @unit . ns . fromIntegral . toNanoSecs
data ElapsedTime = ElapsedTime
{ elapsedCpuTime :: TimeSpec
, elapsedWallTime :: TimeSpec
} deriving (Show)
instance Buildable ElapsedTime where
build ElapsedTime{..} =
"(CPU time = "+||elapsedCpuTime||+", wall time = "+||elapsedWallTime||+")"
getTime' :: MonadIO m => Clock -> m TimeSpec
getTime' = liftIO . getTime
measureTime :: MonadIO m => m a -> m (ElapsedTime, a)
measureTime action = do
cpuTimeBefore <- getTime' ProcessCPUTime
wallTimeBefore <- getTime' Realtime
res <- action
wallTimeAfter <- getTime' Realtime
cpuTimeAfter <- getTime' ProcessCPUTime
return
( ElapsedTime
{ elapsedCpuTime = cpuTimeAfter `diffTimeSpec` cpuTimeBefore
, elapsedWallTime = wallTimeAfter `diffTimeSpec` wallTimeBefore
}
, res)
measureTime_ :: MonadIO m => m a -> m ElapsedTime
measureTime_ = fmap fst . measureTime
perSecond :: (Real a, Fractional b) => a -> TimeSpec -> b
perSecond n time =
fromRational $
toRational n / (fromIntegral (max 1 $ toNanoSecs time) * 1.0e9)
#endif