packages feed

scientist-0.0.0.0: library/Scientist/Duration.hs

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Scientist.Duration
  ( Duration
  , measureDuration
  , durationToSeconds
  ) where

import Prelude

import Control.Monad.IO.Class (MonadIO(..))
import Data.Fixed (Fixed(..), Nano, showFixed)
import qualified System.Clock as Clock

-- | Time elapsed in seconds up to nanosecond precision
--
-- >> 1.005
-- 1.005s
newtype Duration = Duration
  { _unDuration :: Nano
  }
  deriving stock (Eq)
  deriving newtype (Enum, Ord, Num, Real, Fractional, RealFrac)

instance Show Duration where
  show (Duration x) = showFixed True x <> "s"

measureDuration :: MonadIO m => m a -> m (a, Duration)
measureDuration f = do
  begin <- liftIO getTime
  (,) <$> f <*> liftIO
    (fromNanoSecs . Clock.toNanoSecs . subtract begin <$> getTime)
  where getTime = Clock.getTime Clock.Monotonic

-- | Convert from duration to seconds
--
-- >> toSecs 0.000001
-- 0.000001
durationToSeconds :: Duration -> Double
durationToSeconds = realToFrac

-- | Convert to duration from nanoseconds
--
-- >> fromNanoSecs 1000
-- 0.000001s
fromNanoSecs :: Integer -> Duration
fromNanoSecs = Duration . MkFixed