diff --git a/src/test/java/net/berack/upo/valpre/sim/TestSimulation.java b/src/test/java/net/berack/upo/valpre/sim/TestSimulation.java index 7d453dc..ddf84df 100644 --- a/src/test/java/net/berack/upo/valpre/sim/TestSimulation.java +++ b/src/test/java/net/berack/upo/valpre/sim/TestSimulation.java @@ -13,29 +13,28 @@ import net.berack.upo.valpre.rand.Rng; public class TestSimulation { - private static double DELTA = 0.0000001; - private static Rng rigged = new RiggedRng(); - private static Distribution const0 = new Constant(0.0); - private static Distribution const1 = new Constant(1.0); + private static final double DELTA = 0.0000001; + private static final Distribution const0 = _ -> 0.0; + private static final Distribution const1 = _ -> 1.0; + private static final Rng rigged; + private static final Net simpleNet; + private static final ServerNode node0; + private static final ServerNode node1; + static { + node0 = ServerNode.createLimitedSource("First", const1, 0); + node1 = ServerNode.createQueue("Second", 1, const1); - private final static class RiggedRng extends Rng { - @Override - public double random() { - return 0.1; - } - } + simpleNet = new Net(); + simpleNet.addNode(node0); + simpleNet.addNode(node1); + simpleNet.addConnection(0, 1, 1.0); - private final static class Constant implements Distribution { - public final double value; - - public Constant(double value) { - this.value = value; - } - - @Override - public double sample(Rng rng) { - return this.value; - } + rigged = new Rng() { + @Override + public double random() { + return 0.1; + } + }; } @Test @@ -177,22 +176,313 @@ public class TestSimulation { } @Test - public void criteria() { - // TODO + public void criteriaTime() { + var criteria = new EndCriteria.MaxTime(3.0); - var criteria = new EndCriteria.MaxTime(5.0); - criteria.shouldEnd(null); + var sim = new Simulation(simpleNet, rigged); + assertTrue(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.addArrival(node0); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Arrival + assertEquals(0.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Source + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.processNextEvent(); // Arrival Queue + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Queue + assertEquals(2.0, sim.getTime(), DELTA); + assertTrue(sim.hasEnded()); // No more events + assertFalse(criteria.shouldEnd(sim)); + + sim.addArrival(node0); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Arrival + assertEquals(2.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Source + assertEquals(3.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertTrue(criteria.shouldEnd(sim)); + } + + @Test + public void criteriaArrivals() { + var criteria = new EndCriteria.MaxArrivals(node0.name, 2); + + var sim = new Simulation(simpleNet, rigged); + assertTrue(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.addArrival(node0); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.processNextEvent(); // Arrival + assertEquals(0.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Source + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.processNextEvent(); // Arrival Queue + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Queue + assertEquals(2.0, sim.getTime(), DELTA); + assertTrue(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.addArrival(node0); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Arrival + assertEquals(2.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertTrue(criteria.shouldEnd(sim)); + } + + @Test + public void criteriaDeparture() { + var criteria = new EndCriteria.MaxDepartures(node0.name, 2); + + var sim = new Simulation(simpleNet, rigged); + assertTrue(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.addArrival(node0); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.processNextEvent(); // Arrival + assertEquals(0.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Source + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.processNextEvent(); // Arrival Queue + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Queue + assertEquals(2.0, sim.getTime(), DELTA); + assertTrue(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + + sim.addArrival(node0); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Arrival + assertEquals(2.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertFalse(criteria.shouldEnd(sim)); + sim.processNextEvent(); // Departure Source + assertEquals(3.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertTrue(criteria.shouldEnd(sim)); } @Test public void simulation() { - // TODO - var sim = new Simulation(null, rigged); - sim.endSimulation(); + var start = System.nanoTime(); + var sim = new Simulation(simpleNet, rigged); + // knowing that it takes time to allocate the object + // we can use the average time + var endAllocation = System.nanoTime(); + var time = (endAllocation + start) / 2; + var diff = 0.5e-6 * (endAllocation - start); // getting the error margin in ms + + assertTrue(sim.hasEnded()); + assertEquals(0, sim.getEventsProcessed()); + assertEquals(0.0, sim.getTime(), DELTA); + assertEquals(node0, sim.getNode(node0.name)); + assertEquals(node1, sim.getNode(node1.name)); + assertEquals(0, sim.getNodeState(node0.name).numServerBusy); + assertEquals(0, sim.getNodeState(node0.name).numServerUnavailable); + assertEquals(0, sim.getNodeState(node1.name).numServerBusy); + assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable); + var fel = sim.getFutureEventList(); + assertEquals(0, fel.size()); + + sim.addArrival(node0); + assertFalse(sim.hasEnded()); + assertEquals(0, sim.getEventsProcessed()); + assertEquals(0.0, sim.getTime(), DELTA); + assertEquals(node0, sim.getNode(node0.name)); + assertEquals(node1, sim.getNode(node1.name)); + assertEquals(0, sim.getNodeState(node0.name).numServerBusy); + assertEquals(0, sim.getNodeState(node0.name).numServerUnavailable); + assertEquals(0, sim.getNodeState(node1.name).numServerBusy); + assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable); + fel = sim.getFutureEventList(); + assertEquals(1, fel.size()); + assertEquals(Event.Type.ARRIVAL, fel.get(0).type); + assertEquals(node0, fel.get(0).node); + assertEquals(0.0, fel.get(0).time, DELTA); + + sim.processNextEvent(); // Arrival + assertEquals(0.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertEquals(1, sim.getEventsProcessed()); + assertEquals(node0, sim.getNode(node0.name)); + assertEquals(node1, sim.getNode(node1.name)); + assertEquals(1, sim.getNodeState(node0.name).numServerBusy); + assertEquals(0, sim.getNodeState(node0.name).numServerUnavailable); + assertEquals(0, sim.getNodeState(node1.name).numServerBusy); + assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable); + fel = sim.getFutureEventList(); + assertEquals(1, fel.size()); + assertEquals(Event.Type.DEPARTURE, fel.get(0).type); + assertEquals(node0, fel.get(0).node); + assertEquals(1.0, fel.get(0).time, DELTA); + + sim.processNextEvent(); // Departure Source + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertEquals(2, sim.getEventsProcessed()); + assertEquals(node0, sim.getNode(node0.name)); + assertEquals(node1, sim.getNode(node1.name)); + assertEquals(0, sim.getNodeState(node0.name).numServerBusy); + assertEquals(0, sim.getNodeState(node0.name).numServerUnavailable); + assertEquals(0, sim.getNodeState(node1.name).numServerBusy); + assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable); + fel = sim.getFutureEventList(); + assertEquals(1, fel.size()); + assertEquals(Event.Type.ARRIVAL, fel.get(0).type); + assertEquals(node1, fel.get(0).node); + assertEquals(1.0, fel.get(0).time, DELTA); + + sim.processNextEvent(); // Arrival Queue + assertEquals(1.0, sim.getTime(), DELTA); + assertFalse(sim.hasEnded()); + assertEquals(3, sim.getEventsProcessed()); + assertEquals(node0, sim.getNode(node0.name)); + assertEquals(node1, sim.getNode(node1.name)); + assertEquals(0, sim.getNodeState(node0.name).numServerBusy); + assertEquals(0, sim.getNodeState(node0.name).numServerUnavailable); + assertEquals(1, sim.getNodeState(node1.name).numServerBusy); + assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable); + fel = sim.getFutureEventList(); + assertEquals(1, fel.size()); + assertEquals(Event.Type.DEPARTURE, fel.get(0).type); + assertEquals(node1, fel.get(0).node); + assertEquals(2.0, fel.get(0).time, DELTA); + + sim.processNextEvent(); // Departure Queue + assertEquals(2.0, sim.getTime(), DELTA); + assertTrue(sim.hasEnded()); + assertEquals(4, sim.getEventsProcessed()); + assertEquals(node0, sim.getNode(node0.name)); + assertEquals(node1, sim.getNode(node1.name)); + assertEquals(0, sim.getNodeState(node0.name).numServerBusy); + assertEquals(0, sim.getNodeState(node0.name).numServerUnavailable); + assertEquals(0, sim.getNodeState(node1.name).numServerBusy); + assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable); + fel = sim.getFutureEventList(); + assertEquals(0, fel.size()); + + var elapsed = (double) (System.nanoTime() - time); + var result = sim.endSimulation(); + assertEquals(2.0, result.simulationTime, DELTA); + assertEquals(sim.seed, result.seed); + assertEquals(elapsed * 1e-6, result.timeElapsedMS * 1e-6, diff); + assertEquals(2, result.nodes.size()); + assertEquals(1, result.nodes.get(node0.name).numArrivals, DELTA); + assertEquals(1, result.nodes.get(node0.name).numDepartures, DELTA); + assertEquals(1, result.nodes.get(node1.name).numArrivals, DELTA); + assertEquals(1, result.nodes.get(node1.name).numDepartures, DELTA); } @Test - public void multipleSim() { - // TODO + public void endSim() { + var criteria = new EndCriteria.MaxDepartures(node0.name, 5); + var sim = new Simulation(simpleNet, rigged, criteria); + sim.addArrival(node0); + sim.addArrival(node0); + sim.addArrival(node0); + sim.addArrival(node0); + sim.addArrival(node0); + sim.addArrival(node0); + + while (!criteria.shouldEnd(sim)) { + sim.processNextEvent(); + } + + assertTrue(sim.hasEnded()); + var res = sim.endSimulation(); + + assertEquals(6, res.nodes.get(node0.name).numArrivals, DELTA); + assertEquals(5, res.nodes.get(node0.name).numDepartures, DELTA); + assertEquals(4, res.nodes.get(node1.name).numArrivals, DELTA); + assertEquals(0, res.nodes.get(node1.name).numDepartures, DELTA); + } + + @Test + public void simulationStats() { + var net = new Net(); + net.addNode(ServerNode.createLimitedSource("Source", const1, 50)); + + var sim = new Simulation(net, rigged); + var result = sim.run(); + var nodeStat = result.nodes.get("Source"); + assertEquals(50, nodeStat.numArrivals, DELTA); + assertEquals(50, nodeStat.numDepartures, DELTA); + assertEquals(1.0, nodeStat.avgQueueLength, DELTA); + assertEquals(1.0, nodeStat.avgResponse, DELTA); + assertEquals(0.0, nodeStat.avgWaitTime, DELTA); + assertEquals(1.0, nodeStat.maxQueueLength, DELTA); + assertEquals(50.0, nodeStat.busyTime, DELTA); + assertEquals(result.simulationTime, nodeStat.lastEventTime, DELTA); + assertEquals(1.0, nodeStat.troughput, DELTA); + assertEquals(1.0, nodeStat.utilization, DELTA); + assertEquals(0.0, nodeStat.unavailable, DELTA); + + net.addNode(ServerNode.createQueue("Queue", 1, const1)); + net.addConnection(0, 1, 1.0); + + sim = new Simulation(net, rigged); + result = sim.run(); + nodeStat = result.nodes.get("Source"); + assertEquals(50, nodeStat.numArrivals, DELTA); + assertEquals(50, nodeStat.numDepartures, DELTA); + assertEquals(1.0, nodeStat.avgQueueLength, DELTA); + assertEquals(1.0, nodeStat.avgResponse, DELTA); + assertEquals(0.0, nodeStat.avgWaitTime, DELTA); + assertEquals(1.0, nodeStat.maxQueueLength, DELTA); + assertEquals(50.0, nodeStat.busyTime, DELTA); + assertEquals(result.simulationTime - 1, nodeStat.lastEventTime, DELTA); + assertEquals(1.0, nodeStat.troughput, DELTA); + assertEquals(1.0, nodeStat.utilization, DELTA); + assertEquals(0.0, nodeStat.unavailable, DELTA); + nodeStat = result.nodes.get("Queue"); + assertEquals(50, nodeStat.numArrivals, DELTA); + assertEquals(50, nodeStat.numDepartures, DELTA); + assertEquals(1.0, nodeStat.avgQueueLength, DELTA); + assertEquals(1.0, nodeStat.avgResponse, DELTA); + assertEquals(0.0, nodeStat.avgWaitTime, DELTA); + assertEquals(1.0, nodeStat.maxQueueLength, DELTA); + assertEquals(50.0, nodeStat.busyTime, DELTA); + assertEquals(result.simulationTime, nodeStat.lastEventTime, DELTA); + + assertEquals(nodeStat.busyTime / nodeStat.lastEventTime, nodeStat.utilization, DELTA); + assertEquals(nodeStat.numDepartures / nodeStat.lastEventTime, nodeStat.troughput, DELTA); + assertEquals(0.0, nodeStat.unavailable, DELTA); } }