-- |
-- Module     : Simulation.Aivika.Operation
-- 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
--
-- It defines a stateless activity, some simplification of 'Server' and 'Activity'.
module Simulation.Aivika.Operation
       (-- * Operation
        Operation,
        newOperation,
        newPreemptibleOperation,
        -- * Processing
        operationProcess,
        -- * Operation Properties
        operationTotalUtilisationTime,
        operationTotalPreemptionTime,
        operationUtilisationTime,
        operationPreemptionTime,
        operationUtilisationFactor,
        operationPreemptionFactor,
        -- * Statistics Reset
        resetOperation,
        -- * Summary
        operationSummary,
        -- * Derived Signals for Properties
        operationTotalUtilisationTimeChanged,
        operationTotalUtilisationTimeChanged_,
        operationTotalPreemptionTimeChanged,
        operationTotalPreemptionTimeChanged_,
        operationUtilisationTimeChanged,
        operationUtilisationTimeChanged_,
        operationPreemptionTimeChanged,
        operationPreemptionTimeChanged_,
        operationUtilisationFactorChanged,
        operationUtilisationFactorChanged_,
        operationPreemptionFactorChanged,
        operationPreemptionFactorChanged_,
        -- * Basic Signals
        operationUtilising,
        operationUtilised,
        operationPreemptionBeginning,
        operationPreemptionEnding,
        -- * Overall Signal
        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

-- | Like 'Server' it models an activity that takes @a@ and provides @b@.
-- But unlike the former this kind of activity has no state. Also it is destined
-- to be used within 'Process' computations.
data Operation a b =
  Operation { forall a b. Operation a b -> a -> Process b
operationInitProcess :: a -> Process b,
              -- ^ Provide @b@ by specified @a@.
              forall a b. Operation a b -> Bool
operationProcessPreemptible :: Bool,
              -- ^ Whether the process is preemptible.
              forall a b. Operation a b -> IORef Double
operationStartTimeRef :: IORef Double,
              -- ^ The start time of creating the operation.
              forall a b. Operation a b -> IORef Double
operationLastTimeRef :: IORef Double,
              -- ^ The last time of utilising the operation activity.
              forall a b. Operation a b -> IORef Double
operationTotalUtilisationTimeRef :: IORef Double,
              -- ^ The counted total time of utilising the activity.
              forall a b. Operation a b -> IORef Double
operationTotalPreemptionTimeRef :: IORef Double,
              -- ^ The counted total time when the activity was preempted. 
              forall a b. Operation a b -> IORef (SamplingStats Double)
operationUtilisationTimeRef :: IORef (SamplingStats Double),
              -- ^ The statistics for the utilisation time.
              forall a b. Operation a b -> IORef (SamplingStats Double)
operationPreemptionTimeRef :: IORef (SamplingStats Double),
              -- ^ The statistics for the time when the activity was preempted.
              forall a b. Operation a b -> SignalSource a
operationUtilisingSource :: SignalSource a,
              -- ^ A signal raised when starting to utilise the activity.
              forall a b. Operation a b -> SignalSource (a, b)
operationUtilisedSource :: SignalSource (a, b),
              -- ^ A signal raised when the activity has been utilised.
              forall a b. Operation a b -> SignalSource a
operationPreemptionBeginningSource :: SignalSource a,
              -- ^ A signal raised when the utilisation was preempted.
              forall a b. Operation a b -> SignalSource a
operationPreemptionEndingSource :: SignalSource a
              -- ^ A signal raised when the utilisation was proceeded after it had been preempted earlier.
           }

-- | Create a new operation that can provide output @b@ by input @a@.
--
-- By default, it is assumed that the activity utilisation cannot be preempted,
-- because the handling of possible task preemption is rather costly
-- operation.
newOperation :: (a -> Process b)
                -- ^ provide an output by the specified input
                -> Event (Operation a b)
newOperation :: forall a b. (a -> Process b) -> Event (Operation a b)
newOperation = forall a b. Bool -> (a -> Process b) -> Event (Operation a b)
newPreemptibleOperation Bool
False

-- | Create a new operation that can provide output @b@ by input @a@.
newPreemptibleOperation :: Bool
                           -- ^ whether the activity can be preempted
                           -> (a -> Process b)
                           -- ^ provide an output by the specified input
                           -> Event (Operation a b)
newPreemptibleOperation :: forall a b. Bool -> (a -> Process b) -> Event (Operation a b)
newPreemptibleOperation Bool
preemptible a -> Process b
provide =
  do Double
t0 <- forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
     IORef Double
r' <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Double
t0
     IORef Double
r0 <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Double
t0
     IORef Double
r1 <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Double
0
     IORef Double
r2 <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Double
0
     IORef (SamplingStats Double)
r3 <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef forall a. SamplingData a => SamplingStats a
emptySamplingStats
     IORef (SamplingStats Double)
r4 <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef forall a. SamplingData a => SamplingStats a
emptySamplingStats
     SignalSource a
s1 <- forall (m :: * -> *) a. SimulationLift m => Simulation a -> m a
liftSimulation forall a. Simulation (SignalSource a)
newSignalSource
     SignalSource (a, b)
s2 <- forall (m :: * -> *) a. SimulationLift m => Simulation a -> m a
liftSimulation forall a. Simulation (SignalSource a)
newSignalSource
     SignalSource a
s3 <- forall (m :: * -> *) a. SimulationLift m => Simulation a -> m a
liftSimulation forall a. Simulation (SignalSource a)
newSignalSource
     SignalSource a
s4 <- forall (m :: * -> *) a. SimulationLift m => Simulation a -> m a
liftSimulation forall a. Simulation (SignalSource a)
newSignalSource
     forall (m :: * -> *) a. Monad m => a -> m a
return Operation { operationInitProcess :: a -> Process b
operationInitProcess = a -> Process b
provide,
                        operationProcessPreemptible :: Bool
operationProcessPreemptible = Bool
preemptible,
                        operationStartTimeRef :: IORef Double
operationStartTimeRef = IORef Double
r',
                        operationLastTimeRef :: IORef Double
operationLastTimeRef = IORef Double
r0,
                        operationTotalUtilisationTimeRef :: IORef Double
operationTotalUtilisationTimeRef = IORef Double
r1,
                        operationTotalPreemptionTimeRef :: IORef Double
operationTotalPreemptionTimeRef = IORef Double
r2,
                        operationUtilisationTimeRef :: IORef (SamplingStats Double)
operationUtilisationTimeRef = IORef (SamplingStats Double)
r3,
                        operationPreemptionTimeRef :: IORef (SamplingStats Double)
operationPreemptionTimeRef = IORef (SamplingStats Double)
r4,
                        operationUtilisingSource :: SignalSource a
operationUtilisingSource = SignalSource a
s1,
                        operationUtilisedSource :: SignalSource (a, b)
operationUtilisedSource = SignalSource (a, b)
s2,
                        operationPreemptionBeginningSource :: SignalSource a
operationPreemptionBeginningSource = SignalSource a
s3,
                        operationPreemptionEndingSource :: SignalSource a
operationPreemptionEndingSource = SignalSource a
s4 }

-- | Return a computation for the specified operation. It updates internal counters.
--
-- The computation can be used only within one process at any time.
operationProcess :: Operation a b -> a -> Process b
operationProcess :: forall a b. Operation a b -> a -> Process b
operationProcess Operation a b
op a
a =
  do Double
t0 <- forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
     forall (m :: * -> *) a. EventLift m => Event a -> m a
liftEvent forall a b. (a -> b) -> a -> b
$
       forall a. SignalSource a -> a -> Event ()
triggerSignal (forall a b. Operation a b -> SignalSource a
operationUtilisingSource Operation a b
op) a
a
     -- utilise the activity
     (b
b, Double
dt) <- if forall a b. Operation a b -> Bool
operationProcessPreemptible Operation a b
op
                then forall a b. Operation a b -> a -> Process (b, Double)
operationProcessPreempting Operation a b
op a
a
                else do b
b <- forall a b. Operation a b -> a -> Process b
operationInitProcess Operation a b
op a
a
                        forall (m :: * -> *) a. Monad m => a -> m a
return (b
b, Double
0)
     Double
t1 <- forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
     forall (m :: * -> *) a. EventLift m => Event a -> m a
liftEvent forall a b. (a -> b) -> a -> b
$
       do forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$
            do forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (forall a b. Operation a b -> IORef Double
operationTotalUtilisationTimeRef Operation a b
op) (forall a. Num a => a -> a -> a
+ (Double
t1 forall a. Num a => a -> a -> a
- Double
t0 forall a. Num a => a -> a -> a
- Double
dt))
               forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (forall a b. Operation a b -> IORef (SamplingStats Double)
operationUtilisationTimeRef Operation a b
op) forall a b. (a -> b) -> a -> b
$
                 forall a. SamplingData a => a -> SamplingStats a -> SamplingStats a
addSamplingStats (Double
t1 forall a. Num a => a -> a -> a
- Double
t0 forall a. Num a => a -> a -> a
- Double
dt)
               forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef Double
operationLastTimeRef Operation a b
op) Double
t1
          forall a. SignalSource a -> a -> Event ()
