From c214a7fe0d46ecc23a71f9237b20281c0ca1c929 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 5 Oct 2022 13:22:40 +0200 Subject: refactor(sim/core): Use SimulationScheduler in coroutine dispatcher This change updates the implementation of `SimulationDispatcher` to use a (possibly user-provided) `SimulationScheduler` for managing the execution of the simulation and future tasks. --- .../kotlin/org/opendc/common/util/PacerTest.kt | 2 +- .../org/opendc/common/util/TimerSchedulerTest.kt | 2 +- .../opendc/compute/service/ComputeServiceTest.kt | 4 +- .../opendc/compute/service/InternalServerTest.kt | 2 +- .../org/opendc/compute/simulator/SimHostTest.kt | 2 +- .../simulator/failure/HostFaultInjectorTest.kt | 2 +- .../experiments/capelin/CapelinBenchmarks.kt | 2 +- .../opendc/experiments/capelin/CapelinRunner.kt | 2 +- .../experiments/capelin/CapelinIntegrationTest.kt | 2 +- .../org/opendc/experiments/faas/FaaSExperiment.kt | 2 +- .../org/opendc/experiments/tf20/TensorFlowTest.kt | 2 +- .../experiments/tf20/core/SimTFDeviceTest.kt | 2 +- .../org/opendc/faas/service/FaaSServiceTest.kt | 2 +- .../opendc/faas/simulator/SimFaaSServiceTest.kt | 2 +- .../simulator/compute/SimMachineBenchmarks.kt | 2 +- .../org/opendc/simulator/compute/SimMachineTest.kt | 2 +- .../opendc/simulator/compute/device/SimPsuTest.kt | 2 +- .../compute/kernel/SimFairShareHypervisorTest.kt | 2 +- .../compute/kernel/SimSpaceSharedHypervisorTest.kt | 2 +- .../compute/workload/SimTraceWorkloadTest.kt | 2 +- .../opendc/simulator/core/SimulationBuilders.kt | 75 --------- .../opendc/simulator/core/SimulationController.kt | 46 ------ .../core/SimulationCoroutineDispatcher.kt | 167 --------------------- .../simulator/core/SimulationCoroutineScope.kt | 62 -------- .../opendc/simulator/kotlin/SimulationBuilders.kt | 80 ++++++++++ .../simulator/kotlin/SimulationController.kt | 52 +++++++ .../kotlin/SimulationCoroutineDispatcher.kt | 94 ++++++++++++ .../simulator/kotlin/SimulationCoroutineScope.kt | 66 ++++++++ .../org/opendc/simulator/flow/FlowBenchmarks.kt | 2 +- .../simulator/flow/FlowConsumerContextTest.kt | 2 +- .../org/opendc/simulator/flow/FlowForwarderTest.kt | 2 +- .../org/opendc/simulator/flow/FlowSinkTest.kt | 2 +- .../flow/mux/ForwardingFlowMultiplexerTest.kt | 2 +- .../flow/mux/MaxMinFlowMultiplexerTest.kt | 2 +- .../simulator/flow/source/FixedFlowSourceTest.kt | 2 +- .../opendc/simulator/network/SimNetworkSinkTest.kt | 2 +- .../network/SimNetworkSwitchVirtualTest.kt | 2 +- .../org/opendc/simulator/power/SimPduTest.kt | 2 +- .../opendc/simulator/power/SimPowerSourceTest.kt | 2 +- .../org/opendc/simulator/power/SimUpsTest.kt | 2 +- .../kotlin/org/opendc/web/runner/OpenDCRunner.kt | 2 +- .../opendc/workflow/service/WorkflowServiceTest.kt | 2 +- 42 files changed, 327 insertions(+), 385 deletions(-) delete mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationBuilders.kt delete mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationController.kt delete mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt delete mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineScope.kt create mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationBuilders.kt create mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationController.kt create mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineDispatcher.kt create mode 100644 opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineScope.kt diff --git a/opendc-common/src/test/kotlin/org/opendc/common/util/PacerTest.kt b/opendc-common/src/test/kotlin/org/opendc/common/util/PacerTest.kt index 1cd435f6..066bc13b 100644 --- a/opendc-common/src/test/kotlin/org/opendc/common/util/PacerTest.kt +++ b/opendc-common/src/test/kotlin/org/opendc/common/util/PacerTest.kt @@ -26,7 +26,7 @@ import kotlinx.coroutines.delay import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.time.Clock import kotlin.coroutines.EmptyCoroutineContext diff --git a/opendc-common/src/test/kotlin/org/opendc/common/util/TimerSchedulerTest.kt b/opendc-common/src/test/kotlin/org/opendc/common/util/TimerSchedulerTest.kt index 01f61f92..93da5646 100644 --- a/opendc-common/src/test/kotlin/org/opendc/common/util/TimerSchedulerTest.kt +++ b/opendc-common/src/test/kotlin/org/opendc/common/util/TimerSchedulerTest.kt @@ -26,7 +26,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.time.Clock import kotlin.coroutines.EmptyCoroutineContext diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt index cc7be4a8..6c251516 100644 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt +++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt @@ -39,8 +39,8 @@ import org.opendc.compute.service.scheduler.filters.ComputeFilter import org.opendc.compute.service.scheduler.filters.RamFilter import org.opendc.compute.service.scheduler.filters.VCpuFilter import org.opendc.compute.service.scheduler.weights.RamWeigher -import org.opendc.simulator.core.SimulationCoroutineScope -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.SimulationCoroutineScope +import org.opendc.simulator.kotlin.runBlockingSimulation import java.util.* /** diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt index 4e5a37ae..0d44722b 100644 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt +++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/InternalServerTest.kt @@ -34,7 +34,7 @@ import org.opendc.compute.service.internal.ComputeServiceImpl import org.opendc.compute.service.internal.InternalFlavor import org.opendc.compute.service.internal.InternalImage import org.opendc.compute.service.internal.InternalServer -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.util.* /** diff --git a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt index a7993291..1634473e 100644 --- a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt +++ b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt @@ -41,9 +41,9 @@ import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceFragment import org.opendc.simulator.compute.workload.SimTraceWorkload -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.mux.FlowMultiplexerFactory +import org.opendc.simulator.kotlin.runBlockingSimulation import java.time.Instant import java.util.* import kotlin.coroutines.resume diff --git a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt index f240a25f..5b71e716 100644 --- a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt +++ b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt @@ -29,7 +29,7 @@ import org.apache.commons.math3.distribution.LogNormalDistribution import org.apache.commons.math3.random.Well19937c import org.junit.jupiter.api.Test import org.opendc.compute.simulator.SimHost -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.time.Clock import java.time.Duration import kotlin.coroutines.CoroutineContext diff --git a/opendc-experiments/opendc-experiments-capelin/src/jmh/kotlin/org/opendc/experiments/capelin/CapelinBenchmarks.kt b/opendc-experiments/opendc-experiments-capelin/src/jmh/kotlin/org/opendc/experiments/capelin/CapelinBenchmarks.kt index f021e223..ea3d9b0d 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/jmh/kotlin/org/opendc/experiments/capelin/CapelinBenchmarks.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/jmh/kotlin/org/opendc/experiments/capelin/CapelinBenchmarks.kt @@ -32,7 +32,7 @@ import org.opendc.experiments.capelin.topology.clusterTopology import org.opendc.experiments.compute.* import org.opendc.experiments.compute.topology.HostSpec import org.opendc.experiments.provisioner.Provisioner -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import org.openjdk.jmh.annotations.* import java.io.File import java.util.* diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinRunner.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinRunner.kt index f1214b08..669fd3b1 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinRunner.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinRunner.kt @@ -28,7 +28,7 @@ import org.opendc.experiments.capelin.topology.clusterTopology import org.opendc.experiments.compute.* import org.opendc.experiments.compute.export.parquet.ParquetComputeMonitor import org.opendc.experiments.provisioner.Provisioner -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.io.File import java.time.Duration import java.util.* diff --git a/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt b/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt index 9be2d522..3214a0bd 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt @@ -39,7 +39,7 @@ import org.opendc.experiments.compute.telemetry.table.HostTableReader import org.opendc.experiments.compute.telemetry.table.ServiceTableReader import org.opendc.experiments.compute.topology.HostSpec import org.opendc.experiments.provisioner.Provisioner -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.io.File import java.time.Duration import java.util.* diff --git a/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt index 98328d3e..c558a3e3 100644 --- a/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt +++ b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt @@ -34,7 +34,7 @@ import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.io.File import java.time.Duration diff --git a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt index 328f1326..119ead46 100644 --- a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt +++ b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt @@ -30,7 +30,7 @@ import org.opendc.experiments.tf20.distribute.MirroredStrategy import org.opendc.experiments.tf20.distribute.OneDeviceStrategy import org.opendc.experiments.tf20.util.MLEnvironmentReader import org.opendc.simulator.compute.power.LinearPowerModel -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.util.* /** diff --git a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt index 051d5730..bc561721 100644 --- a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt +++ b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt @@ -31,7 +31,7 @@ import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.power.LinearPowerModel -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.util.* /** diff --git a/opendc-faas/opendc-faas-service/src/test/kotlin/org/opendc/faas/service/FaaSServiceTest.kt b/opendc-faas/opendc-faas-service/src/test/kotlin/org/opendc/faas/service/FaaSServiceTest.kt index 560039c1..dc296c20 100644 --- a/opendc-faas/opendc-faas-service/src/test/kotlin/org/opendc/faas/service/FaaSServiceTest.kt +++ b/opendc-faas/opendc-faas-service/src/test/kotlin/org/opendc/faas/service/FaaSServiceTest.kt @@ -31,7 +31,7 @@ import org.opendc.faas.api.FaaSFunction import org.opendc.faas.service.deployer.FunctionDeployer import org.opendc.faas.service.deployer.FunctionInstance import org.opendc.faas.service.deployer.FunctionInstanceState -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.util.* /** diff --git a/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt b/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt index 5b730089..0f3bb87f 100644 --- a/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt +++ b/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt @@ -42,7 +42,7 @@ import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.workload.SimRuntimeWorkload import org.opendc.simulator.compute.workload.SimWorkload -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import java.time.Duration import java.util.* 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 797d424e..a2dc9a0f 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 @@ -33,9 +33,9 @@ import org.opendc.simulator.compute.power.ConstantPowerModel import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceWorkload -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.mux.FlowMultiplexerFactory +import org.opendc.simulator.kotlin.runBlockingSimulation import org.openjdk.jmh.annotations.* import java.util.SplittableRandom import java.util.concurrent.ThreadLocalRandom 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 644eb497..b0175917 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 @@ -33,9 +33,9 @@ import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.workload.SimFlopsWorkload import org.opendc.simulator.compute.workload.SimWorkload import org.opendc.simulator.compute.workload.SimWorkloadLifecycle -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation import org.opendc.simulator.network.SimNetworkSink import org.opendc.simulator.power.SimPowerSource diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt index e5b509f0..82ceeecd 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt @@ -28,8 +28,8 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.opendc.simulator.compute.power.PowerDriver -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine +import org.opendc.simulator.kotlin.runBlockingSimulation import org.opendc.simulator.power.SimPowerSource /** 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 ddf8cf14..35e14864 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 @@ -41,9 +41,9 @@ import org.opendc.simulator.compute.runWorkload import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceFragment import org.opendc.simulator.compute.workload.SimTraceWorkload -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.mux.FlowMultiplexerFactory +import org.opendc.simulator.kotlin.runBlockingSimulation import java.util.* /** 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 df6755f1..96eabf5c 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 @@ -37,9 +37,9 @@ import org.opendc.simulator.compute.power.ConstantPowerModel import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.runWorkload import org.opendc.simulator.compute.workload.* -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.mux.FlowMultiplexerFactory +import org.opendc.simulator.kotlin.runBlockingSimulation import java.util.* /** 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 aa91984a..bf4e7622 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 @@ -31,8 +31,8 @@ import org.opendc.simulator.compute.model.* import org.opendc.simulator.compute.power.ConstantPowerModel import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.runWorkload -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [SimTraceWorkloadTest] class. diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationBuilders.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationBuilders.kt deleted file mode 100644 index 9b284c11..00000000 --- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationBuilders.kt +++ /dev/null @@ -1,75 +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.core - -import kotlinx.coroutines.* -import kotlin.coroutines.ContinuationInterceptor -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext - -/** - * Executes a [body] inside an immediate execution dispatcher. - */ -@OptIn(ExperimentalCoroutinesApi::class) -public fun runBlockingSimulation(context: CoroutineContext = EmptyCoroutineContext, body: suspend SimulationCoroutineScope.() -> Unit) { - val (safeContext, dispatcher) = context.checkArguments() - val startingJobs = safeContext.activeJobs() - val scope = SimulationCoroutineScope(safeContext) - val deferred = scope.async { - body(scope) - } - dispatcher.advanceUntilIdle() - deferred.getCompletionExceptionOrNull()?.let { - throw it - } - val endingJobs = safeContext.activeJobs() - if ((endingJobs - startingJobs).isNotEmpty()) { - throw IllegalStateException("Test finished with active jobs: $endingJobs") - } -} - -/** - * Convenience method for calling [runBlockingSimulation] on an existing [SimulationCoroutineScope]. - */ -public fun SimulationCoroutineScope.runBlockingSimulation(block: suspend SimulationCoroutineScope.() -> Unit): Unit = - runBlockingSimulation(coroutineContext, block) - -/** - * Convenience method for calling [runBlockingSimulation] on an existing [SimulationCoroutineDispatcher]. - */ -public fun SimulationCoroutineDispatcher.runBlockingSimulation(block: suspend SimulationCoroutineScope.() -> Unit): Unit = - runBlockingSimulation(this, block) - -private fun CoroutineContext.checkArguments(): Pair { - val dispatcher = get(ContinuationInterceptor).run { - this?.let { require(this is SimulationController) { "Dispatcher must implement SimulationController: $this" } } - this ?: SimulationCoroutineDispatcher() - } - - val job = get(Job) ?: SupervisorJob() - return Pair(this + dispatcher + job, dispatcher as SimulationController) -} - -private fun CoroutineContext.activeJobs(): Set { - return checkNotNull(this[Job]).children.filter { it.isActive }.toSet() -} diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationController.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationController.kt deleted file mode 100644 index 2b670b91..00000000 --- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationController.kt +++ /dev/null @@ -1,46 +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.core - -import kotlinx.coroutines.CoroutineDispatcher -import java.time.Clock - -/** - * 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 - - /** - * 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. - * - * @return the amount of delay-time that this Dispatcher's clock has been forwarded in milliseconds. - */ - public fun advanceUntilIdle(): Long -} diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt deleted file mode 100644 index 908e902a..00000000 --- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt +++ /dev/null @@ -1,167 +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.core - -import kotlinx.coroutines.* -import java.lang.Runnable -import java.time.Clock -import java.time.Instant -import java.time.ZoneId -import java.util.* -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. - */ -@OptIn(InternalCoroutinesApi::class) -public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationController, Delay { - /** - * Queue of ordered tasks to run. - */ - private val queue = PriorityQueue() - - /** - * Global order counter. - */ - private var _counter = 0L - - /** - * The current virtual time of simulation - */ - private var _clock = SimClock() - - /** - * The virtual clock of this dispatcher. - */ - override val clock: Clock = ClockAdapter(_clock) - - override fun dispatch(context: CoroutineContext, block: Runnable) { - block.run() - } - - override fun dispatchYield(context: CoroutineContext, block: Runnable) { - post(block) - } - - @OptIn(ExperimentalCoroutinesApi::class) - override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) { - postDelayed(CancellableContinuationRunnable(continuation) { resumeUndispatched(Unit) }, timeMillis) - } - - override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle { - val node = postDelayed(block, timeMillis) - return object : DisposableHandle { - override fun dispose() { - queue.remove(node) - } - } - } - - override fun toString(): String { - return "SimulationCoroutineDispatcher[time=${_clock.time}ms, queued=${queue.size}]" - } - - private fun post(block: Runnable) = - queue.add(TimedRunnable(block, _counter++)) - - private fun postDelayed(block: Runnable, delayTime: Long) = - TimedRunnable(block, _counter++, safePlus(_clock.time, delayTime)) - .also { - queue.add(it) - } - - private fun safePlus(currentTime: Long, delayTime: Long): Long { - check(delayTime >= 0) - val result = currentTime + delayTime - if (result < currentTime) return Long.MAX_VALUE // clamp on overflow - return result - } - - override fun advanceUntilIdle(): Long { - val queue = queue - val clock = _clock - val oldTime = clock.time - - while (true) { - val current = queue.poll() ?: break - - // If the scheduled time is 0 (immediate) use current virtual time - if (current.time != 0L) { - clock.time = current.time - } - - current.run() - } - - return clock.time - oldTime - } - - /** - * A helper class that holds the time of the simulation. - */ - private class SimClock(@JvmField var time: Long = 0) - - /** - * A helper class to expose a [Clock] instance for this dispatcher. - */ - private class ClockAdapter(private val clock: SimClock, private val zone: ZoneId = ZoneId.systemDefault()) : Clock() { - override fun getZone(): ZoneId = zone - - override fun withZone(zone: ZoneId): Clock = ClockAdapter(clock, zone) - - override fun instant(): Instant = Instant.ofEpochMilli(millis()) - - override fun millis(): Long = clock.time - - override fun toString(): String = "SimulationCoroutineDispatcher.ClockAdapter[time=${clock.time}]" - } - - /** - * This class exists to allow cleanup code to avoid throwing for cancelled continuations scheduled - * in the future. - */ - private class CancellableContinuationRunnable( - @JvmField val continuation: CancellableContinuation, - private val block: CancellableContinuation.() -> Unit - ) : Runnable { - override fun run() = continuation.block() - } - - /** - * A Runnable for our event loop that represents a task to perform at a time. - */ - private class TimedRunnable( - @JvmField val runnable: Runnable, - private val count: Long = 0, - @JvmField val time: Long = 0 - ) : Comparable, Runnable by runnable { - override fun compareTo(other: TimedRunnable) = if (time == other.time) { - count.compareTo(other.count) - } else { - time.compareTo(other.time) - } - - override fun toString() = "TimedRunnable[time=$time, run=$runnable]" - } -} diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineScope.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineScope.kt deleted file mode 100644 index 1da7f0fa..00000000 --- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineScope.kt +++ /dev/null @@ -1,62 +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.core - -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlin.coroutines.ContinuationInterceptor -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext - -/** - * A scope which provides detailed control over the execution of coroutines for simulations. - */ -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. - */ -@Suppress("FunctionName") -public fun SimulationCoroutineScope(context: CoroutineContext = EmptyCoroutineContext): SimulationCoroutineScope { - var safeContext = context - if (context[ContinuationInterceptor] == null) safeContext += SimulationCoroutineDispatcher() - return SimulationCoroutineScopeImpl(safeContext) -} - -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)" - ) - } 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 new file mode 100644 index 00000000..a291b4e2 --- /dev/null +++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationBuilders.kt @@ -0,0 +1,80 @@ +/* + * 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.* +import org.opendc.simulator.SimulationScheduler +import kotlin.coroutines.ContinuationInterceptor +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +/** + * Executes a [body] inside an immediate execution dispatcher. + */ +@OptIn(ExperimentalCoroutinesApi::class) +public fun runBlockingSimulation( + context: CoroutineContext = EmptyCoroutineContext, + scheduler: SimulationScheduler = SimulationScheduler(), + body: suspend SimulationCoroutineScope.() -> Unit +) { + val (safeContext, dispatcher) = context.checkArguments(scheduler) + val startingJobs = safeContext.activeJobs() + val scope = SimulationCoroutineScope(safeContext) + val deferred = scope.async { + body(scope) + } + dispatcher.advanceUntilIdle() + deferred.getCompletionExceptionOrNull()?.let { + throw it + } + val endingJobs = safeContext.activeJobs() + if ((endingJobs - startingJobs).isNotEmpty()) { + throw IllegalStateException("Test finished with active jobs: $endingJobs") + } +} + +/** + * Convenience method for calling [runBlockingSimulation] on an existing [SimulationCoroutineScope]. + */ +public fun SimulationCoroutineScope.runBlockingSimulation(block: suspend SimulationCoroutineScope.() -> Unit): Unit = + runBlockingSimulation(coroutineContext, scheduler, block) + +/** + * Convenience method for calling [runBlockingSimulation] on an existing [SimulationCoroutineDispatcher]. + */ +public fun SimulationCoroutineDispatcher.runBlockingSimulation(block: suspend SimulationCoroutineScope.() -> Unit): Unit = + runBlockingSimulation(this, scheduler, block) + +private fun CoroutineContext.checkArguments(scheduler: SimulationScheduler): Pair { + val dispatcher = get(ContinuationInterceptor).run { + this?.let { require(this is SimulationController) { "Dispatcher must implement SimulationController: $this" } } + this ?: SimulationCoroutineDispatcher(scheduler) + } + + val job = get(Job) ?: SupervisorJob() + return Pair(this + dispatcher + job, dispatcher as SimulationController) +} + +private fun CoroutineContext.activeJobs(): Set { + return checkNotNull(this[Job]).children.filter { it.isActive }.toSet() +} 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 new file mode 100644 index 00000000..f96b2326 --- /dev/null +++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationController.kt @@ -0,0 +1,52 @@ +/* + * 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.CoroutineDispatcher +import org.opendc.simulator.SimulationScheduler +import java.time.Clock + +/** + * 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 + + /** + * The [SimulationScheduler] driving the simulation. + */ + public val scheduler: SimulationScheduler + + /** + * 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. + * + * @return the amount of delay-time that this Dispatcher's clock has been forwarded in milliseconds. + */ + public fun advanceUntilIdle(): Long +} 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 new file mode 100644 index 00000000..21ad1a86 --- /dev/null +++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineDispatcher.kt @@ -0,0 +1,94 @@ +/* + * 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.* +import org.opendc.simulator.SimulationScheduler +import java.lang.Runnable +import java.time.Clock +import java.util.* +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) { + 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( + @JvmField val continuation: CancellableContinuation, + private val block: CancellableContinuation.() -> 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 new file mode 100644 index 00000000..6be8e67a --- /dev/null +++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/kotlin/SimulationCoroutineScope.kt @@ -0,0 +1,66 @@ +/* + * 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.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import org.opendc.simulator.SimulationScheduler +import kotlin.coroutines.ContinuationInterceptor +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +/** + * A scope which provides detailed control over the execution of coroutines for simulations. + */ +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. + */ +@Suppress("FunctionName") +public fun SimulationCoroutineScope( + context: CoroutineContext = EmptyCoroutineContext, + scheduler: SimulationScheduler = SimulationScheduler() +): SimulationCoroutineScope { + var safeContext = context + if (context[ContinuationInterceptor] == null) safeContext += SimulationCoroutineDispatcher(scheduler) + return SimulationCoroutineScopeImpl(safeContext) +} + +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)" + ) + } diff --git a/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow/FlowBenchmarks.kt b/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow/FlowBenchmarks.kt index aabd2220..e3cde1d2 100644 --- a/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow/FlowBenchmarks.kt +++ b/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow/FlowBenchmarks.kt @@ -24,10 +24,10 @@ package org.opendc.simulator.flow import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.mux.ForwardingFlowMultiplexer import org.opendc.simulator.flow.mux.MaxMinFlowMultiplexer import org.opendc.simulator.flow.source.TraceFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation import org.openjdk.jmh.annotations.* import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.TimeUnit diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowConsumerContextTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowConsumerContextTest.kt index e7b25554..220b247f 100644 --- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowConsumerContextTest.kt +++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowConsumerContextTest.kt @@ -24,9 +24,9 @@ package org.opendc.simulator.flow import io.mockk.* import org.junit.jupiter.api.* -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.internal.FlowConsumerContextImpl import org.opendc.simulator.flow.internal.FlowEngineImpl +import org.opendc.simulator.kotlin.runBlockingSimulation /** * A test suite for the [FlowConsumerContextImpl] class. diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowForwarderTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowForwarderTest.kt index 8b090593..cd183ae2 100644 --- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowForwarderTest.kt +++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowForwarderTest.kt @@ -28,9 +28,9 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.internal.FlowEngineImpl import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * A test suite for the [FlowForwarder] class. diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowSinkTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowSinkTest.kt index 726ddbf7..95cb8123 100644 --- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowSinkTest.kt +++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/FlowSinkTest.kt @@ -27,10 +27,10 @@ import io.mockk.verify import kotlinx.coroutines.* import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.internal.FlowEngineImpl import org.opendc.simulator.flow.source.FixedFlowSource import org.opendc.simulator.flow.source.FlowSourceRateAdapter +import org.opendc.simulator.kotlin.runBlockingSimulation /** * A test suite for the [FlowSink] class. diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/ForwardingFlowMultiplexerTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/ForwardingFlowMultiplexerTest.kt index ef15f711..523dac3a 100644 --- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/ForwardingFlowMultiplexerTest.kt +++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/ForwardingFlowMultiplexerTest.kt @@ -27,12 +27,12 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertAll import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.* import org.opendc.simulator.flow.internal.FlowEngineImpl import org.opendc.simulator.flow.source.FixedFlowSource import org.opendc.simulator.flow.source.FlowSourceRateAdapter import org.opendc.simulator.flow.source.TraceFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [ForwardingFlowMultiplexer] class. diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/MaxMinFlowMultiplexerTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/MaxMinFlowMultiplexerTest.kt index 6e2cdb98..adfc265a 100644 --- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/MaxMinFlowMultiplexerTest.kt +++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/mux/MaxMinFlowMultiplexerTest.kt @@ -27,12 +27,12 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.yield import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowSink import org.opendc.simulator.flow.consume import org.opendc.simulator.flow.internal.FlowEngineImpl import org.opendc.simulator.flow.source.FixedFlowSource import org.opendc.simulator.flow.source.TraceFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [FlowMultiplexer] implementations diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/source/FixedFlowSourceTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/source/FixedFlowSourceTest.kt index 8396d346..99630d32 100644 --- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/source/FixedFlowSourceTest.kt +++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow/source/FixedFlowSourceTest.kt @@ -24,10 +24,10 @@ package org.opendc.simulator.flow.source import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowSink import org.opendc.simulator.flow.consume import org.opendc.simulator.flow.internal.FlowEngineImpl +import org.opendc.simulator.kotlin.runBlockingSimulation /** * A test suite for the [FixedFlowSource] class. 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 2e6983c8..8e95f2b0 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 @@ -30,9 +30,9 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.* import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [SimNetworkSink] class. 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 62e54ffb..b45b150d 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 @@ -27,9 +27,9 @@ import io.mockk.verify import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.* import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [SimNetworkSwitchVirtual] class. 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 7cc4b801..2177a374 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 @@ -27,10 +27,10 @@ import io.mockk.verify import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.FlowSource import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [SimPdu] class. 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 4f319e65..832b9d09 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 @@ -30,10 +30,10 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.FlowSource import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [SimPowerSource] 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 e19e72fa..e3e9dbff 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 @@ -27,10 +27,10 @@ import io.mockk.verify import org.junit.jupiter.api.Assertions.assertAll import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.FlowEngine import org.opendc.simulator.flow.FlowSource import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.kotlin.runBlockingSimulation /** * Test suite for the [SimUps] class. diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt index 74f7c8c1..e2193cf1 100644 --- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt +++ b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt @@ -33,7 +33,7 @@ import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.power.LinearPowerModel import org.opendc.simulator.compute.power.SimplePowerDriver -import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.kotlin.runBlockingSimulation import org.opendc.web.proto.runner.Job import org.opendc.web.proto.runner.Scenario import org.opendc.web.proto.runner.Topology diff --git a/opendc-workflow/opendc-workflow-service/src/test/kotlin/org/opendc/workflow/service/WorkflowServiceTest.kt b/opendc-workflow/opendc-workflow-service/src/test/kotlin/org/opendc/workflow/service/WorkflowServiceTest.kt index f8039e1d..4dc4e196 100644 --- a/opendc-workflow/opendc-workflow-service/src/test/kotlin/org/opendc/workflow/service/WorkflowServiceTest.kt +++ b/opendc-workflow/opendc-workflow-service/src/test/kotlin/org/opendc/workflow/service/WorkflowServiceTest.kt @@ -44,8 +44,8 @@ import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.power.ConstantPowerModel import org.opendc.simulator.compute.power.SimplePowerDriver -import org.opendc.simulator.core.runBlockingSimulation import org.opendc.simulator.flow.mux.FlowMultiplexerFactory +import org.opendc.simulator.kotlin.runBlockingSimulation import org.opendc.trace.Trace import org.opendc.workflow.service.scheduler.job.NullJobAdmissionPolicy import org.opendc.workflow.service.scheduler.job.SubmissionTimeJobOrderPolicy -- cgit v1.2.3