module Data.Metrics.Timer (
Timer,
mkTimer,
timer,
time,
module Data.Metrics.Types
) where
import Control.Applicative
import Control.Lens
import Control.Lens.TH
import Control.Monad.Base
import Control.Monad.Primitive
import qualified Data.Metrics.MovingAverage.ExponentiallyWeighted as E
import qualified Data.Metrics.Histogram.Internal as H
import qualified Data.Metrics.Meter.Internal as M
import qualified Data.Metrics.Timer.Internal as P
import qualified Data.Metrics.Reservoir.ExponentiallyDecaying as R
import Data.Metrics.Internal
import Data.Metrics.Types
import Data.Primitive.MutVar
import Data.Time.Clock
import Data.Time.Clock.POSIX
import System.Random.MWC
data Timer m = Timer
{ fromTimer :: !(MutVar (PrimState m) P.Timer)
, timerGetTime :: !(m NominalDiffTime)
}
makeFields ''Timer
instance (MonadBase b m, PrimMonad b) => Clear b m (Timer b) where
clear t = liftBase $ do
ts <- timerGetTime t
updateRef (fromTimer t) $ P.clear ts
instance (MonadBase b m, PrimMonad b) => Update b m (Timer b) Double where
update t x = liftBase $ do
ts <- timerGetTime t
updateRef (fromTimer t) $ P.update ts x
instance (MonadBase b m, PrimMonad b) => Count b m (Timer b) where
count t = liftBase $ fmap P.count $ readMutVar (fromTimer t)
instance (MonadBase b m, PrimMonad b) => Statistics b m (Timer b) where
mean t = liftBase $ applyWithRef (fromTimer t) P.mean
stddev t = liftBase $ applyWithRef (fromTimer t) P.stddev
variance t = liftBase $ applyWithRef (fromTimer t) P.variance
maxVal t = liftBase $ P.maxVal <$> readMutVar (fromTimer t)
minVal t = liftBase $ P.minVal <$> readMutVar (fromTimer t)
instance (MonadBase b m, PrimMonad b) => Rate b m (Timer b) where
oneMinuteRate t = liftBase $ do
ts <- timerGetTime t
updateAndApplyToRef (fromTimer t) (P.tickIfNecessary ts) P.oneMinuteRate
fiveMinuteRate t = liftBase $ do
ts <- timerGetTime t
updateAndApplyToRef (fromTimer t) (P.tickIfNecessary ts) P.fiveMinuteRate
fifteenMinuteRate t = liftBase $ do
ts <- timerGetTime t
updateAndApplyToRef (fromTimer t) (P.tickIfNecessary ts) P.fifteenMinuteRate
meanRate t = liftBase $ do
ts <- timerGetTime t
applyWithRef (fromTimer t) (P.meanRate ts)
instance (MonadBase b m, PrimMonad b) => TakeSnapshot b m (Timer b) where
snapshot t = liftBase $ applyWithRef (fromTimer t) P.snapshot
mkTimer :: (MonadBase b m, PrimMonad b) => b NominalDiffTime -> Seed -> m (Timer b)
mkTimer mt s = liftBase $ do
t <- mt
let ewmaMeter = M.meterData 5 E.movingAverage t
let histogram = H.histogram $ R.reservoir 0.015 1028 t s
v <- newMutVar $ P.Timer ewmaMeter histogram
return $ Timer v mt
timer :: MonadBase IO m => m (Timer IO)
timer = liftBase $ do
s <- withSystemRandom (asGenIO $ save)
mkTimer getPOSIXTime s
time :: MonadBase IO m => Timer IO -> m a -> m a
time t m = do
let gt = t ^. getTime
ts <- liftBase gt
r <- m
tf <- liftBase gt
update t $ realToFrac $ tf ts
return r