module Simulation.Aivika.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.IORef
import Data.Monoid
import Control.Monad
import Control.Monad.Trans
import Simulation.Aivika.Internal.Specs
import Simulation.Aivika.Simulation
import Simulation.Aivika.Dynamics
import Simulation.Aivika.Internal.Event
import Simulation.Aivika.Signal
import Simulation.Aivika.Cont
import Simulation.Aivika.Process
import Simulation.Aivika.Activity
import Simulation.Aivika.Server
import Simulation.Aivika.Statistics
data Operation a b =
Operation { operationInitProcess :: a -> Process b,
operationProcessPreemptible :: Bool,
operationStartTimeRef :: IORef Double,
operationLastTimeRef :: IORef Double,
operationTotalUtilisationTimeRef :: IORef Double,
operationTotalPreemptionTimeRef :: IORef Double,
operationUtilisationTimeRef :: IORef (SamplingStats Double),
operationPreemptionTimeRef :: IORef (SamplingStats Double),
operationUtilisingSource :: SignalSource a,
operationUtilisedSource :: SignalSource (a, b),
operationPreemptionBeginningSource :: SignalSource a,
operationPreemptionEndingSource :: SignalSource a
}
newOperation :: (a -> Process b)
-> Event (Operation a b)
newOperation = newPreemptibleOperation False
newPreemptibleOperation :: Bool
-> (a -> Process b)
-> Event (Operation a b)
newPreemptibleOperation preemptible provide =
do t0 <- liftDynamics time
r' <- liftIO $ newIORef t0
r0 <- liftIO $ newIORef t0
r1 <- liftIO $ newIORef 0
r2 <- liftIO $ newIORef 0
r3 <- liftIO $ newIORef emptySamplingStats
r4 <- liftIO $ newIORef 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 :: Operation a b -> a -> Process b
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 liftIO $
do modifyIORef' (operationTotalUtilisationTimeRef op) (+ (t1 - t0 - dt))
modifyIORef' (operationUtilisationTimeRef op) $
addSamplingStats (t1 - t0 - dt)
writeIORef (operationLastTimeRef op) t1
triggerSignal (operationUtilisedSource op) (a, b)
return b
operationProcessPreempting :: Operation a b -> a -> Process (b, Double)
operationProcessPreempting op a =
do pid <- processId
t0 <- liftDynamics time
rs <- liftIO $ newIORef 0
r0 <- liftIO $ newIORef t0
h1 <- liftEvent $
handleSignal (processPreemptionBeginning pid) $ \() ->
do t0 <- liftDynamics time
liftIO $ writeIORef r0 t0
triggerSignal (operationPreemptionBeginningSource op) a
h2 <- liftEvent $
handleSignal (processPreemptionEnding pid) $ \() ->
do t0 <- liftIO $ readIORef r0
t1 <- liftDynamics time
let dt = t1 - t0
liftIO $
do modifyIORef' rs (+ dt)
modifyIORef' (operationTotalPreemptionTimeRef op) (+ dt)
modifyIORef' (operationPreemptionTimeRef op) $
addSamplingStats dt
writeIORef (operationLastTimeRef op) t1
triggerSignal (operationPreemptionEndingSource op) a
let m1 =
do b <- operationInitProcess op a
dt <- liftIO $ readIORef rs
return (b, dt)
m2 =
liftEvent $
do disposeEvent h1
disposeEvent h2
finallyProcess m1 m2
operationTotalUtilisationTime :: Operation a b -> Event Double
operationTotalUtilisationTime op =
Event $ \p -> readIORef (operationTotalUtilisationTimeRef op)
operationTotalUtilisationTimeChanged :: Operation a b -> Signal Double
operationTotalUtilisationTimeChanged op =
mapSignalM (const $ operationTotalUtilisationTime op) (operationTotalUtilisationTimeChanged_ op)
operationTotalUtilisationTimeChanged_ :: Operation a b -> Signal ()
operationTotalUtilisationTimeChanged_ op =
mapSignal (const ()) (operationUtilised op)
operationTotalPreemptionTime :: Operation a b -> Event Double
operationTotalPreemptionTime op =
Event $ \p -> readIORef (operationTotalPreemptionTimeRef op)
operationTotalPreemptionTimeChanged :: Operation a b -> Signal Double
operationTotalPreemptionTimeChanged op =
mapSignalM (const $ operationTotalPreemptionTime op) (operationTotalPreemptionTimeChanged_ op)
operationTotalPreemptionTimeChanged_ :: Operation a b -> Signal ()
operationTotalPreemptionTimeChanged_ op =
mapSignal (const ()) (operationPreemptionEnding op)
operationUtilisationTime :: Operation a b -> Event (SamplingStats Double)
operationUtilisationTime op =
Event $ \p -> readIORef (operationUtilisationTimeRef op)
operationUtilisationTimeChanged :: Operation a b -> Signal (SamplingStats Double)
operationUtilisationTimeChanged op =
mapSignalM (const $ operationUtilisationTime op) (operationUtilisationTimeChanged_ op)
operationUtilisationTimeChanged_ :: Operation a b -> Signal ()
operationUtilisationTimeChanged_ op =
mapSignal (const ()) (operationUtilised op)
operationPreemptionTime :: Operation a b -> Event (SamplingStats Double)
operationPreemptionTime op =
Event $ \p -> readIORef (operationPreemptionTimeRef op)
operationPreemptionTimeChanged :: Operation a b -> Signal (SamplingStats Double)
operationPreemptionTimeChanged op =
mapSignalM (const $ operationPreemptionTime op) (operationPreemptionTimeChanged_ op)
operationPreemptionTimeChanged_ :: Operation a b -> Signal ()
operationPreemptionTimeChanged_ op =
mapSignal (const ()) (operationPreemptionEnding op)
operationUtilisationFactor :: Operation a b -> Event Double
operationUtilisationFactor op =
Event $ \p ->
do t0 <- readIORef (operationStartTimeRef op)
t1 <- readIORef (operationLastTimeRef op)
x <- readIORef (operationTotalUtilisationTimeRef op)
return (x / (t1 - t0))
operationUtilisationFactorChanged :: Operation a b -> Signal Double
operationUtilisationFactorChanged op =
mapSignalM (const $ operationUtilisationFactor op) (operationUtilisationFactorChanged_ op)
operationUtilisationFactorChanged_ :: Operation a b -> Signal ()
operationUtilisationFactorChanged_ op =
mapSignal (const ()) (operationUtilised op) <>
mapSignal (const ()) (operationPreemptionEnding op)
operationPreemptionFactor :: Operation a b -> Event Double
operationPreemptionFactor op =
Event $ \p ->
do t0 <- readIORef (operationStartTimeRef op)
t1 <- readIORef (operationLastTimeRef op)
x <- readIORef (operationTotalPreemptionTimeRef op)
return (x / (t1 - t0))
operationPreemptionFactorChanged :: Operation a b -> Signal Double
operationPreemptionFactorChanged op =
mapSignalM (const $ operationPreemptionFactor op) (operationPreemptionFactorChanged_ op)
operationPreemptionFactorChanged_ :: Operation a b -> Signal ()
operationPreemptionFactorChanged_ op =
mapSignal (const ()) (operationUtilised op) <>
mapSignal (const ()) (operationPreemptionEnding op)
operationUtilising :: Operation a b -> Signal a
operationUtilising = publishSignal . operationUtilisingSource
operationUtilised :: Operation a b -> Signal (a, b)
operationUtilised = publishSignal . operationUtilisedSource
operationPreemptionBeginning :: Operation a b -> Signal a
operationPreemptionBeginning = publishSignal . operationPreemptionBeginningSource
operationPreemptionEnding :: Operation a b -> Signal a
operationPreemptionEnding = publishSignal . operationPreemptionEndingSource
operationChanged_ :: Operation a b -> Signal ()
operationChanged_ op =
mapSignal (const ()) (operationUtilising op) <>
mapSignal (const ()) (operationUtilised op) <>
mapSignal (const ()) (operationPreemptionEnding op)
operationSummary :: Operation a b -> Int -> Event ShowS
operationSummary op indent =
Event $ \p ->
do t0 <- readIORef (operationStartTimeRef op)
t1 <- readIORef (operationLastTimeRef op)
tx1 <- readIORef (operationTotalUtilisationTimeRef op)
tx2 <- readIORef (operationTotalPreemptionTimeRef op)
let xf1 = tx1 / (t1 - t0)
xf2 = tx2 / (t1 - t0)
xs1 <- readIORef (operationUtilisationTimeRef op)
xs2 <- readIORef (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 :: Operation a b -> Event ()
resetOperation op =
Event $ \p ->
do let t0 = pointTime p
writeIORef (operationStartTimeRef op) t0
writeIORef (operationLastTimeRef op) t0
writeIORef (operationTotalUtilisationTimeRef op) 0
writeIORef (operationTotalPreemptionTimeRef op) 0
writeIORef (operationUtilisationTimeRef op) emptySamplingStats
writeIORef (operationPreemptionTimeRef op) emptySamplingStats