{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators       #-}

-- |
-- Module      : Instrument.Measurement
-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan
--               (c) 2012, Ozgun Ataman
--
-- License     : BSD-style

module Instrument.Measurement
    (
      getTime
    , time
    , time_
    , timeEx
    ) where

-------------------------------------------------------------------------------
import           Control.Monad.IO.Class
import           Data.Time.Clock.POSIX  (getPOSIXTime)
import           Control.Exception (SomeException)
import           Control.Exception.Safe (MonadCatch, tryAny)
-------------------------------------------------------------------------------


-- | Measure how long action took, in seconds along with its result
time :: MonadIO m =>  m a -> m (Double, a)
time :: m a -> m (Double, a)
time m a
act = do
  Double
start <- IO Double -> m Double
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Double
getTime
  !a
result <- m a
act
  Double
end <- IO Double -> m Double
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Double
getTime
  let !delta :: Double
delta = Double
end Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
start
  (Double, a) -> m (Double, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Double
delta, a
result)

-- | Measure how long action took, even if they fail
timeEx :: (MonadCatch m, MonadIO m) => m a -> m (Double, Either SomeException a)
timeEx :: m a -> m (Double, Either SomeException a)
timeEx = m (Either SomeException a) -> m (Double, Either SomeException a)
forall (m :: * -> *) a. MonadIO m => m a -> m (Double, a)
time (m (Either SomeException a) -> m (Double, Either SomeException a))
-> (m a -> m (Either SomeException a))
-> m a
-> m (Double, Either SomeException a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> m (Either SomeException a)
forall (m :: * -> *) a.
MonadCatch m =>
m a -> m (Either SomeException a)
tryAny

-- | Just measure how long action takes, discard its result
time_ :: MonadIO m => m a -> m Double
time_ :: m a -> m Double
time_  = ((Double, a) -> Double) -> m (Double, a) -> m Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Double, a) -> Double
forall a b. (a, b) -> a
fst (m (Double, a) -> m Double)
-> (m a -> m (Double, a)) -> m a -> m Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> m (Double, a)
forall (m :: * -> *) a. MonadIO m => m a -> m (Double, a)
time


-------------------------------------------------------------------------------
getTime :: IO Double
getTime :: IO Double
getTime = POSIXTime -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac (POSIXTime -> Double) -> IO POSIXTime -> IO Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` IO POSIXTime
getPOSIXTime