module Simulation.Aivika.Trans.Operation
(
Operation,
newOperation,
newPreemptibleOperation,
operationProcess,
operationTotalUtilisationTime,
operationTotalPreemptionTime,
operationUtilisationTime,
operationPreemptionTime,
operationUtilisationFactor,
operationPreemptionFactor,
resetOperation,
operationSummary,
operationTotalUtilisationTimeChanged,
operationTotalUtilisationTimeChanged_,
operationTotalPreemptionTimeChanged,
operationTotalPreemptionTimeChanged_,
operationUtilisationTimeChanged,
operationUtilisationTimeChanged_,
operationPreemptionTimeChanged,
operationPreemptionTimeChanged_,
operationUtilisationFactorChanged,
operationUtilisationFactorChanged_,
operationPreemptionFactorChanged,
operationPreemptionFactorChanged_,
operationUtilising,
operationUtilised,
operationPreemptionBeginning,
operationPreemptionEnding,
operationChanged_) where
import Data.Monoid
import Control.Monad
import Control.Monad.Trans
import Simulation.Aivika.Trans.Ref.Base
import Simulation.Aivika.Trans.DES
import Simulation.Aivika.Trans.Parameter
import Simulation.Aivika.Trans.Simulation
import Simulation.Aivika.Trans.Dynamics
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Event
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.Cont
import Simulation.Aivika.Trans.Process
import Simulation.Aivika.Trans.Activity
import Simulation.Aivika.Trans.Server
import Simulation.Aivika.Trans.Statistics
data Operation m a b =
Operation { operationInitProcess :: a -> Process m b,
operationProcessPreemptible :: Bool,
operationStartTimeRef :: Ref m Double,
operationLastTimeRef :: Ref m Double,
operationTotalUtilisationTimeRef :: Ref m Double,
operationTotalPreemptionTimeRef :: Ref m Double,
operationUtilisationTimeRef :: Ref m (SamplingStats Double),
operationPreemptionTimeRef :: Ref m (SamplingStats Double),
operationUtilisingSource :: SignalSource m a,
operationUtilisedSource :: SignalSource m (a, b),
operationPreemptionBeginningSource :: SignalSource m a,
operationPreemptionEndingSource :: SignalSource m a
}
newOperation :: MonadDES m
=> (a -> Process m b)
-> Event m (Operation m a b)
{-# INLINABLE newOperation #-}
newOperation = newPreemptibleOperation False
newPreemptibleOperation :: MonadDES m
=> Bool
-> (a -> Process m b)
-> Event m (Operation m a b)
{-# INLINABLE newPreemptibleOperation #-}
newPreemptibleOperation preemptible provide =
do t0 <- liftDynamics time
r' <- liftSimulation $ newRef t0
r0 <- liftSimulation $ newRef t0
r1 <- liftSimulation $ newRef 0
r2 <- liftSimulation $ newRef 0
r3 <- liftSimulation $ newRef emptySamplingStats
r4 <- liftSimulation $ newRef emptySamplingStats
s1 <- liftSimulation newSignalSource
s2 <- liftSimulation newSignalSource
s3 <- liftSimulation newSignalSource
s4 <- liftSimulation newSignalSource
return Operation { operationInitProcess = provide,
operationProcessPreemptible = preemptible,
operationStartTimeRef = r',
operationLastTimeRef = r0,
operationTotalUtilisationTimeRef = r1,
operationTotalPreemptionTimeRef = r2,
operationUtilisationTimeRef = r3,
operationPreemptionTimeRef = r4,
operationUtilisingSource = s1,
operationUtilisedSource = s2,
operationPreemptionBeginningSource = s3,
operationPreemptionEndingSource = s4 }
operationProcess :: MonadDES m => Operation m a b -> a -> Process m b
{-# INLINABLE operationProcess #-}
operationProcess op a =
do t0 <- liftDynamics time
liftEvent $
triggerSignal (operationUtilisingSource op) a
(b, dt) <- if operationProcessPreemptible op
then operationProcessPreempting op a
else do b <- operationInitProcess op a
return (b, 0)
t1 <- liftDynamics time
liftEvent $
do modifyRef (operationTotalUtilisationTimeRef op) (+ (t1 - t0 - dt))
modifyRef (operationUtilisationTimeRef op) $
addSamplingStats (t1 - t0 - dt)
writeRef (operationLastTimeRef op) t1
triggerSignal (operationUtilisedSource op) (a, b)
return b
operationProcessPreempting :: MonadDES m => Operation m a b -> a -> Process m (b, Double)
{-# INLINABLE operationProcessPreempting #-}
operationProcessPreempting op a =
do pid <- processId
t0 <- liftDynamics time
rs <- liftSimulation $ newRef 0
r0 <- liftSimulation $ newRef t0
h1 <- liftEvent $
handleSignal (processPreemptionBeginning pid) $ \() ->
do t0 <- liftDynamics time
writeRef r0 t0
triggerSignal (operationPreemptionBeginningSource op) a
h2 <- liftEvent $
handleSignal (processPreemptionEnding pid) $ \() ->
do t0 <- readRef r0
t1 <- liftDynamics time
let dt = t1 - t0
modifyRef rs (+ dt)
modifyRef (operationTotalPreemptionTimeRef op) (+ dt)
modifyRef (operationPreemptionTimeRef op) $
addSamplingStats dt
writeRef (operationLastTimeRef op) t1
triggerSignal (operationPreemptionEndingSource op) a
let m1 =
do b <- operationInitProcess op a
dt <- liftEvent $ readRef rs
return (b, dt)
m2 =
liftEvent $
do disposeEvent h1
disposeEvent h2
finallyProcess m1 m2
operationTotalUtilisationTime :: MonadDES m => Operation m a b -> Event m Double
{-# INLINABLE operationTotalUtilisationTime #-}
operationTotalUtilisationTime op =
Event $ \p -> invokeEvent p $ readRef (operationTotalUtilisationTimeRef op)
operationTotalUtilisationTimeChanged :: MonadDES m => Operation m a b -> Signal m Double
{-# INLINABLE operationTotalUtilisationTimeChanged #-}
operationTotalUtilisationTimeChanged op =
mapSignalM (const $ operationTotalUtilisationTime op) (operationTotalUtilisationTimeChanged_ op)
operationTotalUtilisationTimeChanged_ :: MonadDES m => Operation m a b -> Signal m ()
{-# INLINABLE operationTotalUtilisationTimeChanged_ #-}
operationTotalUtilisationTimeChanged_ op =
mapSignal (const ()) (operationUtilised op)
operationTotalPreemptionTime :: MonadDES m => Operation m a b -> Event m Double
{-# INLINABLE operationTotalPreemptionTime #-}
operationTotalPreemptionTime op =
Event $ \p -> invokeEvent p $ readRef (operationTotalPreemptionTimeRef op)
operationTotalPreemptionTimeChanged :: MonadDES m => Operation m a b -> Signal m Double
{-# INLINABLE operationTotalPreemptionTimeChanged #-}
operationTotalPreemptionTimeChanged op =
mapSignalM (const $ operationTotalPreemptionTime op) (operationTotalPreemptionTimeChanged_ op)
operationTotalPreemptionTimeChanged_ :: MonadDES m => Operation m a b -> Signal m ()
{-# INLINABLE operationTotalPreemptionTimeChanged_ #-}
operationTotalPreemptionTimeChanged_ op =
mapSignal (const ()) (operationPreemptionEnding op)
operationUtilisationTime :: MonadDES m => Operation m a b -> Event m (SamplingStats Double)
{-# INLINABLE operationUtilisationTime #-}
operationUtilisationTime op =
Event $ \p -> invokeEvent p $ readRef (operationUtilisationTimeRef op)
operationUtilisationTimeChanged :: MonadDES m => Operation m a b -> Signal m (SamplingStats Double)
{-# INLINABLE operationUtilisationTimeChanged #-}
operationUtilisationTimeChanged op =
mapSignalM (const $ operationUtilisationTime op) (operationUtilisationTimeChanged_ op)
operationUtilisationTimeChanged_ :: MonadDES m => Operation m a b -> Signal m ()
{-# INLINABLE operationUtilisationTimeChanged_ #-}
operationUtilisationTimeChanged_ op =
mapSignal (const ()) (operationUtilised op)
operationPreemptionTime :: MonadDES m => Operation m a b -> Event m (SamplingStats Double)
{-# INLINABLE operationPreemptionTime #-}
operationPreemptionTime op =
Event $ \p -> invokeEvent p $ readRef (operationPreemptionTimeRef op)
operationPreemptionTimeChanged :: MonadDES m => Operation m a b -> Signal m (SamplingStats Double)
{-# INLINABLE operationPreemptionTimeChanged #-}
operationPreemptionTimeChanged op =
mapSignalM (const $ operationPreemptionTime op) (operationPreemptionTimeChanged_ op)
operationPreemptionTimeChanged_ :: MonadDES m => Operation m a b -> Signal m ()
{-# INLINABLE operationPreemptionTimeChanged_ #-}
operationPreemptionTimeChanged_ op =
mapSignal (const ()) (operationPreemptionEnding op)
operationUtilisationFactor :: MonadDES m => Operation m a b -> Event m Double
{-# INLINABLE operationUtilisationFactor #-}
operationUtilisationFactor op =
Event $ \p ->
do t0 <- invokeEvent p $ readRef (operationStartTimeRef op)
t1 <- invokeEvent p $ readRef (operationLastTimeRef op)
x <- invokeEvent p $ readRef (operationTotalUtilisationTimeRef op)
return (x / (t1 - t0))
operationUtilisationFactorChanged :: MonadDES m => Operation m a b -> Signal m Double
{-# INLINABLE operationUtilisationFactorChanged #-}
operationUtilisationFactorChanged op =
mapSignalM (const $ operationUtilisationFactor op) (operationUtilisationFactorChanged_ op)
operationUtilisationFactorChanged_ :: MonadDES m => Operation m a b -> Signal m ()
{-# INLINABLE operationUtilisationFactorChanged_ #-}
operationUtilisationFactorChanged_ op =
mapSignal (const ()) (operationUtilised op) <>
mapSignal (const ()) (operationPreemptionEnding op)
operationPreemptionFactor :: MonadDES m => Operation m a b -> Event m Double
{-# INLINABLE operationPreemptionFactor #-}
operationPreemptionFactor op =
Event $ \p ->
do t0 <- invokeEvent p $ readRef (operationStartTimeRef op)
t1 <- invokeEvent p $ readRef (operationLastTimeRef op)
x <- invokeEvent p $ readRef (operationTotalPreemptionTimeRef op)
return (x / (t1 - t0))
operationPreemptionFactorChanged :: MonadDES m => Operation m a b -> Signal m Double
{-# INLINABLE operationPreemptionFactorChanged #-}
operationPreemptionFactorChanged op =
mapSignalM (const $ operationPreemptionFactor op) (operationPreemptionFactorChanged_ op)
operationPreemptionFactorChanged_ :: MonadDES m => Operation m a b -> Signal m ()
{-# INLINABLE operationPreemptionFactorChanged_ #-}
operationPreemptionFactorChanged_ op =
mapSignal (const ()) (operationUtilised op) <>
mapSignal (const ()) (operationPreemptionEnding op)
operationUtilising :: MonadDES m => Operation m a b -> Signal m a
{-# INLINABLE operationUtilising #-}
operationUtilising = publishSignal . operationUtilisingSource
operationUtilised :: MonadDES m => Operation m a b -> Signal m (a, b)
{-# INLINABLE operationUtilised #-}
operationUtilised = publishSignal . operationUtilisedSource
operationPreemptionBeginning :: MonadDES m => Operation m a b -> Signal m a
{-# INLINABLE operationPreemptionBeginning #-}
operationPreemptionBeginning = publishSignal . operationPreemptionBeginningSource
operationPreemptionEnding :: MonadDES m => Operation m a b -> Signal m a
{-# INLINABLE operationPreemptionEnding #-}
operationPreemptionEnding = publishSignal . operationPreemptionEndingSource
operationChanged_ :: MonadDES m => Operation m a b -> Signal m ()
{-# INLINABLE operationChanged_ #-}
operationChanged_ op =
mapSignal (const ()) (operationUtilising op) <>
mapSignal (const ()) (operationUtilised op) <>
mapSignal (const ()) (operationPreemptionEnding op)
operationSummary :: MonadDES m => Operation m a b -> Int -> Event m ShowS
{-# INLINABLE operationSummary #-}
operationSummary op indent =
Event $ \p ->
do t0 <- invokeEvent p $ readRef (operationStartTimeRef op)
t1 <- invokeEvent p $ readRef (operationLastTimeRef op)
tx1 <- invokeEvent p $ readRef (operationTotalUtilisationTimeRef op)
tx2 <- invokeEvent p $ readRef (operationTotalPreemptionTimeRef op)
let xf1 = tx1 / (t1 - t0)
xf2 = tx2 / (t1 - t0)
xs1 <- invokeEvent p $ readRef (operationUtilisationTimeRef op)
xs2 <- invokeEvent p $ readRef (operationPreemptionTimeRef op)
let tab = replicate indent ' '
return $
showString tab .
showString "total utilisation time = " . shows tx1 .
showString "\n" .
showString tab .
showString "total preemption time = " . shows tx2 .
showString "\n" .
showString tab .
showString "utilisation factor (from 0 to 1) = " . shows xf1 .
showString "\n" .
showString tab .
showString "preemption factor (from 0 to 1) = " . shows xf2 .
showString "\n" .
showString tab .
showString "utilisation time:\n\n" .
samplingStatsSummary xs1 (2 + indent) .
showString "\n\n" .
showString tab .
showString "preemption time:\n\n" .
samplingStatsSummary xs2 (2 + indent)
resetOperation :: MonadDES m => Operation m a b -> Event m ()
{-# INLINABLE resetOperation #-}
resetOperation op =
do t0 <- liftDynamics time
writeRef (operationStartTimeRef op) t0
writeRef (operationLastTimeRef op) t0
writeRef (operationTotalUtilisationTimeRef op) 0
writeRef (operationTotalPreemptionTimeRef op) 0
writeRef (operationUtilisationTimeRef op) emptySamplingStats
writeRef (operationPreemptionTimeRef op) emptySamplingStats