triggerSignal (forall a b. Operation a b -> SignalSource (a, b)
operationUtilisedSource Operation a b
op) (a
a, b
b)
     forall (m :: * -> *) a. Monad m => a -> m a
return b
b

-- | Process the input with ability to handle a possible preemption.
operationProcessPreempting :: Operation a b -> a -> Process (b, Double)
operationProcessPreempting :: forall a b. Operation a b -> a -> Process (b, Double)
operationProcessPreempting Operation a b
op a
a =
  do ProcessId
pid <- Process ProcessId
processId
     Double
t0  <- forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
     IORef Double
rs  <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Double
0
     IORef Double
r0  <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Double
t0
     DisposableEvent
h1  <- forall (m :: * -> *) a. EventLift m => Event a -> m a
liftEvent forall a b. (a -> b) -> a -> b
$
            forall a. Signal a -> (a -> Event ()) -> Event DisposableEvent
handleSignal (ProcessId -> Signal ()
processPreemptionBeginning ProcessId
pid) forall a b. (a -> b) -> a -> b
$ \() ->
            do Double
t0 <- forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
               forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> a -> IO ()
writeIORef IORef Double
r0 Double
t0
               forall a. SignalSource a -> a -> Event ()
triggerSignal (forall a b. Operation a b -> SignalSource a
operationPreemptionBeginningSource Operation a b
op) a
a
     DisposableEvent
