summaryrefslogtreecommitdiff
path: root/opendc-simulator
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-11-09 21:24:08 +0000
committerFabian Mastenbroek <mail.fabianm@gmail.com>2022-11-13 17:42:01 +0000
commit00ac59e8e9d6a41c2eac55aa25420dce8fa9c6e0 (patch)
tree2d921b5573dcaa9b2bbbd1d7ab2e35f711493deb /opendc-simulator
parent7a4b2c45a9926de59754b1d7219159656eea6e6d (diff)
refactor(sim/core): Re-implement SimulationScheduler as Dispatcher
This change updates the `SimulationScheduler` class to implement the `Dispatcher` interface from the OpenDC Common module, so that OpenDC modules only need to depend on the common module for dispatching future task (possibly in simulation).
Diffstat (limited to 'opendc-simulator')
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt8
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt48
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt12
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt20
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt16
-rw-r--r--opendc-simulator/opendc-simulator-core/build.gradle.kts1
-rw-r--r--opendc-simulator/opendc-simulator-core/src/main/java/org/opendc/simulator/SimulationDispatcher.java (renamed from opendc-simulator/opendc-simulator-core/src/main/java/org/opendc/simulator/SimulationScheduler.java)134
-rw-r--r--opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationBuilders.kt74
-rw-r--r--opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationController.kt34
-rw-r--r--opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineDispatcher.kt98
-rw-r--r--opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineScope.kt36
-rw-r--r--opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/SimulationDispatcherTest.kt (renamed from opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/SimulationSchedulerTest.kt)23
-rw-r--r--opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/kotlin/SimulationBuildersTest.kt98
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt8
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt26
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt4
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt4
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt18
-rw-r--r--opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt14
-rw-r--r--opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt4
-rw-r--r--opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt12
-rw-r--r--opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt14
-rw-r--r--opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt8
24 files changed, 399 insertions, 353 deletions
diff --git a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt
index ec032070..b761598b 100644
--- a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt
@@ -74,7 +74,7 @@ class SimMachineBenchmarks {
@Benchmark
fun benchmarkBareMetal() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
return@runSimulation machine.runWorkload(trace.createWorkload(0))
@@ -84,7 +84,7 @@ class SimMachineBenchmarks {
@Benchmark
fun benchmarkSpaceSharedHypervisor() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(1))
@@ -105,7 +105,7 @@ class SimMachineBenchmarks {
@Benchmark
fun benchmarkFairShareHypervisorSingle() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1))
@@ -126,7 +126,7 @@ class SimMachineBenchmarks {
@Benchmark
fun benchmarkFairShareHypervisorDouble() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1))
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
index 2acf6ec7..646d687d 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
@@ -72,7 +72,7 @@ class SimMachineTest {
@Test
fun testFlopsWorkload() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -83,7 +83,7 @@ class SimMachineTest {
machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0))
// Two cores execute 1000 MFlOps per second (1000 ms)
- assertEquals(1000, clock.millis())
+ assertEquals(1000, timeSource.millis())
}
@Test
@@ -97,7 +97,7 @@ class SimMachineTest {
}
val trace = builder.build()
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
graph,
@@ -107,12 +107,12 @@ class SimMachineTest {
machine.runWorkload(trace.createWorkload(0))
// Two cores execute 1000 MFlOps per second (1000 ms)
- assertEquals(1000000000, clock.millis())
+ assertEquals(1000000000, timeSource.millis())
}
@Test
fun testDualSocketMachine() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val cpuNode = machineModel.cpus[0].node
@@ -128,12 +128,12 @@ class SimMachineTest {
machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0))
// Two sockets with two cores execute 2000 MFlOps per second (500 ms)
- assertEquals(500, clock.millis())
+ assertEquals(500, timeSource.millis())
}
@Test
fun testPower() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
graph,
@@ -156,7 +156,7 @@ class SimMachineTest {
@Test
fun testCapacityClamp() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -184,7 +184,7 @@ class SimMachineTest {
@Test
fun testMemory() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -206,7 +206,7 @@ class SimMachineTest {
@Test
fun testMemoryUsage() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -225,12 +225,12 @@ class SimMachineTest {
override fun snapshot(): SimWorkload = TODO()
})
- assertEquals(1000, clock.millis())
+ assertEquals(1000, timeSource.millis())
}
@Test
fun testNetUsage() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -253,12 +253,12 @@ class SimMachineTest {
override fun snapshot(): SimWorkload = TODO()
})
- assertEquals(40, clock.millis())
+ assertEquals(40, timeSource.millis())
}
@Test
fun testDiskReadUsage() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -278,12 +278,12 @@ class SimMachineTest {
override fun snapshot(): SimWorkload = TODO()
})
- assertEquals(4000, clock.millis())
+ assertEquals(4000, timeSource.millis())
}
@Test
fun testDiskWriteUsage() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -303,12 +303,12 @@ class SimMachineTest {
override fun snapshot(): SimWorkload = TODO()
})
- assertEquals(4000, clock.millis())
+ assertEquals(4000, timeSource.millis())
}
@Test
fun testCancellation() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -325,12 +325,12 @@ class SimMachineTest {
// Ignore
}
- assertEquals(0, clock.millis())
+ assertEquals(0, timeSource.millis())
}
@Test
fun testConcurrentRuns() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -351,7 +351,7 @@ class SimMachineTest {
@Test
fun testCatchStartFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -367,7 +367,7 @@ class SimMachineTest {
@Test
fun testCatchStopFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -384,7 +384,7 @@ class SimMachineTest {
@Test
fun testCatchShutdownFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -400,7 +400,7 @@ class SimMachineTest {
@Test
fun testCatchNestedFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt
index 79669d40..f60ff67c 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt
@@ -74,7 +74,7 @@ internal class SimFairShareHypervisorTest {
SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1)
).createWorkload(0)
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, model)
@@ -93,7 +93,7 @@ internal class SimFairShareHypervisorTest {
{ assertEquals(319781, hypervisor.counters.cpuActiveTime, "Active time does not match") },
{ assertEquals(880219, hypervisor.counters.cpuIdleTime, "Idle time does not match") },
{ assertEquals(28125, hypervisor.counters.cpuStealTime, "Steal time does not match") },
- { assertEquals(1200000, clock.millis()) { "Current time is correct" } }
+ { assertEquals(1200000, timeSource.millis()) { "Current time is correct" } }
)
}
@@ -118,7 +118,7 @@ internal class SimFairShareHypervisorTest {
SimTraceFragment(duration * 3000, duration * 1000, 73.0, 1)
).createWorkload(0)
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, model)
@@ -145,7 +145,7 @@ internal class SimFairShareHypervisorTest {
{ assertEquals(329250, hypervisor.counters.cpuActiveTime, "Active time does not match") },
{ assertEquals(870750, hypervisor.counters.cpuIdleTime, "Idle time does not match") },
{ assertEquals(318750, hypervisor.counters.cpuStealTime, "Steal time does not match") },
- { assertEquals(1200000, clock.millis()) }
+ { assertEquals(1200000, timeSource.millis()) }
)
}
@@ -157,7 +157,7 @@ internal class SimFairShareHypervisorTest {
/*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
)
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, model)
@@ -184,7 +184,7 @@ internal class SimFairShareHypervisorTest {
.addGroup(setOf("a", "n"), 0.1, 0.8)
.build()
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, model)
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt
index d11b91ee..31718794 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt
@@ -75,7 +75,7 @@ internal class SimSpaceSharedHypervisorTest {
SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1)
).createWorkload(0)
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
@@ -89,7 +89,7 @@ internal class SimSpaceSharedHypervisorTest {
hypervisor.removeMachine(vm)
machine.cancel()
- assertEquals(5 * 60L * 4000, clock.millis()) { "Took enough time" }
+ assertEquals(5 * 60L * 4000, timeSource.millis()) { "Took enough time" }
}
/**
@@ -99,7 +99,7 @@ internal class SimSpaceSharedHypervisorTest {
fun testRuntimeWorkload() = runSimulation {
val duration = 5 * 60L * 1000
val workload = SimWorkloads.runtime(duration, 1.0)
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
@@ -113,7 +113,7 @@ internal class SimSpaceSharedHypervisorTest {
machine.cancel()
- assertEquals(duration, clock.millis()) { "Took enough time" }
+ assertEquals(duration, timeSource.millis()) { "Took enough time" }
}
/**
@@ -123,7 +123,7 @@ internal class SimSpaceSharedHypervisorTest {
fun testFlopsWorkload() = runSimulation {
val duration = 5 * 60L * 1000
val workload = SimWorkloads.flops((duration * 3.2).toLong(), 1.0)
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
@@ -135,7 +135,7 @@ internal class SimSpaceSharedHypervisorTest {
vm.runWorkload(workload)
machine.cancel()
- assertEquals(duration, clock.millis()) { "Took enough time" }
+ assertEquals(duration, timeSource.millis()) { "Took enough time" }
}
/**
@@ -144,7 +144,7 @@ internal class SimSpaceSharedHypervisorTest {
@Test
fun testTwoWorkloads() = runSimulation {
val duration = 5 * 60L * 1000
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
@@ -165,7 +165,7 @@ internal class SimSpaceSharedHypervisorTest {
machine.cancel()
- assertEquals(duration * 2, clock.millis()) { "Took enough time" }
+ assertEquals(duration * 2, timeSource.millis()) { "Took enough time" }
}
/**
@@ -173,7 +173,7 @@ internal class SimSpaceSharedHypervisorTest {
*/
@Test
fun testConcurrentWorkloadFails() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
@@ -200,7 +200,7 @@ internal class SimSpaceSharedHypervisorTest {
*/
@Test
fun testConcurrentWorkloadSucceeds() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt
index d0b0efaa..c208a2af 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt
@@ -59,7 +59,7 @@ class SimChainWorkloadTest {
@Test
fun testMultipleWorkloads() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -75,12 +75,12 @@ class SimChainWorkloadTest {
machine.runWorkload(workload)
- assertEquals(2000, clock.millis())
+ assertEquals(2000, timeSource.millis())
}
@Test
fun testStartFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -100,12 +100,12 @@ class SimChainWorkloadTest {
assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- assertEquals(0, clock.millis())
+ assertEquals(0, timeSource.millis())
}
@Test
fun testStartFailureSecond() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -126,12 +126,12 @@ class SimChainWorkloadTest {
assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- assertEquals(1000, clock.millis())
+ assertEquals(1000, timeSource.millis())
}
@Test
fun testStopFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -150,12 +150,12 @@ class SimChainWorkloadTest {
assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- assertEquals(1000, clock.millis())
+ assertEquals(1000, timeSource.millis())
}
@Test
fun testStopFailureSecond() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -175,12 +175,12 @@ class SimChainWorkloadTest {
assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- assertEquals(2000, clock.millis())
+ assertEquals(2000, timeSource.millis())
}
@Test
fun testStartAndStopFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -201,12 +201,12 @@ class SimChainWorkloadTest {
val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
assertEquals(2, exc.cause!!.suppressedExceptions.size)
- assertEquals(1000, clock.millis())
+ assertEquals(1000, timeSource.millis())
}
@Test
fun testShutdownAndStopFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -227,12 +227,12 @@ class SimChainWorkloadTest {
val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
assertEquals(1, exc.cause!!.suppressedExceptions.size)
- assertEquals(1000, clock.millis())
+ assertEquals(1000, timeSource.millis())
}
@Test
fun testShutdownAndStartFailure() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -255,12 +255,12 @@ class SimChainWorkloadTest {
val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
assertEquals(1, exc.cause!!.suppressedExceptions.size)
- assertEquals(1000, clock.millis())
+ assertEquals(1000, timeSource.millis())
}
@Test
fun testSnapshot() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(graph, machineModel)
@@ -276,10 +276,10 @@ class SimChainWorkloadTest {
job.join()
- assertEquals(2000, clock.millis())
+ assertEquals(2000, timeSource.millis())
machine.runWorkload(snapshot)
- assertEquals(3500, clock.millis())
+ assertEquals(3500, timeSource.millis())
}
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt
index e3b6e6c5..c0bdfd25 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt
@@ -53,7 +53,7 @@ class SimTraceWorkloadTest {
@Test
fun testSmoke() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -71,12 +71,12 @@ class SimTraceWorkloadTest {
machine.runWorkload(workload)
- assertEquals(4000, clock.millis())
+ assertEquals(4000, timeSource.millis())
}
@Test
fun testOffset() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -94,12 +94,12 @@ class SimTraceWorkloadTest {
machine.runWorkload(workload)
- assertEquals(5000, clock.millis())
+ assertEquals(5000, timeSource.millis())
}
@Test
fun testSkipFragment() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -118,12 +118,12 @@ class SimTraceWorkloadTest {
delay(1000L)
machine.runWorkload(workload)
- assertEquals(4000, clock.millis())
+ assertEquals(4000, timeSource.millis())
}
@Test
fun testZeroCores() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val machine = SimBareMetalMachine.create(
@@ -141,6 +141,6 @@ class SimTraceWorkloadTest {
machine.runWorkload(workload)
- assertEquals(4000, clock.millis())
+ assertEquals(4000, timeSource.millis())
}
}
diff --git a/opendc-simulator/opendc-simulator-core/build.gradle.kts b/opendc-simulator/opendc-simulator-core/build.gradle.kts
index 0de96a8e..0ae95d42 100644
--- a/opendc-simulator/opendc-simulator-core/build.gradle.kts
+++ b/opendc-simulator/opendc-simulator-core/build.gradle.kts
@@ -28,5 +28,6 @@ plugins {
}
dependencies {
+ api(projects.opendc.opendcCommon)
api(libs.kotlinx.coroutines)
}
diff --git a/opendc-simulator/opendc-simulator-core/src/main/java/org/opendc/simulator/SimulationScheduler.java b/opendc-simulator/opendc-simulator-core/src/main/java/org/opendc/simulator/SimulationDispatcher.java
index 305bdf5e..8c74aacf 100644
--- a/opendc-simulator/opendc-simulator-core/src/main/java/org/opendc/simulator/SimulationScheduler.java
+++ b/opendc-simulator/opendc-simulator-core/src/main/java/org/opendc/simulator/SimulationDispatcher.java
@@ -22,17 +22,17 @@
package org.opendc.simulator;
-import java.time.Clock;
import java.time.Instant;
-import java.time.ZoneId;
-import java.util.concurrent.Executor;
+import java.time.InstantSource;
+import org.opendc.common.Dispatcher;
+import org.opendc.common.DispatcherHandle;
/**
- * A scheduler is used by simulations to manage execution of (future) tasks, providing a controllable (virtual) clock to
- * skip over delays.
+ * A {@link Dispatcher} used by simulations to manage execution of (future) tasks, providing a controllable (virtual)
+ * clock to skip over delays.
*
* <p>
- * The scheduler can be queried to advance the time (via {@link #advanceBy}), run all the scheduled tasks advancing the
+ * The dispatcher can be queried to advance the time (via {@link #advanceBy}), run all the scheduled tasks advancing the
* virtual time as needed (via {@link #advanceUntilIdle}), or run the tasks that are scheduled to run as soon as
* possible but have not yet been dispatched (via {@link #runCurrent}). These methods execute the pending tasks using
* a single thread.
@@ -40,7 +40,7 @@ import java.util.concurrent.Executor;
* <p>
* This class is not thread-safe and must not be used concurrently by multiple threads.
*/
-public final class SimulationScheduler implements Executor {
+public final class SimulationDispatcher implements Dispatcher {
/**
* The {@link TaskQueue} containing the pending tasks.
*/
@@ -57,36 +57,27 @@ public final class SimulationScheduler implements Executor {
private int count = 0;
/**
- * The {@link Clock} instance linked to this scheduler.
+ * The {@link InstantSource} instance linked to this scheduler.
*/
- private final SimulationClock clock = new SimulationClock(this, ZoneId.systemDefault());
+ private final SimulationClock timeSource = new SimulationClock(this);
/**
- * Construct a {@link SimulationScheduler} instance with the specified initial time.
+ * Construct a {@link SimulationDispatcher} instance with the specified initial time.
*
* @param initialTimeMs The initial virtual time of the scheduler in milliseconds since epoch.
*/
- public SimulationScheduler(long initialTimeMs) {
+ public SimulationDispatcher(long initialTimeMs) {
this.currentTime = initialTimeMs;
}
/**
- * Construct a {@link SimulationScheduler} instance with the initial time set to UNIX Epoch 0.
+ * Construct a {@link SimulationDispatcher} instance with the initial time set to UNIX Epoch 0.
*/
- public SimulationScheduler() {
+ public SimulationDispatcher() {
this(0);
}
/**
- * Return the virtual clock associated with this dispatcher.
- *
- * @return A {@link Clock} tracking the virtual time of the dispatcher.
- */
- public Clock getClock() {
- return clock;
- }
-
- /**
* Return the current virtual timestamp of the dispatcher (in milliseconds since epoch).
*
* @return A long value representing the virtual timestamp of the dispatcher in milliseconds since epoch.
@@ -96,37 +87,30 @@ public final class SimulationScheduler implements Executor {
}
/**
- * Schedule a <code>task</code> that executes after the specified <code>delayMs</code>.
+ * Return the virtual time source associated with this dispatcher.
*
- * @param delayMs The time from now until the execution of the task (in milliseconds).
- * @param task The task to execute after the delay.
- * @return The identifier of the task that can be used together with the timestamp of the task to cancel it.
+ * @return A {@link InstantSource} tracking the virtual time of the dispatcher.
*/
- public int schedule(long delayMs, Runnable task) {
- if (delayMs < 0) {
- throw new IllegalArgumentException(
- "Attempted scheduling an event earlier in time (delay " + delayMs + " ms)");
- }
+ @Override
+ public InstantSource getTimeSource() {
+ return timeSource;
+ }
+ @Override
+ public void schedule(long delayMs, Runnable command) {
+ internalSchedule(delayMs, command);
+ }
+
+ @Override
+ public DispatcherHandle scheduleCancellable(long delayMs, Runnable command) {
long target = currentTime + delayMs;
if (target < 0) {
target = Long.MAX_VALUE;
}
- int id = count++;
- queue.add(target, id, task);
- return id;
- }
-
- /**
- * Cancel a pending task.
- *
- * @param deadline The deadline of the task.
- * @param id The identifier of the task (returned by {@link #schedule(long, Runnable)}).
- * @return A boolean indicating whether a task was actually cancelled.
- */
- public boolean cancel(long deadline, int id) {
- return queue.remove(deadline, id);
+ long deadline = target;
+ int id = internalSchedule(delayMs, command);
+ return () -> internalCancel(deadline, id);
}
/**
@@ -198,50 +182,62 @@ public final class SimulationScheduler implements Executor {
}
/**
- * Schedule the specified command to run at this moment of virtual time.
+ * Schedule a <code>task</code> that executes after the specified <code>delayMs</code>.
*
- * @param command The command to execute.
+ * @param delayMs The time from now until the execution of the task (in milliseconds).
+ * @param task The task to execute after the delay.
+ * @return The identifier of the task that can be used together with the timestamp of the task to cancel it.
*/
- @Override
- public void execute(Runnable command) {
- schedule(0, command);
+ private int internalSchedule(long delayMs, Runnable task) {
+ if (delayMs < 0) {
+ throw new IllegalArgumentException(
+ "Attempted scheduling an event earlier in time (delay " + delayMs + " ms)");
+ }
+
+ long target = currentTime + delayMs;
+ if (target < 0) {
+ target = Long.MAX_VALUE;
+ }
+
+ int id = count++;
+ queue.add(target, id, task);
+ return id;
}
/**
- * A {@link Clock} implementation for a {@link SimulationScheduler}.
+ * Cancel a pending task.
+ *
+ * @param deadline The deadline of the task.
+ * @param id The identifier of the task (returned by {@link #internalSchedule(long, Runnable)}).
+ * @return A boolean indicating whether a task was actually cancelled.
*/
- private static class SimulationClock extends Clock {
- private final SimulationScheduler scheduler;
- private final ZoneId zone;
-
- SimulationClock(SimulationScheduler scheduler, ZoneId zone) {
- this.scheduler = scheduler;
- this.zone = zone;
- }
+ private boolean internalCancel(long deadline, int id) {
+ return queue.remove(deadline, id);
+ }
- @Override
- public ZoneId getZone() {
- return zone;
- }
+ /**
+ * A {@link InstantSource} implementation for a {@link SimulationDispatcher}.
+ */
+ private static class SimulationClock implements InstantSource {
+ private final SimulationDispatcher dispatcher;
- @Override
- public Clock withZone(ZoneId zoneId) {
- return new SimulationClock(scheduler, zone);
+ SimulationClock(SimulationDispatcher dispatcher) {
+ this.dispatcher = dispatcher;
}
@Override
public Instant instant() {
- return Instant.ofEpochMilli(scheduler.currentTime);
+ return Instant.ofEpochMilli(dispatcher.currentTime);
}
@Override
public long millis() {
- return scheduler.currentTime;
+ return dispatcher.currentTime;
}
@Override
public String toString() {
- return "SimulationClock[time=" + millis() + "ms]";
+ return "SimulationDispatcher.InstantSource[time=" + millis() + "ms]";
}
}
}
diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationBuilders.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationBuilders.kt
index 882a0fc5..6e568137 100644
--- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationBuilders.kt
+++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationBuilders.kt
@@ -22,11 +22,18 @@
package org.opendc.simulator.kotlin
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
+import kotlinx.coroutines.NonCancellable.children
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
-import org.opendc.simulator.SimulationScheduler
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import org.opendc.common.DispatcherProvider
+import org.opendc.common.asCoroutineDispatcher
+import org.opendc.simulator.SimulationDispatcher
+import java.time.InstantSource
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
@@ -54,16 +61,16 @@ import kotlin.coroutines.EmptyCoroutineContext
* The simulation is run in a single thread, unless other [CoroutineDispatcher] are used for child coroutines.
* Because of this, child coroutines are not executed in parallel to [body].
* In order for the spawned-off asynchronous code to actually be executed, one must either [yield] or suspend the
- * body some other way, or use commands that control scheduling (see [SimulationScheduler]).
+ * body some other way, or use commands that control scheduling (see [SimulationDispatcher]).
*/
@OptIn(ExperimentalCoroutinesApi::class)
public fun runSimulation(
context: CoroutineContext = EmptyCoroutineContext,
- scheduler: SimulationScheduler = SimulationScheduler(),
+ scheduler: SimulationDispatcher = SimulationDispatcher(),
body: suspend SimulationCoroutineScope.() -> Unit
) {
- val (safeContext, dispatcher) = context.checkArguments(scheduler)
- val startingJobs = safeContext.activeJobs()
+ val (safeContext, job, dispatcher) = context.checkArguments(scheduler)
+ val startingJobs = job.activeJobs()
val scope = SimulationCoroutineScope(safeContext)
val deferred = scope.async {
body(scope)
@@ -72,7 +79,7 @@ public fun runSimulation(
deferred.getCompletionExceptionOrNull()?.let {
throw it
}
- val endingJobs = safeContext.activeJobs()
+ val endingJobs = job.activeJobs()
if ((endingJobs - startingJobs).isNotEmpty()) {
throw IllegalStateException("Test finished with active jobs: $endingJobs")
}
@@ -82,24 +89,51 @@ public fun runSimulation(
* Convenience method for calling [runSimulation] on an existing [SimulationCoroutineScope].
*/
public fun SimulationCoroutineScope.runSimulation(block: suspend SimulationCoroutineScope.() -> Unit): Unit =
- runSimulation(coroutineContext, scheduler, block)
+ runSimulation(coroutineContext, dispatcher, block)
+
+private fun CoroutineContext.checkArguments(scheduler: SimulationDispatcher): Triple<CoroutineContext, Job, SimulationController> {
+ val job = get(Job) ?: SupervisorJob()
+ val dispatcher = get(ContinuationInterceptor) ?: scheduler.asCoroutineDispatcher()
+ val simulationDispatcher = dispatcher.asSimulationDispatcher()
+ return Triple(this + dispatcher + job, job, simulationDispatcher.asController())
+}
+
+private fun Job.activeJobs(): Set<Job> {
+ return children.filter { it.isActive }.toSet()
+}
/**
- * Convenience method for calling [runSimulation] on an existing [SimulationCoroutineDispatcher].
+ * Convert a [ContinuationInterceptor] into a [SimulationDispatcher] if possible.
*/
-public fun SimulationCoroutineDispatcher.runSimulation(block: suspend SimulationCoroutineScope.() -> Unit): Unit =
- runSimulation(this, scheduler, block)
-
-private fun CoroutineContext.checkArguments(scheduler: SimulationScheduler): Pair<CoroutineContext, SimulationController> {
- val dispatcher = get(ContinuationInterceptor).run {
- this?.let { require(this is SimulationController) { "Dispatcher must implement SimulationController: $this" } }
- this ?: SimulationCoroutineDispatcher(scheduler)
- }
+internal fun ContinuationInterceptor.asSimulationDispatcher(): SimulationDispatcher {
+ val provider = this as? DispatcherProvider ?: throw IllegalArgumentException(
+ "DispatcherProvider such as SimulatorCoroutineDispatcher as the ContinuationInterceptor(Dispatcher) is required"
+ )
- val job = get(Job) ?: SupervisorJob()
- return Pair(this + dispatcher + job, dispatcher as SimulationController)
+ return provider.dispatcher as? SimulationDispatcher ?: throw IllegalArgumentException("Active dispatcher is not a SimulationDispatcher")
}
-private fun CoroutineContext.activeJobs(): Set<Job> {
- return checkNotNull(this[Job]).children.filter { it.isActive }.toSet()
+/**
+ * Helper method to convert a [SimulationDispatcher] into a [SimulationController].
+ */
+internal fun SimulationDispatcher.asController(): SimulationController {
+ return object : SimulationController {
+ override val dispatcher: SimulationDispatcher
+ get() = this@asController
+
+ override val timeSource: InstantSource
+ get() = this@asController.timeSource
+
+ override fun advanceUntilIdle() {
+ dispatcher.advanceUntilIdle()
+ }
+
+ override fun advanceBy(delayMs: Long) {
+ dispatcher.advanceBy(delayMs)
+ }
+
+ override fun runCurrent() {
+ dispatcher.runCurrent()
+ }
+ }
}
diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationController.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationController.kt
index f96b2326..f7470ad9 100644
--- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationController.kt
+++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationController.kt
@@ -23,30 +23,48 @@
package org.opendc.simulator.kotlin
import kotlinx.coroutines.CoroutineDispatcher
-import org.opendc.simulator.SimulationScheduler
-import java.time.Clock
+import org.opendc.simulator.SimulationDispatcher
+import java.time.InstantSource
/**
- * Control the virtual clock of a [CoroutineDispatcher].
+ * Interface to control the virtual clock of a [CoroutineDispatcher].
*/
public interface SimulationController {
/**
* The current virtual clock as it is known to this Dispatcher.
*/
- public val clock: Clock
+ public val timeSource: InstantSource
/**
- * The [SimulationScheduler] driving the simulation.
+ * The current virtual timestamp of the dispatcher (in milliseconds since epoch).
*/
- public val scheduler: SimulationScheduler
+ public val currentTime: Long
+ get() = timeSource.millis()
+
+ /**
+ * Return the [SimulationDispatcher] driving the simulation.
+ */
+ public val dispatcher: SimulationDispatcher
/**
* Immediately execute all pending tasks and advance the virtual clock-time to the last delay.
*
* If new tasks are scheduled due to advancing virtual time, they will be executed before `advanceUntilIdle`
* returns.
+ */
+ public fun advanceUntilIdle()
+
+ /**
+ * Move the virtual clock of this dispatcher forward by the specified amount, running the scheduled tasks in the
+ * meantime.
*
- * @return the amount of delay-time that this Dispatcher's clock has been forwarded in milliseconds.
+ * @param delayMs The amount of time to move the virtual clock forward (in milliseconds).
+ * @throws IllegalStateException if passed a negative <code>delay</code>.
+ */
+ public fun advanceBy(delayMs: Long)
+
+ /**
+ * Execute the tasks that are scheduled to execute at this moment of virtual time.
*/
- public fun advanceUntilIdle(): Long
+ public fun runCurrent()
}
diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineDispatcher.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineDispatcher.kt
deleted file mode 100644
index cacbbbf7..00000000
--- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineDispatcher.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.kotlin
-
-import kotlinx.coroutines.CancellableContinuation
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.Delay
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.InternalCoroutinesApi
-import org.opendc.simulator.SimulationScheduler
-import java.lang.Runnable
-import java.time.Clock
-import kotlin.coroutines.CoroutineContext
-
-/**
- * A [CoroutineDispatcher] that performs both immediate execution of coroutines on the main thread and uses a virtual
- * clock for time management.
- *
- * @param scheduler The [SimulationScheduler] used to manage the execution of future tasks.
- */
-@OptIn(InternalCoroutinesApi::class)
-public class SimulationCoroutineDispatcher(
- override val scheduler: SimulationScheduler = SimulationScheduler()
-) : CoroutineDispatcher(), SimulationController, Delay {
- /**
- * The virtual clock of this dispatcher.
- */
- override val clock: Clock = scheduler.clock
-
- override fun dispatch(context: CoroutineContext, block: Runnable) {
- block.run()
- }
-
- override fun dispatchYield(context: CoroutineContext, block: Runnable) {
- scheduler.execute(block)
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
- scheduler.schedule(timeMillis, CancellableContinuationRunnable(continuation) { resumeUndispatched(Unit) })
- }
-
- override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle {
- return object : DisposableHandle {
- private val deadline = (scheduler.currentTime + timeMillis).let { if (it >= 0) it else Long.MAX_VALUE }
- private val id = scheduler.schedule(timeMillis, block)
-
- override fun dispose() {
- scheduler.cancel(deadline, id)
- }
- }
- }
-
- override fun toString(): String {
- return "SimulationCoroutineDispatcher[time=${scheduler.currentTime}ms]"
- }
-
- override fun advanceUntilIdle(): Long {
- val scheduler = scheduler
- val oldTime = scheduler.currentTime
-
- scheduler.advanceUntilIdle()
-
- return scheduler.currentTime - oldTime
- }
-
- /**
- * This class exists to allow cleanup code to avoid throwing for cancelled continuations scheduled
- * in the future.
- */
- private class CancellableContinuationRunnable<T>(
- @JvmField val continuation: CancellableContinuation<T>,
- private val block: CancellableContinuation<T>.() -> Unit
- ) : Runnable {
- override fun run() = continuation.block()
- }
-}
diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineScope.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineScope.kt
index 6be8e67a..ca49fc53 100644
--- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineScope.kt
+++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineScope.kt
@@ -24,7 +24,8 @@ package org.opendc.simulator.kotlin
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
-import org.opendc.simulator.SimulationScheduler
+import org.opendc.common.asCoroutineDispatcher
+import org.opendc.simulator.SimulationDispatcher
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
@@ -34,33 +35,28 @@ import kotlin.coroutines.EmptyCoroutineContext
*/
public interface SimulationCoroutineScope : CoroutineScope, SimulationController
-private class SimulationCoroutineScopeImpl(
- override val coroutineContext: CoroutineContext
-) :
- SimulationCoroutineScope,
- SimulationController by coroutineContext.simulationController
-
/**
* A scope which provides detailed control over the execution of coroutines for simulations.
*
* If the provided context does not provide a [ContinuationInterceptor] (Dispatcher) or [CoroutineExceptionHandler], the
- * scope adds [SimulationCoroutineDispatcher] automatically.
+ * scope adds a dispatcher automatically.
*/
-@Suppress("FunctionName")
public fun SimulationCoroutineScope(
context: CoroutineContext = EmptyCoroutineContext,
- scheduler: SimulationScheduler = SimulationScheduler()
+ scheduler: SimulationDispatcher = SimulationDispatcher()
): SimulationCoroutineScope {
var safeContext = context
- if (context[ContinuationInterceptor] == null) safeContext += SimulationCoroutineDispatcher(scheduler)
- return SimulationCoroutineScopeImpl(safeContext)
-}
+ val simulationDispatcher: SimulationDispatcher
+ val interceptor = context[ContinuationInterceptor]
-private inline val CoroutineContext.simulationController: SimulationController
- get() {
- val handler = this[ContinuationInterceptor]
- return handler as? SimulationController ?: throw IllegalArgumentException(
- "SimulationCoroutineScope requires a SimulationController such as SimulatorCoroutineDispatcher as " +
- "the ContinuationInterceptor (Dispatcher)"
- )
+ if (interceptor != null) {
+ simulationDispatcher = interceptor.asSimulationDispatcher()
+ } else {
+ simulationDispatcher = scheduler
+ safeContext += scheduler.asCoroutineDispatcher()
}
+
+ return object : SimulationCoroutineScope, SimulationController by simulationDispatcher.asController() {
+ override val coroutineContext: CoroutineContext = safeContext
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/SimulationSchedulerTest.kt b/opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/SimulationDispatcherTest.kt
index eca3b582..600102be 100644
--- a/opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/SimulationSchedulerTest.kt
+++ b/opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/SimulationDispatcherTest.kt
@@ -28,15 +28,15 @@ import org.junit.jupiter.api.assertThrows
import java.time.Instant
/**
- * Test suite for the [SimulationScheduler] class.
+ * Test suite for the [SimulationDispatcher] class.
*/
-class SimulationSchedulerTest {
+class SimulationDispatcherTest {
/**
- * Test the basic functionality of [SimulationScheduler.runCurrent].
+ * Test the basic functionality of [SimulationDispatcher.runCurrent].
*/
@Test
fun testRunCurrent() {
- val scheduler = SimulationScheduler()
+ val scheduler = SimulationDispatcher()
var count = 0
scheduler.schedule(1) { count += 1 }
@@ -58,11 +58,11 @@ class SimulationSchedulerTest {
}
/**
- * Test the clock of the [SimulationScheduler].
+ * Test the clock of the [SimulationDispatcher].
*/
@Test
fun testClock() {
- val scheduler = SimulationScheduler()
+ val scheduler = SimulationDispatcher()
var count = 0
scheduler.schedule(1) { count += 1 }
@@ -70,8 +70,8 @@ class SimulationSchedulerTest {
scheduler.advanceBy(2)
assertEquals(2, scheduler.currentTime)
- assertEquals(2, scheduler.clock.millis())
- assertEquals(Instant.ofEpochMilli(2), scheduler.clock.instant())
+ assertEquals(2, scheduler.timeSource.millis())
+ assertEquals(Instant.ofEpochMilli(2), scheduler.timeSource.instant())
}
/**
@@ -79,7 +79,7 @@ class SimulationSchedulerTest {
*/
@Test
fun testAdvanceByLargeDelays() {
- val scheduler = SimulationScheduler()
+ val scheduler = SimulationDispatcher()
var count = 0
scheduler.schedule(1) { count += 1 }
@@ -87,10 +87,11 @@ class SimulationSchedulerTest {
scheduler.advanceBy(10)
scheduler.schedule(Long.MAX_VALUE) { count += 1 }
+ scheduler.scheduleCancellable(Long.MAX_VALUE) { count += 1 }
scheduler.schedule(100_000_000) { count += 1 }
scheduler.advanceUntilIdle()
- assertEquals(3, count)
+ assertEquals(4, count)
}
/**
@@ -98,7 +99,7 @@ class SimulationSchedulerTest {
*/
@Test
fun testNegativeDelays() {
- val scheduler = SimulationScheduler()
+ val scheduler = SimulationDispatcher()
assertThrows<IllegalArgumentException> { scheduler.schedule(-100) { } }
assertThrows<IllegalArgumentException> { scheduler.advanceBy(-100) }
diff --git a/opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/kotlin/SimulationBuildersTest.kt b/opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/kotlin/SimulationBuildersTest.kt
new file mode 100644
index 00000000..26419a50
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-core/src/test/kotlin/org/opendc/simulator/kotlin/SimulationBuildersTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.kotlin
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+
+/**
+ * Test suite for the Kotlin simulation builders.
+ */
+class SimulationBuildersTest {
+ @Test
+ fun testDelay() = runSimulation {
+ assertEquals(0, currentTime)
+ delay(100)
+ assertEquals(100, currentTime)
+ }
+
+ @Test
+ fun testController() = runSimulation {
+ var completed = false
+
+ launch {
+ delay(20)
+ completed = true
+ }
+
+ advanceBy(10)
+ assertFalse(completed)
+ advanceBy(11)
+ assertTrue(completed)
+
+ completed = false
+ launch { completed = true }
+ runCurrent()
+ assertTrue(completed)
+ }
+
+ @Test
+ fun testFailOnActiveJobs() {
+ assertThrows<IllegalStateException> {
+ runSimulation {
+ launch { suspendCancellableCoroutine {} }
+ }
+ }
+ }
+
+ @Test
+ fun testPropagateException() {
+ assertThrows<IllegalStateException> {
+ runSimulation {
+ throw IllegalStateException("Test")
+ }
+ }
+ }
+
+ @Test
+ fun testInvalidDispatcher() {
+ assertThrows<IllegalArgumentException> {
+ runSimulation(Dispatchers.Default) { }
+ }
+ }
+
+ @Test
+ fun testExistingJob() {
+ runSimulation(Job()) {
+ delay(10)
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt b/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt
index fb112082..5a67c7d2 100644
--- a/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt
@@ -60,7 +60,7 @@ class FlowBenchmarks {
@Benchmark
fun benchmarkSink() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 4200.0f)
val source = TraceFlowSource(graph, trace)
@@ -71,7 +71,7 @@ class FlowBenchmarks {
@Benchmark
fun benchmarkForward() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 4200.0f)
val source = TraceFlowSource(graph, trace)
@@ -85,7 +85,7 @@ class FlowBenchmarks {
@Benchmark
fun benchmarkMuxMaxMinSingleSource() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val switch = MaxMinFlowMultiplexer(graph)
@@ -103,7 +103,7 @@ class FlowBenchmarks {
@Benchmark
fun benchmarkMuxMaxMinTripleSource() {
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val switch = MaxMinFlowMultiplexer(graph)
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt
index 839835ce..b5054375 100644
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt
@@ -38,7 +38,7 @@ import org.opendc.simulator.kotlin.runSimulation
class FlowEngineTest {
@Test
fun testSmoke() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val multiplexer = MaxMinFlowMultiplexer(graph)
@@ -55,7 +55,7 @@ class FlowEngineTest {
@Test
fun testConnectInvalidInlet() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val inlet = mockk<Inlet>()
@@ -65,7 +65,7 @@ class FlowEngineTest {
@Test
fun testConnectInvalidOutlet() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val outlet = mockk<Outlet>()
@@ -75,7 +75,7 @@ class FlowEngineTest {
@Test
fun testConnectInletBelongsToDifferentGraph() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graphA = engine.newGraph()
val graphB = engine.newGraph()
@@ -87,7 +87,7 @@ class FlowEngineTest {
@Test
fun testConnectOutletBelongsToDifferentGraph() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graphA = engine.newGraph()
val graphB = engine.newGraph()
@@ -99,7 +99,7 @@ class FlowEngineTest {
@Test
fun testConnectInletAlreadyConnected() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 2.0f)
@@ -112,7 +112,7 @@ class FlowEngineTest {
@Test
fun testConnectOutletAlreadyConnected() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sinkA = SimpleFlowSink(graph, 2.0f)
@@ -125,7 +125,7 @@ class FlowEngineTest {
@Test
fun testDisconnectInletInvalid() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val inlet = mockk<Inlet>()
@@ -134,7 +134,7 @@ class FlowEngineTest {
@Test
fun testDisconnectOutletInvalid() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val outlet = mockk<Outlet>()
@@ -143,7 +143,7 @@ class FlowEngineTest {
@Test
fun testDisconnectInletInvalidGraph() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graphA = engine.newGraph()
val graphB = engine.newGraph()
@@ -154,7 +154,7 @@ class FlowEngineTest {
@Test
fun testDisconnectOutletInvalidGraph() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graphA = engine.newGraph()
val graphB = engine.newGraph()
@@ -165,7 +165,7 @@ class FlowEngineTest {
@Test
fun testInletEquality() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sinkA = SimpleFlowSink(graph, 2.0f)
@@ -181,7 +181,7 @@ class FlowEngineTest {
@Test
fun testOutletEquality() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sourceA = SimpleFlowSource(graph, 2000.0f, 0.8f)
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt
index a2ed2195..d7a2190f 100644
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt
@@ -39,7 +39,7 @@ class ForwardingFlowMultiplexerTest {
*/
@Test
fun testTrace() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val switch = ForwardingFlowMultiplexer(graph)
@@ -60,7 +60,7 @@ class ForwardingFlowMultiplexerTest {
advanceUntilIdle()
assertAll(
- { assertEquals(4000, clock.millis()) { "Took enough time" } }
+ { assertEquals(4000, timeSource.millis()) { "Took enough time" } }
)
}
}
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt
index ba339ee3..635b1d98 100644
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt
@@ -35,7 +35,7 @@ import org.opendc.simulator.kotlin.runSimulation
class MaxMinFlowMultiplexerTest {
@Test
fun testSmoke() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val switch = MaxMinFlowMultiplexer(graph)
@@ -49,6 +49,6 @@ class MaxMinFlowMultiplexerTest {
advanceUntilIdle()
- assertEquals(500, clock.millis())
+ assertEquals(500, timeSource.millis())
}
}
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt
index a75efba3..d50a40b0 100644
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt
@@ -37,7 +37,7 @@ import java.util.concurrent.ThreadLocalRandom
class FlowSinkTest {
@Test
fun testSmoke() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 1.0f)
@@ -46,12 +46,12 @@ class FlowSinkTest {
graph.connect(source.output, sink.input)
advanceUntilIdle()
- assertEquals(2000, clock.millis())
+ assertEquals(2000, timeSource.millis())
}
@Test
fun testAdjustCapacity() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 1.0f)
@@ -64,12 +64,12 @@ class FlowSinkTest {
advanceUntilIdle()
- assertEquals(3000, clock.millis())
+ assertEquals(3000, timeSource.millis())
}
@Test
fun testUtilization() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 1.0f)
@@ -78,12 +78,12 @@ class FlowSinkTest {
graph.connect(source.output, sink.input)
advanceUntilIdle()
- assertEquals(4000, clock.millis())
+ assertEquals(4000, timeSource.millis())
}
@Test
fun testFragments() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 1.0f)
@@ -100,7 +100,7 @@ class FlowSinkTest {
graph.connect(source.output, sink.input)
advanceUntilIdle()
- assertEquals(4000, clock.millis())
+ assertEquals(4000, timeSource.millis())
}
@Test
@@ -114,7 +114,7 @@ class FlowSinkTest {
)
return runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimpleFlowSink(graph, 4200.0f)
val source = TraceFlowSource(graph, trace)
diff --git a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt
index 8b4ebb89..c1a558b8 100644
--- a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt
+++ b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt
@@ -43,7 +43,7 @@ import org.opendc.simulator.kotlin.runSimulation
class SimNetworkSinkTest {
@Test
fun testInitialState() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
@@ -56,7 +56,7 @@ class SimNetworkSinkTest {
@Test
fun testDisconnectIdempotent() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
@@ -66,7 +66,7 @@ class SimNetworkSinkTest {
@Test
fun testConnectCircular() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
@@ -77,7 +77,7 @@ class SimNetworkSinkTest {
@Test
fun testConnectAlreadyConnectedTarget() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
val source = mockk<SimNetworkPort>(relaxUnitFun = true)
@@ -90,7 +90,7 @@ class SimNetworkSinkTest {
@Test
fun testConnectAlreadyConnected() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
val source1 = TestSource(graph)
@@ -107,7 +107,7 @@ class SimNetworkSinkTest {
@Test
fun testConnect() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
val source = TestSource(graph)
@@ -127,7 +127,7 @@ class SimNetworkSinkTest {
@Test
fun testDisconnect() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
val source = TestSource(graph)
diff --git a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt
index 1507c4a1..e45b1bd7 100644
--- a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt
+++ b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt
@@ -38,7 +38,7 @@ import org.opendc.simulator.kotlin.runSimulation
class SimNetworkSwitchVirtualTest {
@Test
fun testConnect() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
val source = TestSource(graph)
@@ -60,7 +60,7 @@ class SimNetworkSwitchVirtualTest {
@Test
fun testConnectClosedPort() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val sink = SimNetworkSink(graph, /*capacity*/ 100.0f)
val switch = SimNetworkSwitchVirtual(graph)
diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt
index 6adb0548..2e0dc5c4 100644
--- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt
+++ b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt
@@ -35,7 +35,7 @@ import org.opendc.simulator.kotlin.runSimulation
internal class SimPduTest {
@Test
fun testZeroOutlets() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
val pdu = SimPdu(graph)
@@ -48,7 +48,7 @@ internal class SimPduTest {
@Test
fun testSingleOutlet() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
val pdu = SimPdu(graph)
@@ -62,7 +62,7 @@ internal class SimPduTest {
@Test
fun testDoubleOutlet() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 200.0f)
val pdu = SimPdu(graph)
@@ -78,7 +78,7 @@ internal class SimPduTest {
@Test
fun testDisconnect() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 300.0f)
val pdu = SimPdu(graph)
@@ -95,7 +95,7 @@ internal class SimPduTest {
@Test
fun testLoss() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 500.0f)
// https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
@@ -110,7 +110,7 @@ internal class SimPduTest {
@Test
fun testOutletClose() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
val pdu = SimPdu(graph)
diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt
index 03b8182c..0f145592 100644
--- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt
+++ b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt
@@ -42,7 +42,7 @@ import org.opendc.simulator.kotlin.runSimulation
internal class SimPowerSourceTest {
@Test
fun testInitialState() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
@@ -57,7 +57,7 @@ internal class SimPowerSourceTest {
@Test
fun testDisconnectIdempotent() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
@@ -67,7 +67,7 @@ internal class SimPowerSourceTest {
@Test
fun testConnect() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
val inlet = TestInlet(graph)
@@ -87,7 +87,7 @@ internal class SimPowerSourceTest {
@Test
fun testDisconnect() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
val inlet = TestInlet(graph)
@@ -102,7 +102,7 @@ internal class SimPowerSourceTest {
@Test
fun testDisconnectAssertion() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
@@ -120,7 +120,7 @@ internal class SimPowerSourceTest {
@Test
fun testOutletAlreadyConnected() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
val inlet = TestInlet(graph)
@@ -135,7 +135,7 @@ internal class SimPowerSourceTest {
@Test
fun testInletAlreadyConnected() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 100.0f)
val inlet = mockk<SimPowerInlet>(relaxUnitFun = true)
diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt
index 0dd7bb05..4ce83fe9 100644
--- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt
+++ b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt
@@ -35,7 +35,7 @@ import org.opendc.simulator.kotlin.runSimulation
internal class SimUpsTest {
@Test
fun testSingleInlet() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 200.0f)
val ups = SimUps(graph)
@@ -49,7 +49,7 @@ internal class SimUpsTest {
@Test
fun testDoubleInlet() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source1 = SimPowerSource(graph, /*capacity*/ 200.0f)
val source2 = SimPowerSource(graph, /*capacity*/ 200.0f)
@@ -69,7 +69,7 @@ internal class SimUpsTest {
@Test
fun testLoss() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source = SimPowerSource(graph, /*capacity*/ 500.0f)
// https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
@@ -84,7 +84,7 @@ internal class SimUpsTest {
@Test
fun testDisconnect() = runSimulation {
- val engine = FlowEngine.create(coroutineContext, clock)
+ val engine = FlowEngine.create(coroutineContext, timeSource)
val graph = engine.newGraph()
val source1 = SimPowerSource(graph, /*capacity*/ 200.0f)
val source2 = SimPowerSource(graph, /*capacity*/ 200.0f)