Refactor simulation and net example tests to use builder pattern for ServerNode and improve arrival handling logic

This commit is contained in:
2025-02-07 17:33:27 +01:00
parent 5aedd25c5f
commit fbc9aeac2c
8 changed files with 329 additions and 99 deletions

View File

@@ -1,5 +1,7 @@
package net.berack.upo.valpre.sim;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import org.junit.Test;
@@ -7,6 +9,8 @@ import org.junit.Test;
import com.esotericsoftware.kryo.KryoException;
import net.berack.upo.valpre.rand.Distribution;
import net.berack.upo.valpre.rand.Rng;
import net.berack.upo.valpre.sim.stats.NodeStats;
public class TestSaveExamplesNet {
@@ -22,40 +26,103 @@ public class TestSaveExamplesNet {
private static final Distribution unNorm = new Distribution.UnavailableTime(0.2, norm4_2);
private static final Distribution unExp = new Distribution.UnavailableTime(0.1, exp10);
private static final int spawn = 10000;
private static final String path = "src/main/resources/example%d.%s";
private static final String net1 = path.formatted(1, "net");
private static final String net2 = path.formatted(2, "net");
private static final String net3 = path.formatted(3, "net");
@Test
public void testSaveExample1() throws KryoException, IOException {
var net = new Net();
net.addNode(ServerNode.createLimitedSource("Source", exp0_22, 10000));
net.addNode(ServerNode.createQueue("Queue", 1, norm3_2));
net.addNode(ServerNode.Builder.sourceLimited("Source", spawn, exp0_22));
net.addNode(ServerNode.Builder.queue("Queue", 1, norm3_2));
net.addConnection(0, 1, 1.0);
net.save("src/main/resources/example1.net");
net = Net.load("src/main/resources/example1.net");
net.save(net1);
net = Net.load(net1);
var sim = new Simulation(net, new Rng());
var res = sim.run();
var time = 44782.0;
var maxErr = time / 1000.0;
assertEquals(Rng.DEFAULT, res.seed);
assertEquals(time, res.simulationTime, maxErr);
testNode(res.nodes.get("Source"), 10000, time, 1.0, 4.5, 0.0, 0.0);
testNode(res.nodes.get("Queue"), 10000, time, 2.6, 7.2, 4.0, 0.0);
}
@Test
public void testSaveExample2() throws KryoException, IOException {
var net = new Net();
net.addNode(ServerNode.createLimitedSource("Source", exp0_22, 10000));
net.addNode(ServerNode.createQueue("Queue", 1, norm3_2));
net.addNode(ServerNode.createQueue("Queue Wait", 1, norm3_2, unNorm));
net.addNode(ServerNode.Builder.sourceLimited("Source", spawn, exp0_22));
net.addNode(ServerNode.Builder.queue("Queue", 1, norm3_2));
net.addNode(ServerNode.Builder.queue("Queue Wait", 1, norm3_2, unNorm));
net.addConnection(0, 1, 1.0);
net.addConnection(1, 2, 1.0);
net.save("src/main/resources/example2.net");
net = Net.load("src/main/resources/example2.net");
net.save(net2);
net = Net.load(net2);
var sim = new Simulation(net, new Rng());
var res = sim.run();
var time = 45417.0;
var maxErr = time / 1000.0;
assertEquals(Rng.DEFAULT, res.seed);
assertEquals(time, res.simulationTime, maxErr);
testNode(res.nodes.get("Source"), 10000, time, 1.0, 4.5, 0.0, 0.0);
testNode(res.nodes.get("Queue"), 10000, time, 2.6, 7.2, 4.0, 0.0);
testNode(res.nodes.get("Queue Wait"), 10000, time, 5.8, 22.3, 19.1, 8497.7);
}
@Test
public void testSaveExample3() throws KryoException, IOException {
var net = new Net();
net.addNode(ServerNode.createLimitedSource("Source", exp1_5, 10000));
net.addNode(ServerNode.createQueue("Service1", 1, exp2));
net.addNode(ServerNode.createQueue("Service2", 1, exp3_5, unExp));
net.addNode(ServerNode.Builder.sourceLimited("Source", spawn, exp1_5));
net.addNode(ServerNode.Builder.queue("Service1", 1, exp2));
net.addNode(ServerNode.Builder.queue("Service2", 1, exp3_5, unExp));
net.addConnection(0, 1, 1.0);
net.addConnection(1, 2, 1.0);
net.save("src/main/resources/example3.net");
net = Net.load("src/main/resources/example3.net");
net.save(net3);
net = Net.load(net3);
var sim = new Simulation(net, new Rng());
var res = sim.run();
var time = 6736.0;
var maxErr = time / 1000.0;
assertEquals(Rng.DEFAULT, res.seed);
assertEquals(time, res.simulationTime, maxErr);
testNode(res.nodes.get("Source"), 10000, time, 1.0, 0.6, 0.0, 0.0);
testNode(res.nodes.get("Service1"), 10000, time, 3.5, 1.7, 1.2, 0.0);
testNode(res.nodes.get("Service2"), 10000, time, 1.7, 0.5, 0.22, 102.2);
}
private void testNode(NodeStats stat, double numClients, double time, double avgQueue,
double avgResponse, double avgWait, double totalUnavailable) {
assertEquals("Num Arrivals", numClients, stat.numArrivals, 0.1);
assertEquals("Num Departures", numClients, stat.numDepartures, 0.1);
var maxErr = time / 1000.0;
assertEquals(time, stat.lastEventTime, maxErr);
assertEquals("Avg Queue", avgQueue, stat.avgQueueLength, 0.1);
assertEquals("Avg Wait", avgWait, stat.avgWaitTime, 0.1);
assertEquals("Avg Response", avgResponse, stat.avgResponse, 0.1);
var totalWait = numClients * stat.avgWaitTime;
var totalResponse = numClients * stat.avgResponse;
var totalBusy = totalResponse - totalWait;
assertEquals("Tot Wait", totalWait, stat.waitTime, maxErr);
assertEquals("Tot Response", totalResponse, stat.responseTime, maxErr);
assertEquals("Tot Busy", totalBusy, stat.busyTime, maxErr);
assertEquals("Tot Unavailable", totalUnavailable, stat.unavailableTime, maxErr);
assertEquals("Throughput", stat.numDepartures / stat.lastEventTime, stat.throughput, 0.001);
assertEquals("% Busy", stat.busyTime / stat.lastEventTime, stat.utilization, 0.001);
assertEquals("% Unavailable", stat.unavailableTime / stat.lastEventTime, stat.unavailable, 0.001);
}
}

View File

@@ -23,8 +23,8 @@ public class TestSimulation {
private static final ServerNode node0;
private static final ServerNode node1;
static {
node0 = ServerNode.createLimitedSource("First", const1, 0);
node1 = ServerNode.createQueue("Second", 1, const1);
node0 = ServerNode.Builder.sourceLimited("First", 0, const1);
node1 = ServerNode.Builder.queue("Second", 1, const1);
simpleNet = new Net();
simpleNet.addNode(node0);
@@ -41,27 +41,27 @@ public class TestSimulation {
@Test
public void serverNode() {
var node = ServerNode.createQueue("Nodo", 0, const1);
var node = ServerNode.Builder.queue("Nodo", 0, const1);
assertEquals("Nodo", node.name);
assertEquals(1, node.maxServers);
assertEquals(0, node.spawnArrivals);
assertEquals(1.0, node.getServiceTime(null), DELTA);
node = ServerNode.createQueue("Queue", 50, const1);
node = ServerNode.Builder.queue("Queue", 50, const1);
assertEquals("Queue", node.name);
assertEquals(50, node.maxServers);
assertEquals(0, node.spawnArrivals);
assertEquals(1.0, node.getServiceTime(null), DELTA);
node = ServerNode.createSource("Source", const1);
node = ServerNode.Builder.source("Source", const1);
assertEquals("Source", node.name);
assertEquals(Integer.MAX_VALUE, node.maxServers);
assertEquals(1, node.maxServers);
assertEquals(Integer.MAX_VALUE, node.spawnArrivals);
assertEquals(1.0, node.getServiceTime(null), DELTA);
node = ServerNode.createLimitedSource("Source", const1, 50);
node = ServerNode.Builder.sourceLimited("Source", 50, const1);
assertEquals("Source", node.name);
assertEquals(Integer.MAX_VALUE, node.maxServers);
assertEquals(1, node.maxServers);
assertEquals(50, node.spawnArrivals);
assertEquals(1.0, node.getServiceTime(null), DELTA);
}
@@ -93,7 +93,7 @@ public class TestSimulation {
var net = new Net();
assertEquals(0, net.size());
var node = ServerNode.createSource("First", const0);
var node = ServerNode.Builder.source("First", const0);
var index = net.addNode(node);
assertEquals(1, net.size());
assertEquals(0, index);
@@ -101,7 +101,7 @@ public class TestSimulation {
assertEquals(node, net.getNode("First"));
assertEquals(index, net.getNodeIndex("First"));
var node1 = ServerNode.createQueue("Second", 1, const0);
var node1 = ServerNode.Builder.queue("Second", 1, const0);
var index1 = net.addNode(node1);
assertEquals(2, net.size());
assertEquals(0, index);
@@ -126,7 +126,7 @@ public class TestSimulation {
conn = net.getChildren(1);
assertEquals(0, conn.size());
var node2 = ServerNode.createQueue("Third", 1, const0);
var node2 = ServerNode.Builder.queue("Third", 1, const0);
net.addNode(node2);
net.addConnection(0, 2, 1.0);
conn = net.getChildren(0);
@@ -172,7 +172,104 @@ public class TestSimulation {
assertFalse(state.hasRequests());
assertFalse(state.shouldSpawnArrival());
// TODO better test
state.numServerBusy = 1;
assertEquals(1, state.numServerBusy);
assertFalse(state.canServe());
assertFalse(state.hasRequests());
state.numServerBusy = 0;
state.numServerUnavailable = 1;
assertEquals(1, state.numServerUnavailable);
assertFalse(state.canServe());
assertFalse(state.hasRequests());
state.queue.add(1.0);
assertEquals(1, state.queue.size());
assertTrue(state.hasRequests());
assertFalse(state.isQueueFull());
state.numServerUnavailable = 0;
state.numServerBusy = 0;
assertTrue(state.canServe());
assertTrue(state.hasRequests());
state.numServerBusy = 1;
state.queue.poll();
assertEquals(0, state.queue.size());
assertFalse(state.hasRequests());
}
@Test
public void nodeStatsUpdates() {
var net = new Net();
net.addNode(ServerNode.Builder.sourceLimited("Source", 50, const1));
net.addNode(node1);
net.addConnection(0, 1, 1.0);
var state = new ServerNodeState(0, net);
var event = state.spawnArrivalIfPossilbe(0);
assertNotNull(event);
assertEquals(0, state.stats.numArrivals, DELTA);
assertEquals(0, state.stats.numDepartures, DELTA);
assertEquals(0, state.numServerBusy);
assertEquals(0, state.numServerUnavailable);
assertEquals(Event.Type.ARRIVAL, event.type);
assertEquals(0, event.nodeIndex);
state.updateArrival(event.time);
assertEquals(1, state.stats.numArrivals, DELTA);
assertEquals(0, state.numServerBusy);
event = state.spawnDepartureIfPossible(event.time, rigged);
assertNotNull(event);
assertEquals(1, state.stats.numArrivals, DELTA);
assertEquals(0, state.stats.numDepartures, DELTA);
assertEquals(1, state.numServerBusy);
assertEquals(0, state.numServerUnavailable);
assertEquals(Event.Type.DEPARTURE, event.type);
assertEquals(0, event.nodeIndex);
state.updateDeparture(event.time);
assertEquals(1, state.stats.numArrivals, DELTA);
assertEquals(1, state.stats.numDepartures, DELTA);
assertEquals(0, state.numServerBusy);
assertEquals(0, state.numServerUnavailable);
state = new ServerNodeState(1, net);
event = state.spawnArrivalIfPossilbe(0);
assertNull(event);
assertEquals(0, state.stats.numArrivals, DELTA);
assertEquals(0, state.stats.numDepartures, DELTA);
assertEquals(0, state.numServerBusy);
assertEquals(0, state.numServerUnavailable);
state.updateArrival(0);
assertEquals(1, state.stats.numArrivals, DELTA);
assertEquals(0, state.numServerBusy);
event = state.spawnDepartureIfPossible(0, rigged);
assertNotNull(event);
assertEquals(1, state.stats.numArrivals, DELTA);
assertEquals(0, state.stats.numDepartures, DELTA);
assertEquals(1, state.numServerBusy);
assertEquals(0, state.numServerUnavailable);
assertEquals(Event.Type.DEPARTURE, event.type);
assertEquals(1, event.nodeIndex);
state.updateDeparture(event.time);
assertEquals(1, state.stats.numArrivals, DELTA);
assertEquals(1, state.stats.numDepartures, DELTA);
assertEquals(0, state.numServerBusy);
assertEquals(0, state.numServerUnavailable);
event = state.spawnUnavailableIfPossible(0, rigged);
assertNull(event);
state = new ServerNodeState(0, net);
event = state.spawnArrivalToChild(0, rigged);
assertNotNull(event);
assertEquals(0, state.stats.numArrivals, DELTA);
assertEquals(0, state.stats.numDepartures, DELTA);
assertEquals(0, state.numServerBusy);
assertEquals(0, state.numServerUnavailable);
assertEquals(Event.Type.ARRIVAL, event.type);
assertEquals(1, event.nodeIndex);
}
@Test
@@ -431,13 +528,13 @@ public class TestSimulation {
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);
assertEquals(3, res.nodes.get(node1.name).numDepartures, DELTA);
}
@Test
public void simulationStats() {
var net = new Net();
net.addNode(ServerNode.createLimitedSource("Source", const1, 50));
net.addNode(ServerNode.Builder.sourceLimited("Source", 50, const1));
var sim = new Simulation(net, rigged);
var result = sim.run();
@@ -454,7 +551,7 @@ public class TestSimulation {
assertEquals(1.0, nodeStat.utilization, DELTA);
assertEquals(0.0, nodeStat.unavailable, DELTA);
net.addNode(ServerNode.createQueue("Queue", 1, const1));
net.addNode(ServerNode.Builder.queue("Queue", 1, const1));
net.addConnection(0, 1, 1.0);
sim = new Simulation(net, rigged);