-- It corresponds to model TimeOutInt described in document -- Advanced Features of the SimPy Language -- [http://heather.cs.ucdavis.edu/~matloff/156/PLN/AdvancedSimPy.pdf]. -- SimPy is available on [http://simpy.sourceforge.net/]. -- -- The model description is as follows. -- -- Same as TimeOut.hs but using interrupts. A network node sends a message -- but also sets a timeout period; if the node times out, it assumes the -- message it had sent was lost, and it will send again. The time to get -- an acknowledgement for a message is exponentially distributed with -- mean 1.0, and the timeout period is 0.5. Immediately after receiving -- an acknowledgement, the node sends out a new message. -- -- We find the proportion of messages which timeout. The output should -- be about 0.61. import Control.Monad import Control.Monad.Trans import Simulation.Aivika ackRate = 1.0 / 1.0 -- reciprocal of the acknowledge mean time toPeriod = 0.5 -- timeout period specs = Specs { spcStartTime = 0.0, spcStopTime = 10000.0, spcDT = 1.0, spcMethod = RungeKutta4, spcGeneratorType = SimpleGenerator } model :: Simulation Double model = do -- number of messages sent nMsgs <- newRef 0 -- number of timeouts which have occured nTimeOuts <- newRef 0 nodePid <- newProcessId let node :: Process () node = do liftEvent $ modifyRef nMsgs $ (+) 1 -- create the process ID timeoutPid <- liftSimulation newProcessId -- set up the timeout liftEvent $ runProcessUsingId timeoutPid timeout -- wait for ACK, but could be timeout ackTime <- liftParameter $ randomExponential (1 / ackRate) holdProcess ackTime liftEvent $ do interrupted <- processInterrupted nodePid if interrupted then modifyRef nTimeOuts $ (+) 1 else cancelProcessWithId timeoutPid node timeout :: Process () timeout = do holdProcess toPeriod liftEvent $ interruptProcess nodePid runProcessInStartTimeUsingId nodePid node runEventInStopTime $ do x <- readRef nTimeOuts y <- readRef nMsgs return $ x / y main = do putStr "The percentage of timeout was " runSimulation model specs >>= print