module Simulation.Aivika.Trans.GPSS.Storage
(
Storage,
newStorage,
storageCapacity,
storageEmpty,
storageFull,
storageContent,
storageContentStats,
storageUseCount,
storageUsedContent,
storageUtilisationCount,
storageUtilisationCountStats,
storageQueueCount,
storageQueueCountStats,
storageTotalWaitTime,
storageWaitTime,
storageAverageHoldingTime,
enterStorage,
leaveStorage,
leaveStorageWithinEvent,
resetStorage,
storageContentChanged,
storageContentChanged_,
storageUseCountChanged,
storageUseCountChanged_,
storageUsedContentChanged,
storageUsedContentChanged_,
storageUtilisationCountChanged,
storageUtilisationCountChanged_,
storageQueueCountChanged,
storageQueueCountChanged_,
storageWaitTimeChanged,
storageWaitTimeChanged_,
storageChanged_) where
import Data.Monoid
import Data.Maybe
import Control.Monad
import Control.Monad.Trans
import Control.Exception
import Simulation.Aivika.Trans
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.Internal.Event
import Simulation.Aivika.Trans.Internal.Cont
import Simulation.Aivika.Trans.Internal.Process
import Simulation.Aivika.Trans.QueueStrategy
import Simulation.Aivika.Trans.Statistics
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.GPSS.Transact
import Simulation.Aivika.Trans.GPSS.TransactQueueStrategy
data Storage m =
Storage { storageCapacity :: Int,
storageContentRef :: Ref m Int,
storageContentStatsRef :: Ref m (TimingStats Int),
storageContentSource :: SignalSource m Int,
storageUseCountRef :: Ref m Int,
storageUseCountSource :: SignalSource m Int,
storageUsedContentRef :: Ref m Int,
storageUsedContentSource :: SignalSource m Int,
storageUtilisationCountRef :: Ref m Int,
storageUtilisationCountStatsRef :: Ref m (TimingStats Int),
storageUtilisationCountSource :: SignalSource m Int,
storageQueueCountRef :: Ref m Int,
storageQueueCountStatsRef :: Ref m (TimingStats Int),
storageQueueCountSource :: SignalSource m Int,
storageTotalWaitTimeRef :: Ref m Double,
storageWaitTimeRef :: Ref m (SamplingStats Double),
storageWaitTimeSource :: SignalSource m (),
storageDelayChain :: StrategyQueue m (TransactQueueStrategy FCFS) (StorageDelayedItem m) }
data StorageDelayedItem m =
StorageDelayedItem { delayedItemTime :: Double,
delayedItemDecrement :: Int,
delayedItemCont :: FrozenCont m () }
instance MonadDES m => Eq (Storage m) where
x == y = storageContentRef x == storageContentRef y
newStorage :: MonadDES m => Int -> Event m (Storage m)
newStorage capacity =
Event $ \p ->
do let r = pointRun p
t = pointTime p
contentRef <- invokeSimulation r $ newRef capacity
contentStatsRef <- invokeSimulation r $ newRef $ returnTimingStats t capacity
contentSource <- invokeSimulation r newSignalSource
useCountRef <- invokeSimulation r $ newRef 0
useCountSource <- invokeSimulation r newSignalSource
usedContentRef <- invokeSimulation r $ newRef 0
usedContentSource <- invokeSimulation r newSignalSource
utilCountRef <- invokeSimulation r $ newRef 0
utilCountStatsRef <- invokeSimulation r $ newRef $ returnTimingStats t 0
utilCountSource <- invokeSimulation r newSignalSource
queueCountRef <- invokeSimulation r $ newRef 0
queueCountStatsRef <- invokeSimulation r $ newRef $ returnTimingStats t 0
queueCountSource <- invokeSimulation r newSignalSource
totalWaitTimeRef <- invokeSimulation r $ newRef 0
waitTimeRef <- invokeSimulation r $ newRef emptySamplingStats
waitTimeSource <- invokeSimulation r newSignalSource
delayChain <- invokeSimulation r $ newStrategyQueue (TransactQueueStrategy FCFS)
return Storage { storageCapacity = capacity,
storageContentRef = contentRef,
storageContentStatsRef = contentStatsRef,
storageContentSource = contentSource,
storageUseCountRef = useCountRef,
storageUseCountSource = useCountSource,
storageUsedContentRef = usedContentRef,
storageUsedContentSource = usedContentSource,
storageUtilisationCountRef = utilCountRef,
storageUtilisationCountStatsRef = utilCountStatsRef,
storageUtilisationCountSource = utilCountSource,
storageQueueCountRef = queueCountRef,
storageQueueCountStatsRef = queueCountStatsRef,
storageQueueCountSource = queueCountSource,
storageTotalWaitTimeRef = totalWaitTimeRef,
storageWaitTimeRef = waitTimeRef,
storageWaitTimeSource = waitTimeSource,
storageDelayChain = delayChain }
storageEmpty :: MonadDES m => Storage m -> Event m Bool
storageEmpty r =
Event $ \p ->
do n <- invokeEvent p $ readRef (storageContentRef r)
return (n == storageCapacity r)
storageFull :: MonadDES m => Storage m -> Event m Bool
storageFull r =
Event $ \p ->
do n <- invokeEvent p $ readRef (storageContentRef r)
return (n == 0)
storageContent :: MonadDES m => Storage m -> Event m Int
storageContent r =
Event $ \p -> invokeEvent p $ readRef (storageContentRef r)
storageContentStats :: MonadDES m => Storage m -> Event m (TimingStats Int)
storageContentStats r =
Event $ \p -> invokeEvent p $ readRef (storageContentStatsRef r)
storageContentChanged :: MonadDES m => Storage m -> Signal m Int
storageContentChanged r =
publishSignal $ storageContentSource r
storageContentChanged_ :: MonadDES m => Storage m -> Signal m ()
storageContentChanged_ r =
mapSignal (const ()) $ storageContentChanged r
storageUseCount :: MonadDES m => Storage m -> Event m Int
storageUseCount r =
Event $ \p -> invokeEvent p $ readRef (storageUseCountRef r)
storageUseCountChanged :: MonadDES m => Storage m -> Signal m Int
storageUseCountChanged r =
publishSignal $ storageUseCountSource r
storageUseCountChanged_ :: MonadDES m => Storage m -> Signal m ()
storageUseCountChanged_ r =
mapSignal (const ()) $ storageUseCountChanged r
storageUsedContent :: MonadDES m => Storage m -> Event m Int
storageUsedContent r =
Event $ \p -> invokeEvent p $ readRef (storageUsedContentRef r)
storageUsedContentChanged :: MonadDES m => Storage m -> Signal m Int
storageUsedContentChanged r =
publishSignal $ storageUsedContentSource r
storageUsedContentChanged_ :: MonadDES m => Storage m -> Signal m ()
storageUsedContentChanged_ r =
mapSignal (const ()) $ storageUsedContentChanged r
storageUtilisationCount :: MonadDES m => Storage m -> Event m Int
storageUtilisationCount r =
Event $ \p -> invokeEvent p $ readRef (storageUtilisationCountRef r)
storageUtilisationCountStats :: MonadDES m => Storage m -> Event m (TimingStats Int)
storageUtilisationCountStats r =
Event $ \p -> invokeEvent p $ readRef (storageUtilisationCountStatsRef r)
storageUtilisationCountChanged :: MonadDES m => Storage m -> Signal m Int
storageUtilisationCountChanged r =
publishSignal $ storageUtilisationCountSource r
storageUtilisationCountChanged_ :: MonadDES m => Storage m -> Signal m ()
storageUtilisationCountChanged_ r =
mapSignal (const ()) $ storageUtilisationCountChanged r
storageQueueCount :: MonadDES m => Storage m -> Event m Int
storageQueueCount r =
Event $ \p -> invokeEvent p $ readRef (storageQueueCountRef r)
storageQueueCountStats :: MonadDES m => Storage m -> Event m (TimingStats Int)
storageQueueCountStats r =
Event $ \p -> invokeEvent p $ readRef (storageQueueCountStatsRef r)
storageQueueCountChanged :: MonadDES m => Storage m -> Signal m Int
storageQueueCountChanged r =
publishSignal $ storageQueueCountSource r
storageQueueCountChanged_ :: MonadDES m => Storage m -> Signal m ()
storageQueueCountChanged_ r =
mapSignal (const ()) $ storageQueueCountChanged r
storageTotalWaitTime :: MonadDES m => Storage m -> Event m Double
storageTotalWaitTime r =
Event $ \p -> invokeEvent p $ readRef (storageTotalWaitTimeRef r)
storageWaitTime :: MonadDES m => Storage m -> Event m (SamplingStats Double)
storageWaitTime r =
Event $ \p -> invokeEvent p $ readRef (storageWaitTimeRef r)
storageWaitTimeChanged :: MonadDES m => Storage m -> Signal m (SamplingStats Double)
storageWaitTimeChanged r =
mapSignalM (\() -> storageWaitTime r) $ storageWaitTimeChanged_ r
storageWaitTimeChanged_ :: MonadDES m => Storage m -> Signal m ()
storageWaitTimeChanged_ r =
publishSignal $ storageWaitTimeSource r
storageAverageHoldingTime :: MonadDES m => Storage m -> Event m Double
storageAverageHoldingTime r =
Event $ \p ->
do s <- invokeEvent p $ readRef (storageUtilisationCountStatsRef r)
n <- invokeEvent p $ readRef (storageUtilisationCountRef r)
m <- invokeEvent p $ readRef (storageUsedContentRef r)
let t = pointTime p
s' = addTimingStats t n s
k = timingStatsSum s' / (fromRational $ toRational m)
return k
enterStorage :: MonadDES m
=> Storage m
-> Transact m a
-> Int
-> Process m ()
enterStorage r transact decrement =
Process $ \pid ->
Cont $ \c ->
Event $ \p ->
do let t = pointTime p
f <- invokeEvent p $ strategyQueueNull (storageDelayChain r)
if f
then invokeEvent p $
invokeCont c $
invokeProcess pid $
enterStorage' r transact decrement
else do c <- invokeEvent p $
freezeContReentering c () $
invokeCont c $
invokeProcess pid $
enterStorage r transact decrement
invokeEvent p $
strategyEnqueueWithPriority
(storageDelayChain r)
(transactPriority transact)
(StorageDelayedItem t decrement c)
invokeEvent p $ updateStorageQueueCount r 1
enterStorage' :: MonadDES m
=> Storage m
-> Transact m a
-> Int
-> Process m ()
enterStorage' r transact decrement =
Process $ \pid ->
Cont $ \c ->
Event $ \p ->
do let t = pointTime p
a <- invokeEvent p $ readRef (storageContentRef r)
if a < decrement
then do c <- invokeEvent p $
freezeContReentering c () $
invokeCont c $
invokeProcess pid $
enterStorage r transact decrement
invokeEvent p $
strategyEnqueueWithPriority
(storageDelayChain r)
(transactPriority transact)
(StorageDelayedItem t decrement c)
invokeEvent p $ updateStorageQueueCount r 1
else do invokeEvent p $ updateStorageWaitTime r 0
invokeEvent p $ updateStorageContent r ( decrement)
invokeEvent p $ updateStorageUseCount r 1
invokeEvent p $ updateStorageUsedContent r decrement
invokeEvent p $ updateStorageUtilisationCount r decrement
invokeEvent p $ resumeCont c ()
leaveStorage :: MonadDES m
=> Storage m
-> Int
-> Process m ()
leaveStorage r increment =
Process $ \_ ->
Cont $ \c ->
Event $ \p ->
do invokeEvent p $ leaveStorageWithinEvent r increment
invokeEvent p $ resumeCont c ()
leaveStorageWithinEvent :: MonadDES m
=> Storage m
-> Int
-> Event m ()
leaveStorageWithinEvent r increment =
Event $ \p ->
do let t = pointTime p
invokeEvent p $ updateStorageUtilisationCount r ( increment)
invokeEvent p $ updateStorageContent r increment
invokeEvent p $ enqueueEvent t $ tryEnterStorage r
tryEnterStorage :: MonadDES m => Storage m -> Event m ()
tryEnterStorage r =
Event $ \p ->
do let t = pointTime p
a <- invokeEvent p $ readRef (storageContentRef r)
if a > 0
then invokeEvent p $ letEnterStorage r
else return ()
letEnterStorage :: MonadDES m => Storage m -> Event m ()
letEnterStorage r =
Event $ \p ->
do let t = pointTime p
a <- invokeEvent p $ readRef (storageContentRef r)
when (a > storageCapacity r) $
throwComp $
SimulationRetry $
"The storage content cannot exceed the limited capacity: leaveStorage'"
x <- invokeEvent p $
strategyQueueDeleteBy
(storageDelayChain r)
(\i -> delayedItemDecrement i <= a)
case x of
Nothing -> return ()
Just (StorageDelayedItem t0 decrement0 c0) ->
do invokeEvent p $ updateStorageQueueCount r (1)
c <- invokeEvent p $ unfreezeCont c0
case c of
Nothing ->
invokeEvent p $ letEnterStorage r
Just c ->
do invokeEvent p $ updateStorageContent r ( decrement0)
invokeEvent p $ updateStorageWaitTime r (t t0)
invokeEvent p $ updateStorageUtilisationCount r decrement0
invokeEvent p $ updateStorageUseCount r 1
invokeEvent p $ updateStorageUsedContent r decrement0
invokeEvent p $ enqueueEvent t $ reenterCont c ()
storageChanged_ :: MonadDES m => Storage m -> Signal m ()
storageChanged_ r =
storageContentChanged_ r <>
storageUsedContentChanged_ r <>
storageUtilisationCountChanged_ r <>
storageQueueCountChanged_ r
updateStorageContent :: MonadDES m => Storage m -> Int -> Event m ()
updateStorageContent r delta =
Event $ \p ->
do a <- invokeEvent p $ readRef (storageContentRef r)
let a' = a + delta
invokeEvent p $
writeRef (storageContentRef r) a'
invokeEvent p $
modifyRef (storageContentStatsRef r) $
addTimingStats (pointTime p) a'
invokeEvent p $
triggerSignal (storageContentSource r) a'
updateStorageUseCount :: MonadDES m => Storage m -> Int -> Event m ()
updateStorageUseCount r delta =
Event $ \p ->
do a <- invokeEvent p $ readRef (storageUseCountRef r)
let a' = a + delta
invokeEvent p $
writeRef (storageUseCountRef r) a'
invokeEvent p $
triggerSignal (storageUseCountSource r) a'
updateStorageUsedContent :: MonadDES m => Storage m -> Int -> Event m ()
updateStorageUsedContent r delta =
Event $ \p ->
do a <- invokeEvent p $ readRef (storageUsedContentRef r)
let a' = a + delta
invokeEvent p $
writeRef (storageUsedContentRef r) a'
invokeEvent p $
triggerSignal (storageUsedContentSource r) a'
updateStorageQueueCount :: MonadDES m => Storage m -> Int -> Event m ()
updateStorageQueueCount r delta =
Event $ \p ->
do a <- invokeEvent p $ readRef (storageQueueCountRef r)
let a' = a + delta
invokeEvent p $
writeRef (storageQueueCountRef r) a'
invokeEvent p $
modifyRef (storageQueueCountStatsRef r) $
addTimingStats (pointTime p) a'
invokeEvent p $
triggerSignal (storageQueueCountSource r) a'
updateStorageUtilisationCount :: MonadDES m => Storage m -> Int -> Event m ()
updateStorageUtilisationCount r delta =
Event $ \p ->
do a <- invokeEvent p $ readRef (storageUtilisationCountRef r)
let a' = a + delta
invokeEvent p $
writeRef (storageUtilisationCountRef r) a'
invokeEvent p $
modifyRef (storageUtilisationCountStatsRef r) $
addTimingStats (pointTime p) a'
invokeEvent p $
triggerSignal (storageUtilisationCountSource r) a'
updateStorageWaitTime :: MonadDES m => Storage m -> Double -> Event m ()
updateStorageWaitTime r delta =
Event $ \p ->
do a <- invokeEvent p $ readRef (storageTotalWaitTimeRef r)
let a' = a + delta
invokeEvent p $
writeRef (storageTotalWaitTimeRef r) a'
invokeEvent p $
modifyRef (storageWaitTimeRef r) $
addSamplingStats delta
invokeEvent p $
triggerSignal (storageWaitTimeSource r) ()
resetStorage :: MonadDES m => Storage m -> Event m ()
resetStorage r =
Event $ \p ->
do let t = pointTime p
content <- invokeEvent p $ readRef (storageContentRef r)
invokeEvent p $ writeRef (storageContentStatsRef r) $
returnTimingStats t content
invokeEvent p $ writeRef (storageUseCountRef r) 0
let usedContent = storageCapacity r content
invokeEvent p $ writeRef (storageUsedContentRef r) usedContent
utilCount <- invokeEvent p $ readRef (storageUtilisationCountRef r)
invokeEvent p $ writeRef (storageUtilisationCountStatsRef r) $
returnTimingStats t utilCount
queueCount <- invokeEvent p $ readRef (storageQueueCountRef r)
invokeEvent p $ writeRef (storageQueueCountStatsRef r) $
returnTimingStats t queueCount
invokeEvent p $ writeRef (storageTotalWaitTimeRef r) 0
invokeEvent p $ writeRef (storageWaitTimeRef r) emptySamplingStats
invokeEvent p $
triggerSignal (storageUseCountSource r) 0
invokeEvent p $
triggerSignal (storageUsedContentSource r) usedContent
invokeEvent p $
triggerSignal (storageUtilisationCountSource r) utilCount
invokeEvent p $
triggerSignal (storageWaitTimeSource r) ()