-- |
-- Module     : Simulation.Aivika.Trans.Statistics.Accumulator
-- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.1
--
-- This small utility module allows accumulating the timing statistics based on 'Signalable' data
-- such as the queue size or the number of lost items in the queue.
--

module Simulation.Aivika.Trans.Statistics.Accumulator
       (-- * Timing Statistics Accumulator
        TimingStatsAccumulator,
        newTimingStatsAccumulator,
        timingStatsAccumulated) where

import Simulation.Aivika.Trans.Comp
import Simulation.Aivika.Trans.Simulation
import Simulation.Aivika.Trans.Dynamics
import Simulation.Aivika.Trans.Event
import Simulation.Aivika.Trans.Ref
import Simulation.Aivika.Trans.Statistics
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.DES

-- | Represents an accumulator for the timing statistics.
newtype TimingStatsAccumulator m a =
  TimingStatsAccumulator { forall (m :: * -> *) a.
TimingStatsAccumulator m a -> Ref m (TimingStats a)
timingStatsAccumulatedRef :: Ref m (TimingStats a) }

-- | Return the accumulated statistics.
timingStatsAccumulated :: MonadDES m => TimingStatsAccumulator m a -> Event m (TimingStats a)
{-# INLINABLE timingStatsAccumulated #-}
timingStatsAccumulated :: forall (m :: * -> *) a.
MonadDES m =>
TimingStatsAccumulator m a -> Event m (TimingStats a)
timingStatsAccumulated = Ref m (TimingStats a) -> Event m (TimingStats a)
forall (m :: * -> *) a. MonadDES m => Ref m a -> Event m a
readRef (Ref m (TimingStats a) -> Event m (TimingStats a))
-> (TimingStatsAccumulator m a -> Ref m (TimingStats a))
-> TimingStatsAccumulator m a
-> Event m (TimingStats a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimingStatsAccumulator m a -> Ref m (TimingStats a)
forall (m :: * -> *) a.
TimingStatsAccumulator m a -> Ref m (TimingStats a)
timingStatsAccumulatedRef

-- | Start gathering the timing statistics from the current simulation time. 
newTimingStatsAccumulator :: (MonadDES m, TimingData a) => Signalable m a -> Event m (TimingStatsAccumulator m a)
{-# INLINABLE newTimingStatsAccumulator #-}
newTimingStatsAccumulator :: forall (m :: * -> *) a.
(MonadDES m, TimingData a) =>
Signalable m a -> Event m (TimingStatsAccumulator m a)
newTimingStatsAccumulator Signalable m a
x =
  do Double
t0 <- Dynamics m Double -> Event m Double
forall a. Dynamics m a -> Event m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
DynamicsLift t m =>
Dynamics m a -> t m a
liftDynamics Dynamics m Double
forall (m :: * -> *). Monad m => Dynamics m Double
time
     a
a0 <- Signalable m a -> Event m a
forall (m :: * -> *) a. Signalable m a -> Event m a
readSignalable Signalable m a
x
     Ref m (TimingStats a)
r  <- Simulation m (Ref m (TimingStats a))
-> Event m (Ref m (TimingStats a))
forall a. Simulation m a -> Event m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
SimulationLift t m =>
Simulation m a -> t m a
liftSimulation (Simulation m (Ref m (TimingStats a))
 -> Event m (Ref m (TimingStats a)))
-> Simulation m (Ref m (TimingStats a))
-> Event m (Ref m (TimingStats a))
forall a b. (a -> b) -> a -> b
$ TimingStats a -> Simulation m (Ref m (TimingStats a))
forall (m :: * -> *) a. MonadDES m => a -> Simulation m (Ref m a)
newRef (Double -> a -> TimingStats a
forall a. TimingData a => Double -> a -> TimingStats a
returnTimingStats Double
t0 a
a0)
     Signal m a -> (a -> Event m ()) -> Event m ()
forall (m :: * -> *) a.
MonadDES m =>
Signal m a -> (a -> Event m ()) -> Event m ()
handleSignal_ (Signalable m a -> Signal m a
forall (m :: * -> *) a. MonadDES m => Signalable m a -> Signal m a
signalableChanged Signalable m a
x) ((a -> Event m ()) -> Event m ())
-> (a -> Event m ()) -> Event m ()
forall a b. (a -> b) -> a -> b
$ \a
a ->
       do Double
t <- Dynamics m Double -> Event m Double
forall a. Dynamics m a -> Event m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
DynamicsLift t m =>
Dynamics m a -> t m a
liftDynamics Dynamics m Double
forall (m :: * -> *). Monad m => Dynamics m Double
time
          Ref m (TimingStats a)
-> (TimingStats a -> TimingStats a) -> Event m ()
forall (m :: * -> *) a.
MonadDES m =>
Ref m a -> (a -> a) -> Event m ()
modifyRef Ref m (TimingStats a)
r ((TimingStats a -> TimingStats a) -> Event m ())
-> (TimingStats a -> TimingStats a) -> Event m ()
forall a b. (a -> b) -> a -> b
$ Double -> a -> TimingStats a -> TimingStats a
forall a.
TimingData a =>
Double -> a -> TimingStats a -> TimingStats a
addTimingStats Double
t a
a
     TimingStatsAccumulator m a -> Event m (TimingStatsAccumulator m a)
forall a. a -> Event m a
forall (m :: * -> *) a. Monad m => a -> m a
return TimingStatsAccumulator { timingStatsAccumulatedRef :: Ref m (TimingStats a)
timingStatsAccumulatedRef = Ref m (TimingStats a)
r }