h2  <- forall (m :: * -> *) a. EventLift m => Event a -> m a
liftEvent forall a b. (a -> b) -> a -> b
$
            forall a. Signal a -> (a -> Event ()) -> Event DisposableEvent
handleSignal (ProcessId -> Signal ()
processPreemptionEnding ProcessId
pid) forall a b. (a -> b) -> a -> b
$ \() ->
            do Double
t0 <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> IO a
readIORef IORef Double
r0
               Double
t1 <- forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
               let dt :: Double
dt = Double
t1 forall a. Num a => a -> a -> a
- Double
t0
               forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$
                 do forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' IORef Double
rs (forall a. Num a => a -> a -> a
+ Double
dt)
                    forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (forall a b. Operation a b -> IORef Double
operationTotalPreemptionTimeRef Operation a b
op) (forall a. Num a => a -> a -> a
+ Double
dt)
                    forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (forall a b. Operation a b -> IORef (SamplingStats Double)
operationPreemptionTimeRef Operation a b
op) forall a b. (a -> b) -> a -> b
$
                      forall a. SamplingData a => a -> SamplingStats a -> SamplingStats a
addSamplingStats Double
dt
                    forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef Double
operationLastTimeRef Operation a b
op) Double
t1
               forall a. SignalSource a -> a -> Event ()
triggerSignal (forall a b. Operation a b -> SignalSource a
operationPreemptionEndingSource Operation a b
op) a
a 
     let m1 :: Process (b, Double)
m1 =
           do b
b <- forall a b. Operation a b -> a -> Process b
operationInitProcess Operation a b
op a
a
              Double
dt <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> IO a
readIORef IORef Double
rs
              forall (m :: * -> *) a. Monad m => a -> m a
return (b
b, Double
dt)
         m2 :: Process ()
m2 =
           forall (m :: * -> *) a. EventLift m => Event a -> m a
liftEvent forall a b. (a -> b) -> a -> b
$
           do DisposableEvent -> Event ()
disposeEvent DisposableEvent
h1
              DisposableEvent -> Event ()
disposeEvent DisposableEvent
h2
     forall a b. Process a -> Process b -> Process a
finallyProcess Process (b, Double)
m1 Process ()
m2

-- | Return the counted total time when the operation activity was utilised.
--
-- The value returned changes discretely and it is usually delayed relative
-- to the current simulation time.
--
-- See also 'operationTotalUtilisationTimeChanged' and 'operationTotalUtilisationTimeChanged_'.
operationTotalUtilisationTime :: Operation a b -> Event Double
operationTotalUtilisationTime :: forall a b. Operation a b -> Event Double
operationTotalUtilisationTime Operation a b
op =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p -> forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationTotalUtilisationTimeRef Operation a b
op)
  
-- | Signal when the 'operationTotalUtilisationTime' property value has changed.
operationTotalUtilisationTimeChanged :: Operation a b -> Signal Double
operationTotalUtilisationTimeChanged :: forall a b. Operation a b -> Signal Double
operationTotalUtilisationTimeChanged Operation a b
op =
  forall a b. (a -> Event b) -> Signal a -> Signal b
mapSignalM (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. Operation a b -> Event Double
operationTotalUtilisationTime Operation a b
op) (forall a b. Operation a b -> Signal ()
operationTotalUtilisationTimeChanged_ Operation a b
op)
  
-- | Signal when the 'operationTotalUtilisationTime' property value has changed.
operationTotalUtilisationTimeChanged_ :: Operation a b -> Signal ()
operationTotalUtilisationTimeChanged_ :: forall a b. Operation a b -> Signal ()
operationTotalUtilisationTimeChanged_ Operation a b
op =
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal (a, b)
operationUtilised Operation a b
op)

-- | Return the counted total time when the operation activity was preemted waiting for
-- the further proceeding.
--
-- The value returned changes discretely and it is usually delayed relative
-- to the current simulation time.
--
-- See also 'operationTotalPreemptionTimeChanged' and 'operationTotalPreemptionTimeChanged_'.
operationTotalPreemptionTime :: Operation a b -> Event Double
operationTotalPreemptionTime :: forall a b. Operation a b -> Event Double
operationTotalPreemptionTime Operation a b
op =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p -> forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationTotalPreemptionTimeRef Operation a b
op)
  
-- | Signal when the 'operationTotalPreemptionTime' property value has changed.
operationTotalPreemptionTimeChanged :: Operation a b -> Signal Double
operationTotalPreemptionTimeChanged :: forall a b. Operation a b -> Signal Double
operationTotalPreemptionTimeChanged Operation a b
op =
  forall a b. (a -> Event b) -> Signal a -> Signal b
mapSignalM (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. Operation a b -> Event Double
operationTotalPreemptionTime Operation a b
op) (forall a b. Operation a b -> Signal ()
operationTotalPreemptionTimeChanged_ Operation a b
op)
  
-- | Signal when the 'operationTotalPreemptionTime' property value has changed.
operationTotalPreemptionTimeChanged_ :: Operation a b -> Signal ()
operationTotalPreemptionTimeChanged_ :: forall a b. Operation a b -> Signal ()
operationTotalPreemptionTimeChanged_ Operation a b
op =
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal a
operationPreemptionEnding Operation a b
op)

-- | Return the statistics for the time when the operation activity was utilised.
--
-- The value returned changes discretely and it is usually delayed relative
-- to the current simulation time.
--
-- See also 'operationUtilisationTimeChanged' and 'operationUtilisationTimeChanged_'.
operationUtilisationTime :: Operation a b -> Event (SamplingStats Double)
operationUtilisationTime :: forall a b. Operation a b -> Event (SamplingStats Double)
operationUtilisationTime Operation a b
op =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p -> forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef (SamplingStats Double)
operationUtilisationTimeRef Operation a b
op)
  
-- | Signal when the 'operationUtilisationTime' property value has changed.
operationUtilisationTimeChanged :: Operation a b -> Signal (SamplingStats Double)
operationUtilisationTimeChanged :: forall a b. Operation a b -> Signal (SamplingStats Double)
operationUtilisationTimeChanged Operation a b
op =
  forall a b. (a -> Event b) -> Signal a -> Signal b
mapSignalM (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. Operation a b -> Event (SamplingStats Double)
operationUtilisationTime Operation a b
op) (forall a b. Operation a b -> Signal ()
operationUtilisationTimeChanged_ Operation a b
op)
  
-- | Signal when the 'operationUtilisationTime' property value has changed.
operationUtilisationTimeChanged_ :: Operation a b -> Signal ()
operationUtilisationTimeChanged_ :: forall a b. Operation a b -> Signal ()
operationUtilisationTimeChanged_ Operation a b
op =
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal (a, b)
operationUtilised Operation a b
op)

-- | Return the statistics for the time when the operation activity was preempted
-- waiting for the further proceeding.
--
-- The value returned changes discretely and it is usually delayed relative
-- to the current simulation time.
--
-- See also 'operationPreemptionTimeChanged' and 'operationPreemptionTimeChanged_'.
operationPreemptionTime :: Operation a b -> Event (SamplingStats Double)
operationPreemptionTime :: forall a b. Operation a b -> Event (SamplingStats Double)
operationPreemptionTime Operation a b
op =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p -> forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef (SamplingStats Double)
operationPreemptionTimeRef Operation a b
op)
  
-- | Signal when the 'operationPreemptionTime' property value has changed.
operationPreemptionTimeChanged :: Operation a b -> Signal (SamplingStats Double)
operationPreemptionTimeChanged :: forall a b. Operation a b -> Signal (SamplingStats Double)
operationPreemptionTimeChanged Operation a b
op =
  forall a b. (a -> Event b) -> Signal a -> Signal b
mapSignalM (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. Operation a b -> Event (SamplingStats Double)
operationPreemptionTime Operation a b
op) (forall a b. Operation a b -> Signal ()
operationPreemptionTimeChanged_ Operation a b
op)
  
-- | Signal when the 'operationPreemptionTime' property value has changed.
operationPreemptionTimeChanged_ :: Operation a b -> Signal ()
operationPreemptionTimeChanged_ :: forall a b. Operation a b -> Signal ()
operationPreemptionTimeChanged_ Operation a b
op =
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal a
operationPreemptionEnding Operation a b
op)
  
-- | It returns the factor changing from 0 to 1, which estimates how often
-- the operation activity was utilised since the time of creating the operation.
--
-- The value returned changes discretely and it is usually delayed relative
-- to the current simulation time.
--
-- See also 'operationUtilisationFactorChanged' and 'operationUtilisationFactorChanged_'.
operationUtilisationFactor :: Operation a b -> Event Double
operationUtilisationFactor :: forall a b. Operation a b -> Event Double
operationUtilisationFactor Operation a b
op =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do Double
t0 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationStartTimeRef Operation a b
op)
     Double
t1 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationLastTimeRef Operation a b
op)
     Double
x  <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationTotalUtilisationTimeRef Operation a b
op)
     forall (m :: * -> *) a. Monad m => a -> m a
return (Double
x forall a. Fractional a => a -> a -> a
/ (Double
t1 forall a. Num a => a -> a -> a
- Double
t0))
  
-- | Signal when the 'operationUtilisationFactor' property value has changed.
operationUtilisationFactorChanged :: Operation a b -> Signal Double
operationUtilisationFactorChanged :: forall a b. Operation a b -> Signal Double
operationUtilisationFactorChanged Operation a b
op =
  forall a b. (a -> Event b) -> Signal a -> Signal b
mapSignalM (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. Operation a b -> Event Double
operationUtilisationFactor Operation a b
op) (forall a b. Operation a b -> Signal ()
operationUtilisationFactorChanged_ Operation a b
op)
  
-- | Signal when the 'operationUtilisationFactor' property value has changed.
operationUtilisationFactorChanged_ :: Operation a b -> Signal ()
operationUtilisationFactorChanged_ :: forall a b. Operation a b -> Signal ()
operationUtilisationFactorChanged_ Operation a b
op =
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal (a, b)
operationUtilised Operation a b
op) forall a. Semigroup a => a -> a -> a
<>
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal a
operationPreemptionEnding Operation a b
op)
  
-- | It returns the factor changing from 0 to 1, which estimates how often
-- the operation activity was preempted waiting for the further proceeding
-- since the time of creating the operation.
--
-- The value returned changes discretely and it is usually delayed relative
-- to the current simulation time.
--
-- See also 'operationPreemptionFactorChanged' and 'operationPreemptionFactorChanged_'.
operationPreemptionFactor :: Operation a b -> Event Double
operationPreemptionFactor :: forall a b. Operation a b -> Event Double
operationPreemptionFactor Operation a b
op =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do Double
t0 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationStartTimeRef Operation a b
op)
     Double
t1 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationLastTimeRef Operation a b
op)
     Double
x  <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationTotalPreemptionTimeRef Operation a b
op)
     forall (m :: * -> *) a. Monad m => a -> m a
return (Double
x forall a. Fractional a => a -> a -> a
/ (Double
t1 forall a. Num a => a -> a -> a
- Double
t0))
  
-- | Signal when the 'operationPreemptionFactor' property value has changed.
operationPreemptionFactorChanged :: Operation a b -> Signal Double
operationPreemptionFactorChanged :: forall a b. Operation a b -> Signal Double
operationPreemptionFactorChanged Operation a b
op =
  forall a b. (a -> Event b) -> Signal a -> Signal b
mapSignalM (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. Operation a b -> Event Double
operationPreemptionFactor Operation a b
op) (forall a b. Operation a b -> Signal ()
operationPreemptionFactorChanged_ Operation a b
op)
  
-- | Signal when the 'operationPreemptionFactor' property value has changed.
operationPreemptionFactorChanged_ :: Operation a b -> Signal ()
operationPreemptionFactorChanged_ :: forall a b. Operation a b -> Signal ()
operationPreemptionFactorChanged_ Operation a b
op =
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal (a, b)
operationUtilised Operation a b
op) forall a. Semigroup a => a -> a -> a
<>
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal a
operationPreemptionEnding Operation a b
op)
  
-- | Raised when starting to utilise the operation activity after a new input task is received.
operationUtilising :: Operation a b -> Signal a
operationUtilising :: forall a b. Operation a b -> Signal a
operationUtilising = forall a. SignalSource a -> Signal a
publishSignal forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. Operation a b -> SignalSource a
operationUtilisingSource

-- | Raised when the operation activity has been utilised after the current task is processed.
operationUtilised :: Operation a b -> Signal (a, b)
operationUtilised :: forall a b. Operation a b -> Signal (a, b)
operationUtilised = forall a. SignalSource a -> Signal a
publishSignal forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. Operation a b -> SignalSource (a, b)
operationUtilisedSource

-- | Raised when the operation activity utilisation was preempted.
operationPreemptionBeginning :: Operation a b -> Signal a
operationPreemptionBeginning :: forall a b. Operation a b -> Signal a
operationPreemptionBeginning = forall a. SignalSource a -> Signal a
publishSignal forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. Operation a b -> SignalSource a
operationPreemptionBeginningSource

-- | Raised when the operation activity utilisation was proceeded after it had been preempted earlier.
operationPreemptionEnding :: Operation a b -> Signal a
operationPreemptionEnding :: forall a b. Operation a b -> Signal a
operationPreemptionEnding = forall a. SignalSource a -> Signal a
publishSignal forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. Operation a b -> SignalSource a
operationPreemptionEndingSource

-- | Signal whenever any property of the operation changes.
operationChanged_ :: Operation a b -> Signal ()
operationChanged_ :: forall a b. Operation a b -> Signal ()
operationChanged_ Operation a b
op =
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal a
operationUtilising Operation a b
op) forall a. Semigroup a => a -> a -> a
<>
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal (a, b)
operationUtilised Operation a b
op) forall a. Semigroup a => a -> a -> a
<>
  forall a b. (a -> b) -> Signal a -> Signal b
mapSignal (forall a b. a -> b -> a
const ()) (forall a b. Operation a b -> Signal a
operationPreemptionEnding Operation a b
op)

-- | Return the summary for the operation with desciption of its
-- properties using the specified indent.
operationSummary :: Operation a b -> Int -> Event ShowS
operationSummary :: forall a b. Operation a b -> Int -> Event ShowS
operationSummary Operation a b
op Int
indent =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do Double
t0  <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationStartTimeRef Operation a b
op)
     Double
t1  <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationLastTimeRef Operation a b
op)
     Double
tx1 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationTotalUtilisationTimeRef Operation a b
op)
     Double
tx2 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef Double
operationTotalPreemptionTimeRef Operation a b
op)
     let xf1 :: Double
xf1 = Double
tx1 forall a. Fractional a => a -> a -> a
/ (Double
t1 forall a. Num a => a -> a -> a
- Double
t0)
         xf2 :: Double
xf2 = Double
tx2 forall a. Fractional a => a -> a -> a
/ (Double
t1 forall a. Num a => a -> a -> a
- Double
t0)
     SamplingStats Double
xs1 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef (SamplingStats Double)
operationUtilisationTimeRef Operation a b
op)
     SamplingStats Double
xs2 <- forall a. IORef a -> IO a
readIORef (forall a b. Operation a b -> IORef (SamplingStats Double)
operationPreemptionTimeRef Operation a b
op)
     let tab :: [Char]
tab = forall a. Int -> a -> [a]
replicate Int
indent Char
' '
     forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
       [Char] -> ShowS
showString [Char]
tab forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"total utilisation time = " forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> ShowS
shows Double
tx1 forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
tab forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"total preemption time = " forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> ShowS
shows Double
tx2 forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
tab forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"utilisation factor (from 0 to 1) = " forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> ShowS
shows Double
xf1 forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
tab forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"preemption factor (from 0 to 1) = " forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> ShowS
shows Double
xf2 forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
tab forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"utilisation time:\n\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       forall a. Show a => SamplingStats a -> Int -> ShowS
samplingStatsSummary SamplingStats Double
xs1 (Int
2 forall a. Num a => a -> a -> a
+ Int
indent) forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"\n\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
tab forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       [Char] -> ShowS
showString [Char]
"preemption time:\n\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
.
       forall a. Show a => SamplingStats a -> Int -> ShowS
samplingStatsSummary SamplingStats Double
xs2 (Int
2 forall a. Num a => a -> a -> a
+ Int
indent)

-- | Reset the statistics.
resetOperation :: Operation a b -> Event ()
resetOperation :: forall a b. Operation a b -> Event ()
resetOperation Operation a b
op =
  forall a. (Point -> IO a) -> Event a
Event forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let t0 :: Double
t0 = Point -> Double
pointTime Point
p
     forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef Double
operationStartTimeRef Operation a b
op) Double
t0
     forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef Double
operationLastTimeRef Operation a b
op) Double
t0
     forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef Double
operationTotalUtilisationTimeRef Operation a b
op) Double
0
     forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef Double
operationTotalPreemptionTimeRef Operation a b
op) Double
0
     forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef (SamplingStats Double)
operationUtilisationTimeRef Operation a b
op) forall a. SamplingData a => SamplingStats a
emptySamplingStats
     forall a. IORef a -> a -> IO ()
writeIORef (forall a b. Operation a b -> IORef (SamplingStats Double)
operationPreemptionTimeRef Operation a b
op) forall a. SamplingData a => SamplingStats a
emptySamplingStats