From b29f90e5ad5bcac29cde86e56c06e0b65a52cedc Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Mon, 21 Jun 2021 20:57:06 +0200 Subject: simulator: Re-organize compute simulator module This change re-organizes the classes of the compute simulator module to make a clearer distinction between the hardware, firmware and software interfaces in this module. --- .../simulator/compute/SimMachineBenchmarks.kt | 7 +- .../simulator/compute/SimAbstractHypervisor.kt | 170 --------------- .../opendc/simulator/compute/SimAbstractMachine.kt | 3 +- .../simulator/compute/SimBareMetalMachine.kt | 4 +- .../simulator/compute/SimFairShareHypervisor.kt | 93 --------- .../compute/SimFairShareHypervisorProvider.kt | 39 ---- .../org/opendc/simulator/compute/SimHypervisor.kt | 71 ------- .../simulator/compute/SimHypervisorProvider.kt | 48 ----- .../org/opendc/simulator/compute/SimMachine.kt | 3 +- .../opendc/simulator/compute/SimMachineModel.kt | 34 --- .../kotlin/org/opendc/simulator/compute/SimPsu.kt | 115 ----------- .../simulator/compute/SimSpaceSharedHypervisor.kt | 40 ---- .../compute/SimSpaceSharedHypervisorProvider.kt | 39 ---- .../compute/cpufreq/ConservativeScalingGovernor.kt | 65 ------ .../compute/cpufreq/OnDemandScalingGovernor.kt | 50 ----- .../compute/cpufreq/PerformanceScalingGovernor.kt | 36 ---- .../compute/cpufreq/PowerSaveScalingGovernor.kt | 36 ---- .../simulator/compute/cpufreq/ScalingGovernor.kt | 56 ----- .../simulator/compute/cpufreq/ScalingPolicy.kt | 51 ----- .../org/opendc/simulator/compute/device/SimPsu.kt | 115 +++++++++++ .../compute/kernel/SimAbstractHypervisor.kt | 172 ++++++++++++++++ .../compute/kernel/SimFairShareHypervisor.kt | 95 +++++++++ .../kernel/SimFairShareHypervisorProvider.kt | 39 ++++ .../simulator/compute/kernel/SimHypervisor.kt | 73 +++++++ .../compute/kernel/SimHypervisorProvider.kt | 48 +++++ .../compute/kernel/SimSpaceSharedHypervisor.kt | 42 ++++ .../kernel/SimSpaceSharedHypervisorProvider.kt | 39 ++++ .../kernel/cpufreq/ConservativeScalingGovernor.kt | 66 ++++++ .../kernel/cpufreq/OnDemandScalingGovernor.kt | 50 +++++ .../kernel/cpufreq/PerformanceScalingGovernor.kt | 36 ++++ .../kernel/cpufreq/PowerSaveScalingGovernor.kt | 36 ++++ .../compute/kernel/cpufreq/ScalingGovernor.kt | 56 +++++ .../compute/kernel/cpufreq/ScalingPolicy.kt | 51 +++++ .../opendc/simulator/compute/model/MachineModel.kt | 31 +++ .../simulator/compute/util/SimWorkloadLifecycle.kt | 76 ------- .../simulator/compute/workload/SimFlopsWorkload.kt | 1 - .../compute/workload/SimRuntimeWorkload.kt | 1 - .../simulator/compute/workload/SimTraceWorkload.kt | 1 - .../compute/workload/SimWorkloadLifecycle.kt | 75 +++++++ .../opendc/simulator/compute/SimHypervisorTest.kt | 224 -------------------- .../org/opendc/simulator/compute/SimMachineTest.kt | 9 +- .../org/opendc/simulator/compute/SimPsuTest.kt | 102 --------- .../compute/SimSpaceSharedHypervisorTest.kt | 227 -------------------- .../cpufreq/ConservativeScalingGovernorTest.kt | 98 --------- .../compute/cpufreq/OnDemandScalingGovernorTest.kt | 81 -------- .../cpufreq/PerformanceScalingGovernorTest.kt | 50 ----- .../cpufreq/PowerSaveScalingGovernorTest.kt | 72 ------- .../opendc/simulator/compute/device/SimPsuTest.kt | 102 +++++++++ .../simulator/compute/kernel/SimHypervisorTest.kt | 226 ++++++++++++++++++++ .../compute/kernel/SimSpaceSharedHypervisorTest.kt | 229 +++++++++++++++++++++ .../cpufreq/ConservativeScalingGovernorTest.kt | 98 +++++++++ .../kernel/cpufreq/OnDemandScalingGovernorTest.kt | 81 ++++++++ .../cpufreq/PerformanceScalingGovernorTest.kt | 50 +++++ .../kernel/cpufreq/PowerSaveScalingGovernorTest.kt | 72 +++++++ 54 files changed, 1899 insertions(+), 1885 deletions(-) delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimPsu.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingPolicy.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/util/SimWorkloadLifecycle.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimPsuTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernorTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt (limited to 'opendc-simulator/opendc-simulator-compute') 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 fb753de2..8f60bf05 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 @@ -25,6 +25,9 @@ package org.opendc.simulator.compute import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch +import org.opendc.simulator.compute.kernel.SimFairShareHypervisor +import org.opendc.simulator.compute.kernel.SimSpaceSharedHypervisor +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 @@ -45,7 +48,7 @@ import java.util.concurrent.TimeUnit class SimMachineBenchmarks { private lateinit var scope: SimulationCoroutineScope private lateinit var interpreter: SimResourceInterpreter - private lateinit var machineModel: SimMachineModel + private lateinit var machineModel: MachineModel @Setup fun setUp() { @@ -54,7 +57,7 @@ class SimMachineBenchmarks { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = SimMachineModel( + machineModel = MachineModel( cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt deleted file mode 100644 index c560cd28..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt +++ /dev/null @@ -1,170 +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.compute - -import org.opendc.simulator.compute.cpufreq.ScalingGovernor -import org.opendc.simulator.compute.cpufreq.ScalingPolicy -import org.opendc.simulator.compute.interference.PerformanceInterferenceModel -import org.opendc.simulator.compute.model.ProcessingUnit -import org.opendc.simulator.resources.* -import org.opendc.simulator.resources.SimResourceSwitch - -/** - * Abstract implementation of the [SimHypervisor] interface. - * - * @param interpreter The resource interpreter to use. - * @param scalingGovernor The scaling governor to use for scaling the CPU frequency of the underlying hardware. - */ -public abstract class SimAbstractHypervisor( - private val interpreter: SimResourceInterpreter, - private val scalingGovernor: ScalingGovernor? -) : SimHypervisor { - /** - * The machine on which the hypervisor runs. - */ - private lateinit var context: SimMachineContext - - /** - * The resource switch to use. - */ - private lateinit var switch: SimResourceSwitch - - /** - * The virtual machines running on this hypervisor. - */ - private val _vms = mutableSetOf() - override val vms: Set - get() = _vms - - /** - * The scaling governors attached to the physical CPUs backing this hypervisor. - */ - private val governors = mutableListOf() - - /** - * Construct the [SimResourceSwitch] implementation that performs the actual scheduling of the CPUs. - */ - public abstract fun createSwitch(ctx: SimMachineContext): SimResourceSwitch - - /** - * Check whether the specified machine model fits on this hypervisor. - */ - public abstract fun canFit(model: SimMachineModel, switch: SimResourceSwitch): Boolean - - /** - * Trigger the governors to recompute the scaling limits. - */ - protected fun triggerGovernors(load: Double) { - for (governor in governors) { - governor.onLimit(load) - } - } - - /* SimHypervisor */ - override fun canFit(model: SimMachineModel): Boolean { - return canFit(model, switch) - } - - override fun createMachine( - model: SimMachineModel, - performanceInterferenceModel: PerformanceInterferenceModel? - ): SimMachine { - require(canFit(model)) { "Machine does not fit" } - val vm = VirtualMachine(model, performanceInterferenceModel) - _vms.add(vm) - return vm - } - - /* SimWorkload */ - override fun onStart(ctx: SimMachineContext) { - context = ctx - switch = createSwitch(ctx) - - for (cpu in ctx.cpus) { - val governor = scalingGovernor?.createLogic(ScalingPolicyImpl(cpu)) - if (governor != null) { - governors.add(governor) - governor.onStart() - } - - switch.addInput(cpu) - } - } - - /** - * A virtual machine running on the hypervisor. - * - * @property model The machine model of the virtual machine. - * @property performanceInterferenceModel The performance interference model to utilize. - */ - private inner class VirtualMachine( - model: SimMachineModel, - val performanceInterferenceModel: PerformanceInterferenceModel? = null, - ) : SimAbstractMachine(interpreter, parent = null, model) { - /** - * The vCPUs of the machine. - */ - override val cpus = model.cpus.map { VCpu(switch.newOutput(), it) } - - override fun close() { - super.close() - - for (cpu in cpus) { - cpu.close() - } - - _vms.remove(this) - } - } - - /** - * A [SimProcessingUnit] of a virtual machine. - */ - private class VCpu( - private val source: SimResourceCloseableProvider, - override val model: ProcessingUnit - ) : SimProcessingUnit, SimResourceCloseableProvider by source { - override var capacity: Double - get() = source.capacity - set(_) { - // Ignore capacity changes - } - - override fun toString(): String = "SimAbstractHypervisor.VCpu[model=$model]" - } - - /** - * A [ScalingPolicy] for a physical CPU of the hypervisor. - */ - private class ScalingPolicyImpl(override val cpu: SimProcessingUnit) : ScalingPolicy { - override var target: Double - get() = cpu.capacity - set(value) { - cpu.capacity = value - } - - override val max: Double = cpu.model.frequency - - override val min: Double = 0.0 - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt index 3a70680c..ca508054 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt @@ -25,6 +25,7 @@ package org.opendc.simulator.compute import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.workload.SimWorkload import org.opendc.simulator.resources.* @@ -41,7 +42,7 @@ import kotlin.coroutines.resume public abstract class SimAbstractMachine( protected val interpreter: SimResourceInterpreter, final override val parent: SimResourceSystem?, - final override val model: SimMachineModel + final override val model: MachineModel ) : SimMachine, SimResourceSystem { /** * A [StateFlow] representing the CPU usage of the simulated machine. diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt index 7f416010..887f0885 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt @@ -22,6 +22,8 @@ package org.opendc.simulator.compute +import org.opendc.simulator.compute.device.SimPsu +import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.power.PowerDriver import org.opendc.simulator.resources.* @@ -41,7 +43,7 @@ import org.opendc.simulator.resources.SimResourceInterpreter */ public class SimBareMetalMachine( interpreter: SimResourceInterpreter, - model: SimMachineModel, + model: MachineModel, powerDriver: PowerDriver, public val psu: SimPsu = SimPsu(500.0, mapOf(1.0 to 1.0)), parent: SimResourceSystem? = null, diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt deleted file mode 100644 index e7776c81..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt +++ /dev/null @@ -1,93 +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.compute - -import org.opendc.simulator.compute.cpufreq.ScalingGovernor -import org.opendc.simulator.compute.workload.SimWorkload -import org.opendc.simulator.resources.SimResourceInterpreter -import org.opendc.simulator.resources.SimResourceSwitch -import org.opendc.simulator.resources.SimResourceSwitchMaxMin -import org.opendc.simulator.resources.SimResourceSystem - -/** - * A [SimHypervisor] that distributes the computing requirements of multiple [SimWorkload] on a single - * [SimBareMetalMachine] concurrently using weighted fair sharing. - * - * @param interpreter The interpreter to manage the machine's resources. - * @param parent The parent simulation system. - * @param scalingGovernor The CPU frequency scaling governor to use for the hypervisor. - * @param listener The hypervisor listener to use. - */ -public class SimFairShareHypervisor( - private val interpreter: SimResourceInterpreter, - private val parent: SimResourceSystem? = null, - scalingGovernor: ScalingGovernor? = null, - private val listener: SimHypervisor.Listener? = null -) : SimAbstractHypervisor(interpreter, scalingGovernor) { - - override fun canFit(model: SimMachineModel, switch: SimResourceSwitch): Boolean = true - - override fun createSwitch(ctx: SimMachineContext): SimResourceSwitch { - return SwitchSystem(ctx).switch - } - - private inner class SwitchSystem(private val ctx: SimMachineContext) : SimResourceSystem { - val switch = SimResourceSwitchMaxMin(interpreter, this) - - override val parent: SimResourceSystem? = this@SimFairShareHypervisor.parent - - private var lastCpuUsage = 0.0 - private var lastCpuDemand = 0.0 - private var lastDemand = 0.0 - private var lastActual = 0.0 - private var lastOvercommit = 0.0 - private var lastReport = Long.MIN_VALUE - - override fun onConverge(timestamp: Long) { - val listener = listener ?: return - val counters = switch.counters - - if (timestamp > lastReport) { - listener.onSliceFinish( - this@SimFairShareHypervisor, - (counters.demand - lastDemand).toLong(), - (counters.actual - lastActual).toLong(), - (counters.overcommit - lastOvercommit).toLong(), - 0L, - lastCpuUsage, - lastCpuDemand - ) - } - lastReport = timestamp - - lastCpuDemand = switch.inputs.sumOf { it.demand } - lastCpuUsage = switch.inputs.sumOf { it.speed } - lastDemand = counters.demand - lastActual = counters.actual - lastOvercommit = counters.overcommit - - val load = lastCpuDemand / ctx.cpus.sumOf { it.model.frequency } - triggerGovernors(load) - } - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt deleted file mode 100644 index 94c905b2..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt +++ /dev/null @@ -1,39 +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.compute - -import org.opendc.simulator.resources.SimResourceInterpreter -import org.opendc.simulator.resources.SimResourceSystem - -/** - * A [SimHypervisorProvider] for the [SimFairShareHypervisor] implementation. - */ -public class SimFairShareHypervisorProvider : SimHypervisorProvider { - override val id: String = "fair-share" - - override fun create( - interpreter: SimResourceInterpreter, - parent: SimResourceSystem?, - listener: SimHypervisor.Listener? - ): SimHypervisor = SimFairShareHypervisor(interpreter, parent, listener = listener) -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt deleted file mode 100644 index 4a233fec..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020 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.compute - -import org.opendc.simulator.compute.interference.PerformanceInterferenceModel -import org.opendc.simulator.compute.workload.SimWorkload - -/** - * A SimHypervisor facilitates the execution of multiple concurrent [SimWorkload]s, while acting as a single workload - * to a [SimBareMetalMachine]. - */ -public interface SimHypervisor : SimWorkload { - /** - * The machines running on the hypervisor. - */ - public val vms: Set - - /** - * Determine whether the specified machine characterized by [model] can fit on this hypervisor at this moment. - */ - public fun canFit(model: SimMachineModel): Boolean - - /** - * Create a [SimMachine] instance on which users may run a [SimWorkload]. - * - * @param model The machine to create. - * @param performanceInterferenceModel The performance interference model to use. - */ - public fun createMachine( - model: SimMachineModel, - performanceInterferenceModel: PerformanceInterferenceModel? = null - ): SimMachine - - /** - * Event listener for hypervisor events. - */ - public interface Listener { - /** - * This method is invoked when a slice is finished. - */ - public fun onSliceFinish( - hypervisor: SimHypervisor, - requestedWork: Long, - grantedWork: Long, - overcommittedWork: Long, - interferedWork: Long, - cpuUsage: Double, - cpuDemand: Double - ) - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt deleted file mode 100644 index 8e8c3698..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt +++ /dev/null @@ -1,48 +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.compute - -import org.opendc.simulator.resources.SimResourceInterpreter -import org.opendc.simulator.resources.SimResourceSystem - -/** - * A service provider interface for constructing a [SimHypervisor]. - */ -public interface SimHypervisorProvider { - /** - * A unique identifier for this hypervisor implementation. - * - * Each hypervisor must provide a unique ID, so that they can be selected by the user. - * When in doubt, you may use the fully qualified name of your custom [SimHypervisor] implementation class. - */ - public val id: String - - /** - * Create a [SimHypervisor] instance with the specified [listener]. - */ - public fun create( - interpreter: SimResourceInterpreter, - parent: SimResourceSystem? = null, - listener: SimHypervisor.Listener? = null - ): SimHypervisor -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt index bfaa60bc..4e7d191c 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt @@ -23,6 +23,7 @@ package org.opendc.simulator.compute import kotlinx.coroutines.flow.StateFlow +import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.workload.SimWorkload /** @@ -32,7 +33,7 @@ public interface SimMachine : AutoCloseable { /** * The model of the machine containing its specifications. */ - public val model: SimMachineModel + public val model: MachineModel /** * A [StateFlow] representing the CPU usage of the simulated machine. diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt deleted file mode 100644 index 2b414540..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt +++ /dev/null @@ -1,34 +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.compute - -import org.opendc.simulator.compute.model.MemoryUnit -import org.opendc.simulator.compute.model.ProcessingUnit - -/** - * A description of the physical or virtual machine on which a bootable image runs. - * - * @property cpus The list of processing units available to the image. - * @property memory The list of memory units available to the image. - */ -public data class SimMachineModel(public val cpus: List, public val memory: List) diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimPsu.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimPsu.kt deleted file mode 100644 index 4ddad1c9..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimPsu.kt +++ /dev/null @@ -1,115 +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.compute - -import org.opendc.simulator.compute.power.PowerDriver -import org.opendc.simulator.power.SimPowerInlet -import org.opendc.simulator.resources.SimResourceCommand -import org.opendc.simulator.resources.SimResourceConsumer -import org.opendc.simulator.resources.SimResourceContext -import org.opendc.simulator.resources.SimResourceEvent -import java.util.* - -/** - * A power supply of a [SimBareMetalMachine]. - * - * @param ratedOutputPower The rated output power of the PSU. - * @param energyEfficiency The energy efficiency of the PSU for various power draws. - */ -public class SimPsu( - private val ratedOutputPower: Double, - energyEfficiency: Map, -) : SimPowerInlet() { - /** - * The power draw of the machine at this instant. - */ - public val powerDraw: Double - get() = _powerDraw - private var _powerDraw = 0.0 - - /** - * The energy efficiency of the PSU at various power draws. - */ - private val energyEfficiency = TreeMap(energyEfficiency) - - /** - * The consumer context. - */ - private var _ctx: SimResourceContext? = null - - /** - * The driver that is connected to the PSU. - */ - private var _driver: PowerDriver.Logic? = null - - init { - require(energyEfficiency.isNotEmpty()) { "Must specify at least one entry for energy efficiency of PSU" } - } - - /** - * Update the power draw of the PSU. - */ - public fun update() { - _ctx?.interrupt() - } - - /** - * Connect the specified [PowerDriver.Logic] to this PSU. - */ - public fun connect(driver: PowerDriver.Logic) { - check(_driver == null) { "PSU already connected" } - _driver = driver - update() - } - - override fun createConsumer(): SimResourceConsumer = object : SimResourceConsumer { - override fun onNext(ctx: SimResourceContext): SimResourceCommand { - val powerDraw = computePowerDraw(_driver?.computePower() ?: 0.0) - - return if (powerDraw > 0.0) - SimResourceCommand.Consume(Double.POSITIVE_INFINITY, powerDraw, Long.MAX_VALUE) - else - SimResourceCommand.Idle() - } - - override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) { - when (event) { - SimResourceEvent.Start -> _ctx = ctx - SimResourceEvent.Run -> _powerDraw = ctx.speed - SimResourceEvent.Exit -> _ctx = null - else -> {} - } - } - } - - /** - * Compute the power draw of the PSU including the power loss. - */ - private fun computePowerDraw(load: Double): Double { - val loadPercentage = (load / ratedOutputPower).coerceIn(0.0, 1.0) - val efficiency = energyEfficiency.ceilingEntry(loadPercentage)?.value ?: 1.0 - return load / efficiency - } - - override fun toString(): String = "SimPsu[draw=$_powerDraw]" -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt deleted file mode 100644 index f6ae18f7..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt +++ /dev/null @@ -1,40 +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.compute - -import org.opendc.simulator.resources.SimResourceInterpreter -import org.opendc.simulator.resources.SimResourceSwitch -import org.opendc.simulator.resources.SimResourceSwitchExclusive - -/** - * A [SimHypervisor] that allocates its sub-resources exclusively for the virtual machine that it hosts. - */ -public class SimSpaceSharedHypervisor(interpreter: SimResourceInterpreter) : SimAbstractHypervisor(interpreter, null) { - override fun canFit(model: SimMachineModel, switch: SimResourceSwitch): Boolean { - return switch.inputs.size - switch.outputs.size >= model.cpus.size - } - - override fun createSwitch(ctx: SimMachineContext): SimResourceSwitch { - return SimResourceSwitchExclusive() - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt deleted file mode 100644 index 923b5bab..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt +++ /dev/null @@ -1,39 +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.compute - -import org.opendc.simulator.resources.SimResourceInterpreter -import org.opendc.simulator.resources.SimResourceSystem - -/** - * A [SimHypervisorProvider] for the [SimSpaceSharedHypervisor] implementation. - */ -public class SimSpaceSharedHypervisorProvider : SimHypervisorProvider { - override val id: String = "space-shared" - - override fun create( - interpreter: SimResourceInterpreter, - parent: SimResourceSystem?, - listener: SimHypervisor.Listener? - ): SimHypervisor = SimSpaceSharedHypervisor(interpreter) -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernor.kt deleted file mode 100644 index 562c0b73..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernor.kt +++ /dev/null @@ -1,65 +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.compute.cpufreq - -/** - * A CPUFreq [ScalingGovernor] that models the conservative scaling governor in the Linux kernel. - */ -public class ConservativeScalingGovernor(public val threshold: Double = 0.8, private val stepSize: Double = -1.0) : ScalingGovernor { - override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { - /** - * The step size to use. - */ - private val stepSize = if (this@ConservativeScalingGovernor.stepSize < 0) { - // https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L33 - policy.max * 0.05 - } else { - this@ConservativeScalingGovernor.stepSize.coerceAtMost(policy.max) - } - - /** - * The previous load of the CPU. - */ - private var previousLoad = threshold - - override fun onStart() { - policy.target = policy.min - } - - override fun onLimit(load: Double) { - val currentTarget = policy.target - if (load > threshold) { - // Check for load increase (see: https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L102) - val step = when { - load > previousLoad -> stepSize - load < previousLoad -> -stepSize - else -> 0.0 - } - policy.target = (currentTarget + step).coerceIn(policy.min, policy.max) - } - previousLoad = load - } - } - - override fun toString(): String = "ConservativeScalingGovernor[threshold=$threshold,stepSize=$stepSize]" -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernor.kt deleted file mode 100644 index 2c4a83f1..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernor.kt +++ /dev/null @@ -1,50 +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.compute.cpufreq - -/** - * A CPUFreq [ScalingGovernor] that models the on-demand scaling governor in the Linux kernel. - */ -public class OnDemandScalingGovernor(public val threshold: Double = 0.8) : ScalingGovernor { - override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { - /** - * The multiplier used for the linear frequency scaling. - */ - private val multiplier = (policy.max - policy.min) / 100 - - override fun onStart() { - policy.target = policy.min - } - - override fun onLimit(load: Double) { - policy.target = if (load < threshold) { - /* Proportional scaling (see: https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_ondemand.c#L151). */ - policy.min + load * multiplier - } else { - policy.max - } - } - } - - override fun toString(): String = "OnDemandScalingGovernor[threshold=$threshold]" -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt deleted file mode 100644 index 8b1d49f6..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt +++ /dev/null @@ -1,36 +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.compute.cpufreq - -/** - * A CPUFreq [ScalingGovernor] that causes the highest possible frequency to be requested from the resource. - */ -public class PerformanceScalingGovernor : ScalingGovernor { - override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { - override fun onStart() { - policy.target = policy.max - } - } - - override fun toString(): String = "PerformanceScalingGovernor" -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernor.kt deleted file mode 100644 index 0889980c..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernor.kt +++ /dev/null @@ -1,36 +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.compute.cpufreq - -/** - * A CPUFreq [ScalingGovernor] that causes the lowest possible frequency to be requested from the resource. - */ -public class PowerSaveScalingGovernor : ScalingGovernor { - override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { - override fun onStart() { - policy.target = policy.min - } - } - - override fun toString(): String = "PowerSaveScalingGovernor" -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt deleted file mode 100644 index 3fb93ad9..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt +++ /dev/null @@ -1,56 +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.compute.cpufreq - -/** - * A [ScalingGovernor] in the CPUFreq subsystem of OpenDC is responsible for scaling the frequency of simulated CPUs - * independent of the particular implementation of the CPU. - * - * Each of the scaling governors implements a single, possibly parametrized, performance scaling algorithm. - * - * For more information, see the documentation of the Linux CPUFreq subsystem: - * https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html - */ -public interface ScalingGovernor { - /** - * Create the scaling logic for the specified [policy] - */ - public fun createLogic(policy: ScalingPolicy): Logic - - /** - * The logic of the scaling governor. - */ - public interface Logic { - /** - * This method is invoked when the governor is started. - */ - public fun onStart() {} - - /** - * This method is invoked when the governor should re-decide the frequency limits. - * - * @param load The load of the system. - */ - public fun onLimit(load: Double) {} - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingPolicy.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingPolicy.kt deleted file mode 100644 index 0552d279..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingPolicy.kt +++ /dev/null @@ -1,51 +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.compute.cpufreq - -import org.opendc.simulator.compute.SimProcessingUnit - -/** - * An interface that holds the state managed by a [ScalingGovernor] and used by the underlying machine to control the - * CPU frequencies. - */ -public interface ScalingPolicy { - /** - * The processing unit that is associated with this policy. - */ - public val cpu: SimProcessingUnit - - /** - * The target frequency which the CPU should attempt to attain. - */ - public var target: Double - - /** - * The minimum frequency to which the CPU may scale. - */ - public val min: Double - - /** - * The maximum frequency to which the CPU may scale. - */ - public val max: Double -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt new file mode 100644 index 00000000..0a7dc40f --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt @@ -0,0 +1,115 @@ +/* + * 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.compute.device + +import org.opendc.simulator.compute.power.PowerDriver +import org.opendc.simulator.power.SimPowerInlet +import org.opendc.simulator.resources.SimResourceCommand +import org.opendc.simulator.resources.SimResourceConsumer +import org.opendc.simulator.resources.SimResourceContext +import org.opendc.simulator.resources.SimResourceEvent +import java.util.* + +/** + * A power supply of a [SimBareMetalMachine]. + * + * @param ratedOutputPower The rated output power of the PSU. + * @param energyEfficiency The energy efficiency of the PSU for various power draws. + */ +public class SimPsu( + private val ratedOutputPower: Double, + energyEfficiency: Map, +) : SimPowerInlet() { + /** + * The power draw of the machine at this instant. + */ + public val powerDraw: Double + get() = _powerDraw + private var _powerDraw = 0.0 + + /** + * The energy efficiency of the PSU at various power draws. + */ + private val energyEfficiency = TreeMap(energyEfficiency) + + /** + * The consumer context. + */ + private var _ctx: SimResourceContext? = null + + /** + * The driver that is connected to the PSU. + */ + private var _driver: PowerDriver.Logic? = null + + init { + require(energyEfficiency.isNotEmpty()) { "Must specify at least one entry for energy efficiency of PSU" } + } + + /** + * Update the power draw of the PSU. + */ + public fun update() { + _ctx?.interrupt() + } + + /** + * Connect the specified [PowerDriver.Logic] to this PSU. + */ + public fun connect(driver: PowerDriver.Logic) { + check(_driver == null) { "PSU already connected" } + _driver = driver + update() + } + + override fun createConsumer(): SimResourceConsumer = object : SimResourceConsumer { + override fun onNext(ctx: SimResourceContext): SimResourceCommand { + val powerDraw = computePowerDraw(_driver?.computePower() ?: 0.0) + + return if (powerDraw > 0.0) + SimResourceCommand.Consume(Double.POSITIVE_INFINITY, powerDraw, Long.MAX_VALUE) + else + SimResourceCommand.Idle() + } + + override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) { + when (event) { + SimResourceEvent.Start -> _ctx = ctx + SimResourceEvent.Run -> _powerDraw = ctx.speed + SimResourceEvent.Exit -> _ctx = null + else -> {} + } + } + } + + /** + * Compute the power draw of the PSU including the power loss. + */ + private fun computePowerDraw(load: Double): Double { + val loadPercentage = (load / ratedOutputPower).coerceIn(0.0, 1.0) + val efficiency = energyEfficiency.ceilingEntry(loadPercentage)?.value ?: 1.0 + return load / efficiency + } + + override fun toString(): String = "SimPsu[draw=$_powerDraw]" +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt new file mode 100644 index 00000000..fb46dab4 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt @@ -0,0 +1,172 @@ +/* + * 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.compute.kernel + +import org.opendc.simulator.compute.* +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel +import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor +import org.opendc.simulator.compute.kernel.cpufreq.ScalingPolicy +import org.opendc.simulator.compute.model.MachineModel +import org.opendc.simulator.compute.model.ProcessingUnit +import org.opendc.simulator.resources.* +import org.opendc.simulator.resources.SimResourceSwitch + +/** + * Abstract implementation of the [SimHypervisor] interface. + * + * @param interpreter The resource interpreter to use. + * @param scalingGovernor The scaling governor to use for scaling the CPU frequency of the underlying hardware. + */ +public abstract class SimAbstractHypervisor( + private val interpreter: SimResourceInterpreter, + private val scalingGovernor: ScalingGovernor? +) : SimHypervisor { + /** + * The machine on which the hypervisor runs. + */ + private lateinit var context: SimMachineContext + + /** + * The resource switch to use. + */ + private lateinit var switch: SimResourceSwitch + + /** + * The virtual machines running on this hypervisor. + */ + private val _vms = mutableSetOf() + override val vms: Set + get() = _vms + + /** + * The scaling governors attached to the physical CPUs backing this hypervisor. + */ + private val governors = mutableListOf() + + /** + * Construct the [SimResourceSwitch] implementation that performs the actual scheduling of the CPUs. + */ + public abstract fun createSwitch(ctx: SimMachineContext): SimResourceSwitch + + /** + * Check whether the specified machine model fits on this hypervisor. + */ + public abstract fun canFit(model: MachineModel, switch: SimResourceSwitch): Boolean + + /** + * Trigger the governors to recompute the scaling limits. + */ + protected fun triggerGovernors(load: Double) { + for (governor in governors) { + governor.onLimit(load) + } + } + + /* SimHypervisor */ + override fun canFit(model: MachineModel): Boolean { + return canFit(model, switch) + } + + override fun createMachine( + model: MachineModel, + performanceInterferenceModel: PerformanceInterferenceModel? + ): SimMachine { + require(canFit(model)) { "Machine does not fit" } + val vm = VirtualMachine(model, performanceInterferenceModel) + _vms.add(vm) + return vm + } + + /* SimWorkload */ + override fun onStart(ctx: SimMachineContext) { + context = ctx + switch = createSwitch(ctx) + + for (cpu in ctx.cpus) { + val governor = scalingGovernor?.createLogic(ScalingPolicyImpl(cpu)) + if (governor != null) { + governors.add(governor) + governor.onStart() + } + + switch.addInput(cpu) + } + } + + /** + * A virtual machine running on the hypervisor. + * + * @property model The machine model of the virtual machine. + * @property performanceInterferenceModel The performance interference model to utilize. + */ + private inner class VirtualMachine( + model: MachineModel, + val performanceInterferenceModel: PerformanceInterferenceModel? = null, + ) : SimAbstractMachine(interpreter, parent = null, model) { + /** + * The vCPUs of the machine. + */ + override val cpus = model.cpus.map { VCpu(switch.newOutput(), it) } + + override fun close() { + super.close() + + for (cpu in cpus) { + cpu.close() + } + + _vms.remove(this) + } + } + + /** + * A [SimProcessingUnit] of a virtual machine. + */ + private class VCpu( + private val source: SimResourceCloseableProvider, + override val model: ProcessingUnit + ) : SimProcessingUnit, SimResourceCloseableProvider by source { + override var capacity: Double + get() = source.capacity + set(_) { + // Ignore capacity changes + } + + override fun toString(): String = "SimAbstractHypervisor.VCpu[model=$model]" + } + + /** + * A [ScalingPolicy] for a physical CPU of the hypervisor. + */ + private class ScalingPolicyImpl(override val cpu: SimProcessingUnit) : ScalingPolicy { + override var target: Double + get() = cpu.capacity + set(value) { + cpu.capacity = value + } + + override val max: Double = cpu.model.frequency + + override val min: Double = 0.0 + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt new file mode 100644 index 00000000..2ce51ea6 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt @@ -0,0 +1,95 @@ +/* + * 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.compute.kernel + +import org.opendc.simulator.compute.SimMachineContext +import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor +import org.opendc.simulator.compute.model.MachineModel +import org.opendc.simulator.compute.workload.SimWorkload +import org.opendc.simulator.resources.SimResourceInterpreter +import org.opendc.simulator.resources.SimResourceSwitch +import org.opendc.simulator.resources.SimResourceSwitchMaxMin +import org.opendc.simulator.resources.SimResourceSystem + +/** + * A [SimHypervisor] that distributes the computing requirements of multiple [SimWorkload] on a single + * [SimBareMetalMachine] concurrently using weighted fair sharing. + * + * @param interpreter The interpreter to manage the machine's resources. + * @param parent The parent simulation system. + * @param scalingGovernor The CPU frequency scaling governor to use for the hypervisor. + * @param listener The hypervisor listener to use. + */ +public class SimFairShareHypervisor( + private val interpreter: SimResourceInterpreter, + private val parent: SimResourceSystem? = null, + scalingGovernor: ScalingGovernor? = null, + private val listener: SimHypervisor.Listener? = null +) : SimAbstractHypervisor(interpreter, scalingGovernor) { + + override fun canFit(model: MachineModel, switch: SimResourceSwitch): Boolean = true + + override fun createSwitch(ctx: SimMachineContext): SimResourceSwitch { + return SwitchSystem(ctx).switch + } + + private inner class SwitchSystem(private val ctx: SimMachineContext) : SimResourceSystem { + val switch = SimResourceSwitchMaxMin(interpreter, this) + + override val parent: SimResourceSystem? = this@SimFairShareHypervisor.parent + + private var lastCpuUsage = 0.0 + private var lastCpuDemand = 0.0 + private var lastDemand = 0.0 + private var lastActual = 0.0 + private var lastOvercommit = 0.0 + private var lastReport = Long.MIN_VALUE + + override fun onConverge(timestamp: Long) { + val listener = listener ?: return + val counters = switch.counters + + if (timestamp > lastReport) { + listener.onSliceFinish( + this@SimFairShareHypervisor, + (counters.demand - lastDemand).toLong(), + (counters.actual - lastActual).toLong(), + (counters.overcommit - lastOvercommit).toLong(), + 0L, + lastCpuUsage, + lastCpuDemand + ) + } + lastReport = timestamp + + lastCpuDemand = switch.inputs.sumOf { it.demand } + lastCpuUsage = switch.inputs.sumOf { it.speed } + lastDemand = counters.demand + lastActual = counters.actual + lastOvercommit = counters.overcommit + + val load = lastCpuDemand / ctx.cpus.sumOf { it.model.frequency } + triggerGovernors(load) + } + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt new file mode 100644 index 00000000..542cd0d2 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt @@ -0,0 +1,39 @@ +/* + * 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.compute.kernel + +import org.opendc.simulator.resources.SimResourceInterpreter +import org.opendc.simulator.resources.SimResourceSystem + +/** + * A [SimHypervisorProvider] for the [SimFairShareHypervisor] implementation. + */ +public class SimFairShareHypervisorProvider : SimHypervisorProvider { + override val id: String = "fair-share" + + override fun create( + interpreter: SimResourceInterpreter, + parent: SimResourceSystem?, + listener: SimHypervisor.Listener? + ): SimHypervisor = SimFairShareHypervisor(interpreter, parent, listener = listener) +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt new file mode 100644 index 00000000..40402f5c --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt @@ -0,0 +1,73 @@ +/* + * 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.compute.kernel + +import org.opendc.simulator.compute.SimMachine +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel +import org.opendc.simulator.compute.model.MachineModel +import org.opendc.simulator.compute.workload.SimWorkload + +/** + * A SimHypervisor facilitates the execution of multiple concurrent [SimWorkload]s, while acting as a single workload + * to a [SimBareMetalMachine]. + */ +public interface SimHypervisor : SimWorkload { + /** + * The machines running on the hypervisor. + */ + public val vms: Set + + /** + * Determine whether the specified machine characterized by [model] can fit on this hypervisor at this moment. + */ + public fun canFit(model: MachineModel): Boolean + + /** + * Create a [SimMachine] instance on which users may run a [SimWorkload]. + * + * @param model The machine to create. + * @param performanceInterferenceModel The performance interference model to use. + */ + public fun createMachine( + model: MachineModel, + performanceInterferenceModel: PerformanceInterferenceModel? = null + ): SimMachine + + /** + * Event listener for hypervisor events. + */ + public interface Listener { + /** + * This method is invoked when a slice is finished. + */ + public fun onSliceFinish( + hypervisor: SimHypervisor, + requestedWork: Long, + grantedWork: Long, + overcommittedWork: Long, + interferedWork: Long, + cpuUsage: Double, + cpuDemand: Double + ) + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt new file mode 100644 index 00000000..cafd1ffc --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt @@ -0,0 +1,48 @@ +/* + * 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.compute.kernel + +import org.opendc.simulator.resources.SimResourceInterpreter +import org.opendc.simulator.resources.SimResourceSystem + +/** + * A service provider interface for constructing a [SimHypervisor]. + */ +public interface SimHypervisorProvider { + /** + * A unique identifier for this hypervisor implementation. + * + * Each hypervisor must provide a unique ID, so that they can be selected by the user. + * When in doubt, you may use the fully qualified name of your custom [SimHypervisor] implementation class. + */ + public val id: String + + /** + * Create a [SimHypervisor] instance with the specified [listener]. + */ + public fun create( + interpreter: SimResourceInterpreter, + parent: SimResourceSystem? = null, + listener: SimHypervisor.Listener? = null + ): SimHypervisor +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisor.kt new file mode 100644 index 00000000..3ceebb9a --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisor.kt @@ -0,0 +1,42 @@ +/* + * 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.compute.kernel + +import org.opendc.simulator.compute.SimMachineContext +import org.opendc.simulator.compute.model.MachineModel +import org.opendc.simulator.resources.SimResourceInterpreter +import org.opendc.simulator.resources.SimResourceSwitch +import org.opendc.simulator.resources.SimResourceSwitchExclusive + +/** + * A [SimHypervisor] that allocates its sub-resources exclusively for the virtual machine that it hosts. + */ +public class SimSpaceSharedHypervisor(interpreter: SimResourceInterpreter) : SimAbstractHypervisor(interpreter, null) { + override fun canFit(model: MachineModel, switch: SimResourceSwitch): Boolean { + return switch.inputs.size - switch.outputs.size >= model.cpus.size + } + + override fun createSwitch(ctx: SimMachineContext): SimResourceSwitch { + return SimResourceSwitchExclusive() + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt new file mode 100644 index 00000000..fb47d9e5 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt @@ -0,0 +1,39 @@ +/* + * 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.compute.kernel + +import org.opendc.simulator.resources.SimResourceInterpreter +import org.opendc.simulator.resources.SimResourceSystem + +/** + * A [SimHypervisorProvider] for the [SimSpaceSharedHypervisor] implementation. + */ +public class SimSpaceSharedHypervisorProvider : SimHypervisorProvider { + override val id: String = "space-shared" + + override fun create( + interpreter: SimResourceInterpreter, + parent: SimResourceSystem?, + listener: SimHypervisor.Listener? + ): SimHypervisor = SimSpaceSharedHypervisor(interpreter) +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.kt new file mode 100644 index 00000000..1a03221d --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.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.compute.kernel.cpufreq + +/** + * A CPUFreq [ScalingGovernor] that models the conservative scaling governor in the Linux kernel. + */ +public class ConservativeScalingGovernor(public val threshold: Double = 0.8, private val stepSize: Double = -1.0) : + ScalingGovernor { + override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { + /** + * The step size to use. + */ + private val stepSize = if (this@ConservativeScalingGovernor.stepSize < 0) { + // https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L33 + policy.max * 0.05 + } else { + this@ConservativeScalingGovernor.stepSize.coerceAtMost(policy.max) + } + + /** + * The previous load of the CPU. + */ + private var previousLoad = threshold + + override fun onStart() { + policy.target = policy.min + } + + override fun onLimit(load: Double) { + val currentTarget = policy.target + if (load > threshold) { + // Check for load increase (see: https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L102) + val step = when { + load > previousLoad -> stepSize + load < previousLoad -> -stepSize + else -> 0.0 + } + policy.target = (currentTarget + step).coerceIn(policy.min, policy.max) + } + previousLoad = load + } + } + + override fun toString(): String = "ConservativeScalingGovernor[threshold=$threshold,stepSize=$stepSize]" +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt new file mode 100644 index 00000000..aef15ce9 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt @@ -0,0 +1,50 @@ +/* + * 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.compute.kernel.cpufreq + +/** + * A CPUFreq [ScalingGovernor] that models the on-demand scaling governor in the Linux kernel. + */ +public class OnDemandScalingGovernor(public val threshold: Double = 0.8) : ScalingGovernor { + override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { + /** + * The multiplier used for the linear frequency scaling. + */ + private val multiplier = (policy.max - policy.min) / 100 + + override fun onStart() { + policy.target = policy.min + } + + override fun onLimit(load: Double) { + policy.target = if (load < threshold) { + /* Proportional scaling (see: https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_ondemand.c#L151). */ + policy.min + load * multiplier + } else { + policy.max + } + } + } + + override fun toString(): String = "OnDemandScalingGovernor[threshold=$threshold]" +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt new file mode 100644 index 00000000..13109a9a --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt @@ -0,0 +1,36 @@ +/* + * 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.compute.kernel.cpufreq + +/** + * A CPUFreq [ScalingGovernor] that causes the highest possible frequency to be requested from the resource. + */ +public class PerformanceScalingGovernor : ScalingGovernor { + override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { + override fun onStart() { + policy.target = policy.max + } + } + + override fun toString(): String = "PerformanceScalingGovernor" +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt new file mode 100644 index 00000000..32c0703a --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt @@ -0,0 +1,36 @@ +/* + * 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.compute.kernel.cpufreq + +/** + * A CPUFreq [ScalingGovernor] that causes the lowest possible frequency to be requested from the resource. + */ +public class PowerSaveScalingGovernor : ScalingGovernor { + override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic { + override fun onStart() { + policy.target = policy.min + } + } + + override fun toString(): String = "PowerSaveScalingGovernor" +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.kt new file mode 100644 index 00000000..d33827db --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.kt @@ -0,0 +1,56 @@ +/* + * 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.compute.kernel.cpufreq + +/** + * A [ScalingGovernor] in the CPUFreq subsystem of OpenDC is responsible for scaling the frequency of simulated CPUs + * independent of the particular implementation of the CPU. + * + * Each of the scaling governors implements a single, possibly parametrized, performance scaling algorithm. + * + * For more information, see the documentation of the Linux CPUFreq subsystem: + * https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html + */ +public interface ScalingGovernor { + /** + * Create the scaling logic for the specified [policy] + */ + public fun createLogic(policy: ScalingPolicy): Logic + + /** + * The logic of the scaling governor. + */ + public interface Logic { + /** + * This method is invoked when the governor is started. + */ + public fun onStart() {} + + /** + * This method is invoked when the governor should re-decide the frequency limits. + * + * @param load The load of the system. + */ + public fun onLimit(load: Double) {} + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.kt new file mode 100644 index 00000000..f9351896 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.kt @@ -0,0 +1,51 @@ +/* + * 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.compute.kernel.cpufreq + +import org.opendc.simulator.compute.SimProcessingUnit + +/** + * An interface that holds the state managed by a [ScalingGovernor] and used by the underlying machine to control the + * CPU frequencies. + */ +public interface ScalingPolicy { + /** + * The processing unit that is associated with this policy. + */ + public val cpu: SimProcessingUnit + + /** + * The target frequency which the CPU should attempt to attain. + */ + public var target: Double + + /** + * The minimum frequency to which the CPU may scale. + */ + public val min: Double + + /** + * The maximum frequency to which the CPU may scale. + */ + public val max: Double +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt new file mode 100644 index 00000000..4b6fd7bb --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt @@ -0,0 +1,31 @@ +/* + * 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.compute.model + +/** + * A description of the physical or virtual machine on which a bootable image runs. + * + * @property cpus The list of processing units available to the image. + * @property memory The list of memory units available to the image. + */ +public data class MachineModel(public val cpus: List, public val memory: List) diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/util/SimWorkloadLifecycle.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/util/SimWorkloadLifecycle.kt deleted file mode 100644 index 43662d93..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/util/SimWorkloadLifecycle.kt +++ /dev/null @@ -1,76 +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.compute.util - -import org.opendc.simulator.compute.SimMachineContext -import org.opendc.simulator.compute.workload.SimWorkload -import org.opendc.simulator.resources.SimResourceConsumer -import org.opendc.simulator.resources.SimResourceContext -import org.opendc.simulator.resources.SimResourceEvent - -/** - * A helper class to manage the lifecycle of a [SimWorkload] - */ -public class SimWorkloadLifecycle(private val ctx: SimMachineContext) { - /** - * The resource consumers which represent the lifecycle of the workload. - */ - private val waiting = mutableSetOf() - - /** - * Wait for the specified [consumer] to complete before ending the lifecycle of the workload. - */ - public fun waitFor(consumer: SimResourceConsumer): SimResourceConsumer { - waiting.add(consumer) - return object : SimResourceConsumer by consumer { - override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) { - try { - consumer.onEvent(ctx, event) - } finally { - if (event == SimResourceEvent.Exit) { - complete(consumer) - } - } - } - - override fun onFailure(ctx: SimResourceContext, cause: Throwable) { - try { - consumer.onFailure(ctx, cause) - } finally { - complete(consumer) - } - } - - override fun toString(): String = "SimWorkloadLifecycle.Consumer[delegate=$consumer]" - } - } - - /** - * Complete the specified [SimResourceConsumer]. - */ - private fun complete(consumer: SimResourceConsumer) { - if (waiting.remove(consumer) && waiting.isEmpty()) { - ctx.close() - } - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt index de6832ca..a01fa20c 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt @@ -23,7 +23,6 @@ package org.opendc.simulator.compute.workload import org.opendc.simulator.compute.SimMachineContext -import org.opendc.simulator.compute.util.SimWorkloadLifecycle import org.opendc.simulator.resources.consumer.SimWorkConsumer /** diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt index 318a6b49..4ee56689 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt @@ -23,7 +23,6 @@ package org.opendc.simulator.compute.workload import org.opendc.simulator.compute.SimMachineContext -import org.opendc.simulator.compute.util.SimWorkloadLifecycle import org.opendc.simulator.resources.consumer.SimWorkConsumer /** diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt index 6929f4d2..622bcd4d 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt @@ -24,7 +24,6 @@ package org.opendc.simulator.compute.workload import org.opendc.simulator.compute.SimMachineContext import org.opendc.simulator.compute.model.ProcessingUnit -import org.opendc.simulator.compute.util.SimWorkloadLifecycle import org.opendc.simulator.resources.SimResourceCommand import org.opendc.simulator.resources.SimResourceConsumer import org.opendc.simulator.resources.SimResourceContext diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt new file mode 100644 index 00000000..5dd18271 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt @@ -0,0 +1,75 @@ +/* + * 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.compute.workload + +import org.opendc.simulator.compute.SimMachineContext +import org.opendc.simulator.resources.SimResourceConsumer +import org.opendc.simulator.resources.SimResourceContext +import org.opendc.simulator.resources.SimResourceEvent + +/** + * A helper class to manage the lifecycle of a [SimWorkload] + */ +public class SimWorkloadLifecycle(private val ctx: SimMachineContext) { + /** + * The resource consumers which represent the lifecycle of the workload. + */ + private val waiting = mutableSetOf() + + /** + * Wait for the specified [consumer] to complete before ending the lifecycle of the workload. + */ + public fun waitFor(consumer: SimResourceConsumer): SimResourceConsumer { + waiting.add(consumer) + return object : SimResourceConsumer by consumer { + override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) { + try { + consumer.onEvent(ctx, event) + } finally { + if (event == SimResourceEvent.Exit) { + complete(consumer) + } + } + } + + override fun onFailure(ctx: SimResourceContext, cause: Throwable) { + try { + consumer.onFailure(ctx, cause) + } finally { + complete(consumer) + } + } + + override fun toString(): String = "SimWorkloadLifecycle.Consumer[delegate=$consumer]" + } + } + + /** + * Complete the specified [SimResourceConsumer]. + */ + private fun complete(consumer: SimResourceConsumer) { + if (waiting.remove(consumer) && waiting.isEmpty()) { + ctx.close() + } + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt deleted file mode 100644 index b15692ec..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2020 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.compute - -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.launch -import kotlinx.coroutines.yield -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertAll -import org.junit.jupiter.api.assertDoesNotThrow -import org.opendc.simulator.compute.cpufreq.PerformanceScalingGovernor -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.ConstantPowerModel -import org.opendc.simulator.compute.power.SimplePowerDriver -import org.opendc.simulator.compute.workload.SimTraceWorkload -import org.opendc.simulator.core.runBlockingSimulation -import org.opendc.simulator.resources.SimResourceInterpreter - -/** - * Test suite for the [SimHypervisor] class. - */ -@OptIn(ExperimentalCoroutinesApi::class) -internal class SimHypervisorTest { - private lateinit var model: SimMachineModel - - @BeforeEach - fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) - model = SimMachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } - ) - } - - /** - * Test overcommitting of resources via the hypervisor with a single VM. - */ - @Test - fun testOvercommittedSingle() = runBlockingSimulation { - val listener = object : SimHypervisor.Listener { - var totalRequestedWork = 0L - var totalGrantedWork = 0L - var totalOvercommittedWork = 0L - - override fun onSliceFinish( - hypervisor: SimHypervisor, - requestedWork: Long, - grantedWork: Long, - overcommittedWork: Long, - interferedWork: Long, - cpuUsage: Double, - cpuDemand: Double - ) { - totalRequestedWork += requestedWork - totalGrantedWork += grantedWork - totalOvercommittedWork += overcommittedWork - } - } - - val duration = 5 * 60L - val workloadA = - SimTraceWorkload( - sequenceOf( - SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 3500.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 183.0, 1) - ), - ) - - val platform = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine(platform, model, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimFairShareHypervisor(platform, scalingGovernor = PerformanceScalingGovernor(), listener = listener) - - launch { - machine.run(hypervisor) - println("Hypervisor finished") - } - yield() - val vm = hypervisor.createMachine(model) - val res = mutableListOf() - val job = launch { machine.usage.toList(res) } - - vm.run(workloadA) - yield() - job.cancel() - machine.close() - - assertAll( - { assertEquals(1113300, listener.totalRequestedWork, "Requested Burst does not match") }, - { assertEquals(1023300, listener.totalGrantedWork, "Granted Burst does not match") }, - { assertEquals(90000, listener.totalOvercommittedWork, "Overcommissioned Burst does not match") }, - { assertEquals(listOf(0.0, 0.00875, 1.0, 0.0, 0.0571875, 0.0), res) { "VM usage is correct" } }, - { assertEquals(1200000, clock.millis()) { "Current time is correct" } } - ) - } - - /** - * Test overcommitting of resources via the hypervisor with two VMs. - */ - @Test - fun testOvercommittedDual() = runBlockingSimulation { - val listener = object : SimHypervisor.Listener { - var totalRequestedWork = 0L - var totalGrantedWork = 0L - var totalOvercommittedWork = 0L - - override fun onSliceFinish( - hypervisor: SimHypervisor, - requestedWork: Long, - grantedWork: Long, - overcommittedWork: Long, - interferedWork: Long, - cpuUsage: Double, - cpuDemand: Double - ) { - totalRequestedWork += requestedWork - totalGrantedWork += grantedWork - totalOvercommittedWork += overcommittedWork - } - } - - val duration = 5 * 60L - val workloadA = - SimTraceWorkload( - sequenceOf( - SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 3500.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 183.0, 1) - ), - ) - val workloadB = - SimTraceWorkload( - sequenceOf( - SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 3100.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 73.0, 1) - ) - ) - - val platform = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimFairShareHypervisor(platform, listener = listener) - - launch { - machine.run(hypervisor) - } - - yield() - coroutineScope { - launch { - val vm = hypervisor.createMachine(model) - vm.run(workloadA) - vm.close() - } - val vm = hypervisor.createMachine(model) - vm.run(workloadB) - vm.close() - } - yield() - machine.close() - yield() - - assertAll( - { assertEquals(2073600, listener.totalRequestedWork, "Requested Burst does not match") }, - { assertEquals(1053600, listener.totalGrantedWork, "Granted Burst does not match") }, - { assertEquals(1020000, listener.totalOvercommittedWork, "Overcommissioned Burst does not match") }, - { assertEquals(1200000, clock.millis()) } - ) - } - - @Test - fun testMultipleCPUs() = runBlockingSimulation { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - val model = SimMachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } - ) - - val platform = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimFairShareHypervisor(platform) - - assertDoesNotThrow { - launch { - machine.run(hypervisor) - } - } - - machine.close() - } -} 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 b9cfb06b..dcf509e2 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 @@ -30,15 +30,16 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows +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.compute.power.ConstantPowerModel import org.opendc.simulator.compute.power.LinearPowerModel import org.opendc.simulator.compute.power.SimplePowerDriver -import org.opendc.simulator.compute.util.SimWorkloadLifecycle 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.power.SimPowerSource import org.opendc.simulator.resources.SimResourceInterpreter @@ -49,13 +50,13 @@ import org.opendc.simulator.resources.consumer.SimWorkConsumer */ @OptIn(ExperimentalCoroutinesApi::class) class SimMachineTest { - private lateinit var machineModel: SimMachineModel + private lateinit var machineModel: MachineModel @BeforeEach fun setUp() { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = SimMachineModel( + machineModel = MachineModel( cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) @@ -82,7 +83,7 @@ class SimMachineTest { @Test fun testDualSocketMachine() = runBlockingSimulation { val cpuNode = machineModel.cpus[0].node - val machineModel = SimMachineModel( + val machineModel = MachineModel( cpus = List(cpuNode.coreCount * 2) { ProcessingUnit(cpuNode, it % 2, 1000.0) }, memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimPsuTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimPsuTest.kt deleted file mode 100644 index e0ebdb73..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimPsuTest.kt +++ /dev/null @@ -1,102 +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.compute - -import io.mockk.every -import io.mockk.mockk -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.power.SimPowerSource -import org.opendc.simulator.resources.SimResourceInterpreter - -/** - * Test suite for [SimPsu] - */ -internal class SimPsuTest { - - @Test - fun testInvalidInput() { - assertThrows { SimPsu(1.0, emptyMap()) } - } - - @Test - fun testDoubleConnect() { - val psu = SimPsu(1.0, mapOf(0.0 to 1.0)) - val cpuLogic = mockk() - psu.connect(cpuLogic) - assertThrows { psu.connect(mockk()) } - } - - @Test - fun testPsuIdle() = runBlockingSimulation { - val ratedOutputPower = 240.0 - val energyEfficiency = mapOf(0.0 to 1.0) - - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val source = SimPowerSource(interpreter, capacity = ratedOutputPower) - - val cpuLogic = mockk() - every { cpuLogic.computePower() } returns 0.0 - - val psu = SimPsu(ratedOutputPower, energyEfficiency) - psu.connect(cpuLogic) - source.connect(psu) - - assertEquals(0.0, source.powerDraw, 0.01) - } - - @Test - fun testPsuPowerLoss() = runBlockingSimulation { - val ratedOutputPower = 240.0 - // Efficiency of 80 Plus Titanium PSU - val energyEfficiency = sortedMapOf( - 0.3 to 0.9, - 0.7 to 0.92, - 1.0 to 0.94, - ) - - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val source = SimPowerSource(interpreter, capacity = ratedOutputPower) - - val cpuLogic = mockk() - every { cpuLogic.computePower() } returnsMany listOf(50.0, 100.0, 150.0, 200.0) - - val psu = SimPsu(ratedOutputPower, energyEfficiency) - psu.connect(cpuLogic) - source.connect(psu) - - assertEquals(55.55, source.powerDraw, 0.01) - - psu.update() - assertEquals(108.695, source.powerDraw, 0.01) - - psu.update() - assertEquals(163.043, source.powerDraw, 0.01) - - psu.update() - assertEquals(212.765, source.powerDraw, 0.01) - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorTest.kt deleted file mode 100644 index dba3e9a1..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorTest.kt +++ /dev/null @@ -1,227 +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.compute - -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.launch -import kotlinx.coroutines.yield -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -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.ConstantPowerModel -import org.opendc.simulator.compute.power.SimplePowerDriver -import org.opendc.simulator.compute.workload.SimFlopsWorkload -import org.opendc.simulator.compute.workload.SimRuntimeWorkload -import org.opendc.simulator.compute.workload.SimTraceWorkload -import org.opendc.simulator.core.runBlockingSimulation -import org.opendc.simulator.resources.SimResourceInterpreter - -/** - * A test suite for the [SimSpaceSharedHypervisor]. - */ -@OptIn(ExperimentalCoroutinesApi::class) -internal class SimSpaceSharedHypervisorTest { - private lateinit var machineModel: SimMachineModel - - @BeforeEach - fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) - machineModel = SimMachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } - ) - } - - /** - * Test a trace workload. - */ - @Test - fun testTrace() = runBlockingSimulation { - val usagePm = mutableListOf() - val usageVm = mutableListOf() - - val duration = 5 * 60L - val workloadA = - SimTraceWorkload( - sequenceOf( - SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 3500.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), - SimTraceWorkload.Fragment(duration * 1000, 183.0, 1) - ), - ) - - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - SimResourceInterpreter(coroutineContext, clock), machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimSpaceSharedHypervisor(interpreter) - - val colA = launch { machine.usage.toList(usagePm) } - launch { machine.run(hypervisor) } - - yield() - - val vm = hypervisor.createMachine(machineModel) - val colB = launch { vm.usage.toList(usageVm) } - vm.run(workloadA) - yield() - - vm.close() - machine.close() - colA.cancel() - colB.cancel() - - assertAll( - { assertEquals(listOf(0.0, 0.00875, 1.0, 0.0, 0.0571875, 0.0), usagePm) { "Correct PM usage" } }, - // Temporary limitation is that VMs do not emit usage information - // { assertEquals(listOf(0.0, 0.00875, 1.0, 0.0, 0.0571875, 0.0), usageVm) { "Correct VM usage" } }, - { assertEquals(5 * 60L * 4000, clock.millis()) { "Took enough time" } } - ) - } - - /** - * Test runtime workload on hypervisor. - */ - @Test - fun testRuntimeWorkload() = runBlockingSimulation { - val duration = 5 * 60L * 1000 - val workload = SimRuntimeWorkload(duration) - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimSpaceSharedHypervisor(interpreter) - - launch { machine.run(hypervisor) } - yield() - val vm = hypervisor.createMachine(machineModel) - vm.run(workload) - vm.close() - machine.close() - - assertEquals(duration, clock.millis()) { "Took enough time" } - } - - /** - * Test FLOPs workload on hypervisor. - */ - @Test - fun testFlopsWorkload() = runBlockingSimulation { - val duration = 5 * 60L * 1000 - val workload = SimFlopsWorkload((duration * 3.2).toLong(), 1.0) - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimSpaceSharedHypervisor(interpreter) - - launch { machine.run(hypervisor) } - yield() - val vm = hypervisor.createMachine(machineModel) - vm.run(workload) - machine.close() - - assertEquals(duration, clock.millis()) { "Took enough time" } - } - - /** - * Test two workloads running sequentially. - */ - @Test - fun testTwoWorkloads() = runBlockingSimulation { - val duration = 5 * 60L * 1000 - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimSpaceSharedHypervisor(interpreter) - - launch { machine.run(hypervisor) } - yield() - - val vm = hypervisor.createMachine(machineModel) - vm.run(SimRuntimeWorkload(duration)) - vm.close() - - val vm2 = hypervisor.createMachine(machineModel) - vm2.run(SimRuntimeWorkload(duration)) - vm2.close() - machine.close() - - assertEquals(duration * 2, clock.millis()) { "Took enough time" } - } - - /** - * Test concurrent workloads on the machine. - */ - @Test - fun testConcurrentWorkloadFails() = runBlockingSimulation { - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimSpaceSharedHypervisor(interpreter) - - launch { machine.run(hypervisor) } - yield() - - hypervisor.createMachine(machineModel) - - assertAll( - { assertFalse(hypervisor.canFit(machineModel)) }, - { assertThrows { hypervisor.createMachine(machineModel) } } - ) - - machine.close() - } - - /** - * Test concurrent workloads on the machine. - */ - @Test - fun testConcurrentWorkloadSucceeds() = runBlockingSimulation { - val interpreter = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine( - interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) - ) - val hypervisor = SimSpaceSharedHypervisor(interpreter) - - launch { machine.run(hypervisor) } - yield() - - hypervisor.createMachine(machineModel).close() - - assertAll( - { assertTrue(hypervisor.canFit(machineModel)) }, - { assertDoesNotThrow { hypervisor.createMachine(machineModel) } } - ) - - machine.close() - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernorTest.kt deleted file mode 100644 index 59817f1d..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/ConservativeScalingGovernorTest.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.compute.cpufreq - -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -/** - * Test suite for the [ConservativeScalingGovernor] - */ -internal class ConservativeScalingGovernorTest { - @Test - fun testSetStartLimitWithoutPStates() { - val cpuCapacity = 4100.0 - val minSpeed = cpuCapacity / 2 - val defaultThreshold = 0.8 - val defaultStepSize = 0.05 * cpuCapacity - val governor = ConservativeScalingGovernor() - - val policy = mockk(relaxUnitFun = true) - every { policy.max } returns cpuCapacity - every { policy.min } returns minSpeed - - var target = 0.0 - every { policy.target } answers { target } - every { policy.target = any() } propertyType Double::class answers { target = value } - - val logic = governor.createLogic(policy) - logic.onStart() - assertEquals(defaultThreshold, governor.threshold) - - logic.onLimit(0.5) - - /* Upwards scaling */ - logic.onLimit(defaultThreshold + 0.2) - - /* Downwards scaling */ - logic.onLimit(defaultThreshold + 0.1) - - verify(exactly = 2) { policy.target = minSpeed } - verify(exactly = 1) { policy.target = minSpeed + defaultStepSize } - } - - @Test - fun testSetStartLimitWithPStatesAndParams() { - val firstPState = 1000.0 - val cpuCapacity = 4100.0 - val minSpeed = firstPState - val threshold = 0.5 - val stepSize = 0.02 * cpuCapacity - val governor = ConservativeScalingGovernor(threshold, stepSize) - - val policy = mockk(relaxUnitFun = true) - every { policy.max } returns cpuCapacity - every { policy.min } returns firstPState - - var target = 0.0 - every { policy.target } answers { target } - every { policy.target = any() } propertyType Double::class answers { target = value } - - val logic = governor.createLogic(policy) - logic.onStart() - assertEquals(threshold, governor.threshold) - logic.onLimit(0.5) - - /* Upwards scaling */ - logic.onLimit(threshold + 0.2) - - /* Downwards scaling */ - logic.onLimit(threshold + 0.1) - - verify(exactly = 2) { policy.target = minSpeed } - verify(exactly = 1) { policy.target = minSpeed + stepSize } - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernorTest.kt deleted file mode 100644 index c0c25c97..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/OnDemandScalingGovernorTest.kt +++ /dev/null @@ -1,81 +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.compute.cpufreq - -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -/** - * Test suite for the [OnDemandScalingGovernor] - */ -internal class OnDemandScalingGovernorTest { - @Test - fun testSetStartLimitWithoutPStates() { - val cpuCapacity = 4100.0 - val minSpeed = cpuCapacity / 2 - val defaultThreshold = 0.8 - val governor = OnDemandScalingGovernor() - - val policy = mockk(relaxUnitFun = true) - every { policy.min } returns minSpeed - every { policy.max } returns cpuCapacity - - val logic = governor.createLogic(policy) - logic.onStart() - assertEquals(defaultThreshold, governor.threshold) - verify(exactly = 1) { policy.target = minSpeed } - - logic.onLimit(0.5) - verify(exactly = 1) { policy.target = minSpeed + 0.5 * (cpuCapacity - minSpeed) / 100 } - - logic.onLimit(defaultThreshold) - verify(exactly = 1) { policy.target = cpuCapacity } - } - - @Test - fun testSetStartLimitWithPStatesAndParams() { - val firstPState = 1000.0 - val cpuCapacity = 4100.0 - val threshold = 0.5 - val governor = OnDemandScalingGovernor(threshold) - - val policy = mockk(relaxUnitFun = true) - every { policy.max } returns cpuCapacity - every { policy.min } returns firstPState - - val logic = governor.createLogic(policy) - - logic.onStart() - assertEquals(threshold, governor.threshold) - verify(exactly = 1) { policy.target = firstPState } - - logic.onLimit(0.1) - verify(exactly = 1) { policy.target = firstPState + 0.1 * (cpuCapacity - firstPState) / 100 } - - logic.onLimit(threshold) - verify(exactly = 1) { policy.target = cpuCapacity } - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernorTest.kt deleted file mode 100644 index d7bd6193..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernorTest.kt +++ /dev/null @@ -1,50 +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.compute.cpufreq - -import io.mockk.every -import io.mockk.spyk -import io.mockk.verify -import org.junit.jupiter.api.Test - -/** - * Test suite for the [PerformanceScalingGovernor] - */ -internal class PerformanceScalingGovernorTest { - @Test - fun testSetStartLimit() { - val policy = spyk() - val logic = PerformanceScalingGovernor().createLogic(policy) - - every { policy.max } returns 4100.0 - - logic.onStart() - verify(exactly = 1) { policy.target = 4100.0 } - - logic.onLimit(0.0) - verify(exactly = 1) { policy.target = 4100.0 } - - logic.onLimit(1.0) - verify(exactly = 1) { policy.target = 4100.0 } - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernorTest.kt deleted file mode 100644 index 8d841981..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PowerSaveScalingGovernorTest.kt +++ /dev/null @@ -1,72 +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.compute.cpufreq - -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.junit.jupiter.api.Test - -/** - * Test suite for the [PowerSaveScalingGovernor] - */ -internal class PowerSaveScalingGovernorTest { - @Test - fun testSetStartLimitWithoutPStates() { - val cpuCapacity = 4100.0 - val minSpeed = cpuCapacity / 2 - val policy = mockk(relaxUnitFun = true) - val logic = PowerSaveScalingGovernor().createLogic(policy) - - every { policy.max } returns cpuCapacity - every { policy.min } returns minSpeed - - logic.onStart() - - logic.onLimit(0.0) - verify(exactly = 1) { policy.target = minSpeed } - - logic.onLimit(1.0) - verify(exactly = 1) { policy.target = minSpeed } - } - - @Test - fun testSetStartLimitWithPStates() { - val cpuCapacity = 4100.0 - val firstPState = 1000.0 - val policy = mockk(relaxUnitFun = true) - val logic = PowerSaveScalingGovernor().createLogic(policy) - - every { policy.max } returns cpuCapacity - every { policy.min } returns firstPState - - logic.onStart() - verify(exactly = 1) { policy.target = firstPState } - - logic.onLimit(0.0) - verify(exactly = 1) { policy.target = firstPState } - - logic.onLimit(1.0) - verify(exactly = 1) { policy.target = firstPState } - } -} 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 new file mode 100644 index 00000000..6c9ec7bd --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt @@ -0,0 +1,102 @@ +/* + * 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.compute.device + +import io.mockk.every +import io.mockk.mockk +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.power.SimPowerSource +import org.opendc.simulator.resources.SimResourceInterpreter + +/** + * Test suite for [SimPsu] + */ +internal class SimPsuTest { + + @Test + fun testInvalidInput() { + assertThrows { SimPsu(1.0, emptyMap()) } + } + + @Test + fun testDoubleConnect() { + val psu = SimPsu(1.0, mapOf(0.0 to 1.0)) + val cpuLogic = mockk() + psu.connect(cpuLogic) + assertThrows { psu.connect(mockk()) } + } + + @Test + fun testPsuIdle() = runBlockingSimulation { + val ratedOutputPower = 240.0 + val energyEfficiency = mapOf(0.0 to 1.0) + + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val source = SimPowerSource(interpreter, capacity = ratedOutputPower) + + val cpuLogic = mockk() + every { cpuLogic.computePower() } returns 0.0 + + val psu = SimPsu(ratedOutputPower, energyEfficiency) + psu.connect(cpuLogic) + source.connect(psu) + + assertEquals(0.0, source.powerDraw, 0.01) + } + + @Test + fun testPsuPowerLoss() = runBlockingSimulation { + val ratedOutputPower = 240.0 + // Efficiency of 80 Plus Titanium PSU + val energyEfficiency = sortedMapOf( + 0.3 to 0.9, + 0.7 to 0.92, + 1.0 to 0.94, + ) + + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val source = SimPowerSource(interpreter, capacity = ratedOutputPower) + + val cpuLogic = mockk() + every { cpuLogic.computePower() } returnsMany listOf(50.0, 100.0, 150.0, 200.0) + + val psu = SimPsu(ratedOutputPower, energyEfficiency) + psu.connect(cpuLogic) + source.connect(psu) + + assertEquals(55.55, source.powerDraw, 0.01) + + psu.update() + assertEquals(108.695, source.powerDraw, 0.01) + + psu.update() + assertEquals(163.043, source.powerDraw, 0.01) + + psu.update() + assertEquals(212.765, source.powerDraw, 0.01) + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorTest.kt new file mode 100644 index 00000000..71d48a31 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorTest.kt @@ -0,0 +1,226 @@ +/* + * 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.compute.kernel + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.yield +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertAll +import org.junit.jupiter.api.assertDoesNotThrow +import org.opendc.simulator.compute.SimBareMetalMachine +import org.opendc.simulator.compute.kernel.cpufreq.PerformanceScalingGovernor +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.compute.power.ConstantPowerModel +import org.opendc.simulator.compute.power.SimplePowerDriver +import org.opendc.simulator.compute.workload.SimTraceWorkload +import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.resources.SimResourceInterpreter + +/** + * Test suite for the [SimHypervisor] class. + */ +@OptIn(ExperimentalCoroutinesApi::class) +internal class SimHypervisorTest { + private lateinit var model: MachineModel + + @BeforeEach + fun setUp() { + val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) + model = MachineModel( + cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + ) + } + + /** + * Test overcommitting of resources via the hypervisor with a single VM. + */ + @Test + fun testOvercommittedSingle() = runBlockingSimulation { + val listener = object : SimHypervisor.Listener { + var totalRequestedWork = 0L + var totalGrantedWork = 0L + var totalOvercommittedWork = 0L + + override fun onSliceFinish( + hypervisor: SimHypervisor, + requestedWork: Long, + grantedWork: Long, + overcommittedWork: Long, + interferedWork: Long, + cpuUsage: Double, + cpuDemand: Double + ) { + totalRequestedWork += requestedWork + totalGrantedWork += grantedWork + totalOvercommittedWork += overcommittedWork + } + } + + val duration = 5 * 60L + val workloadA = + SimTraceWorkload( + sequenceOf( + SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 3500.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 183.0, 1) + ), + ) + + val platform = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine(platform, model, SimplePowerDriver(ConstantPowerModel(0.0))) + val hypervisor = SimFairShareHypervisor(platform, scalingGovernor = PerformanceScalingGovernor(), listener = listener) + + launch { + machine.run(hypervisor) + println("Hypervisor finished") + } + yield() + val vm = hypervisor.createMachine(model) + val res = mutableListOf() + val job = launch { machine.usage.toList(res) } + + vm.run(workloadA) + yield() + job.cancel() + machine.close() + + assertAll( + { assertEquals(1113300, listener.totalRequestedWork, "Requested Burst does not match") }, + { assertEquals(1023300, listener.totalGrantedWork, "Granted Burst does not match") }, + { assertEquals(90000, listener.totalOvercommittedWork, "Overcommissioned Burst does not match") }, + { assertEquals(listOf(0.0, 0.00875, 1.0, 0.0, 0.0571875, 0.0), res) { "VM usage is correct" } }, + { assertEquals(1200000, clock.millis()) { "Current time is correct" } } + ) + } + + /** + * Test overcommitting of resources via the hypervisor with two VMs. + */ + @Test + fun testOvercommittedDual() = runBlockingSimulation { + val listener = object : SimHypervisor.Listener { + var totalRequestedWork = 0L + var totalGrantedWork = 0L + var totalOvercommittedWork = 0L + + override fun onSliceFinish( + hypervisor: SimHypervisor, + requestedWork: Long, + grantedWork: Long, + overcommittedWork: Long, + interferedWork: Long, + cpuUsage: Double, + cpuDemand: Double + ) { + totalRequestedWork += requestedWork + totalGrantedWork += grantedWork + totalOvercommittedWork += overcommittedWork + } + } + + val duration = 5 * 60L + val workloadA = + SimTraceWorkload( + sequenceOf( + SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 3500.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 183.0, 1) + ), + ) + val workloadB = + SimTraceWorkload( + sequenceOf( + SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 3100.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 73.0, 1) + ) + ) + + val platform = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimFairShareHypervisor(platform, listener = listener) + + launch { + machine.run(hypervisor) + } + + yield() + coroutineScope { + launch { + val vm = hypervisor.createMachine(model) + vm.run(workloadA) + vm.close() + } + val vm = hypervisor.createMachine(model) + vm.run(workloadB) + vm.close() + } + yield() + machine.close() + yield() + + assertAll( + { assertEquals(2073600, listener.totalRequestedWork, "Requested Burst does not match") }, + { assertEquals(1053600, listener.totalGrantedWork, "Granted Burst does not match") }, + { assertEquals(1020000, listener.totalOvercommittedWork, "Overcommissioned Burst does not match") }, + { assertEquals(1200000, clock.millis()) } + ) + } + + @Test + fun testMultipleCPUs() = runBlockingSimulation { + val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) + val model = MachineModel( + cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + ) + + val platform = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimFairShareHypervisor(platform) + + assertDoesNotThrow { + launch { + machine.run(hypervisor) + } + } + + machine.close() + } +} 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 new file mode 100644 index 00000000..7c77b283 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt @@ -0,0 +1,229 @@ +/* + * 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.compute.kernel + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.yield +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.opendc.simulator.compute.SimBareMetalMachine +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.compute.power.ConstantPowerModel +import org.opendc.simulator.compute.power.SimplePowerDriver +import org.opendc.simulator.compute.workload.SimFlopsWorkload +import org.opendc.simulator.compute.workload.SimRuntimeWorkload +import org.opendc.simulator.compute.workload.SimTraceWorkload +import org.opendc.simulator.core.runBlockingSimulation +import org.opendc.simulator.resources.SimResourceInterpreter + +/** + * A test suite for the [SimSpaceSharedHypervisor]. + */ +@OptIn(ExperimentalCoroutinesApi::class) +internal class SimSpaceSharedHypervisorTest { + private lateinit var machineModel: MachineModel + + @BeforeEach + fun setUp() { + val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) + machineModel = MachineModel( + cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + ) + } + + /** + * Test a trace workload. + */ + @Test + fun testTrace() = runBlockingSimulation { + val usagePm = mutableListOf() + val usageVm = mutableListOf() + + val duration = 5 * 60L + val workloadA = + SimTraceWorkload( + sequenceOf( + SimTraceWorkload.Fragment(duration * 1000, 28.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 3500.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 0.0, 1), + SimTraceWorkload.Fragment(duration * 1000, 183.0, 1) + ), + ) + + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + SimResourceInterpreter(coroutineContext, clock), machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimSpaceSharedHypervisor(interpreter) + + val colA = launch { machine.usage.toList(usagePm) } + launch { machine.run(hypervisor) } + + yield() + + val vm = hypervisor.createMachine(machineModel) + val colB = launch { vm.usage.toList(usageVm) } + vm.run(workloadA) + yield() + + vm.close() + machine.close() + colA.cancel() + colB.cancel() + + assertAll( + { assertEquals(listOf(0.0, 0.00875, 1.0, 0.0, 0.0571875, 0.0), usagePm) { "Correct PM usage" } }, + // Temporary limitation is that VMs do not emit usage information + // { assertEquals(listOf(0.0, 0.00875, 1.0, 0.0, 0.0571875, 0.0), usageVm) { "Correct VM usage" } }, + { assertEquals(5 * 60L * 4000, clock.millis()) { "Took enough time" } } + ) + } + + /** + * Test runtime workload on hypervisor. + */ + @Test + fun testRuntimeWorkload() = runBlockingSimulation { + val duration = 5 * 60L * 1000 + val workload = SimRuntimeWorkload(duration) + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimSpaceSharedHypervisor(interpreter) + + launch { machine.run(hypervisor) } + yield() + val vm = hypervisor.createMachine(machineModel) + vm.run(workload) + vm.close() + machine.close() + + assertEquals(duration, clock.millis()) { "Took enough time" } + } + + /** + * Test FLOPs workload on hypervisor. + */ + @Test + fun testFlopsWorkload() = runBlockingSimulation { + val duration = 5 * 60L * 1000 + val workload = SimFlopsWorkload((duration * 3.2).toLong(), 1.0) + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimSpaceSharedHypervisor(interpreter) + + launch { machine.run(hypervisor) } + yield() + val vm = hypervisor.createMachine(machineModel) + vm.run(workload) + machine.close() + + assertEquals(duration, clock.millis()) { "Took enough time" } + } + + /** + * Test two workloads running sequentially. + */ + @Test + fun testTwoWorkloads() = runBlockingSimulation { + val duration = 5 * 60L * 1000 + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimSpaceSharedHypervisor(interpreter) + + launch { machine.run(hypervisor) } + yield() + + val vm = hypervisor.createMachine(machineModel) + vm.run(SimRuntimeWorkload(duration)) + vm.close() + + val vm2 = hypervisor.createMachine(machineModel) + vm2.run(SimRuntimeWorkload(duration)) + vm2.close() + machine.close() + + assertEquals(duration * 2, clock.millis()) { "Took enough time" } + } + + /** + * Test concurrent workloads on the machine. + */ + @Test + fun testConcurrentWorkloadFails() = runBlockingSimulation { + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimSpaceSharedHypervisor(interpreter) + + launch { machine.run(hypervisor) } + yield() + + hypervisor.createMachine(machineModel) + + assertAll( + { assertFalse(hypervisor.canFit(machineModel)) }, + { assertThrows { hypervisor.createMachine(machineModel) } } + ) + + machine.close() + } + + /** + * Test concurrent workloads on the machine. + */ + @Test + fun testConcurrentWorkloadSucceeds() = runBlockingSimulation { + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) + ) + val hypervisor = SimSpaceSharedHypervisor(interpreter) + + launch { machine.run(hypervisor) } + yield() + + hypervisor.createMachine(machineModel).close() + + assertAll( + { assertTrue(hypervisor.canFit(machineModel)) }, + { assertDoesNotThrow { hypervisor.createMachine(machineModel) } } + ) + + machine.close() + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt new file mode 100644 index 00000000..ef354569 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt @@ -0,0 +1,98 @@ +/* + * 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.compute.kernel.cpufreq + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +/** + * Test suite for the [ConservativeScalingGovernor] + */ +internal class ConservativeScalingGovernorTest { + @Test + fun testSetStartLimitWithoutPStates() { + val cpuCapacity = 4100.0 + val minSpeed = cpuCapacity / 2 + val defaultThreshold = 0.8 + val defaultStepSize = 0.05 * cpuCapacity + val governor = ConservativeScalingGovernor() + + val policy = mockk(relaxUnitFun = true) + every { policy.max } returns cpuCapacity + every { policy.min } returns minSpeed + + var target = 0.0 + every { policy.target } answers { target } + every { policy.target = any() } propertyType Double::class answers { target = value } + + val logic = governor.createLogic(policy) + logic.onStart() + assertEquals(defaultThreshold, governor.threshold) + + logic.onLimit(0.5) + + /* Upwards scaling */ + logic.onLimit(defaultThreshold + 0.2) + + /* Downwards scaling */ + logic.onLimit(defaultThreshold + 0.1) + + verify(exactly = 2) { policy.target = minSpeed } + verify(exactly = 1) { policy.target = minSpeed + defaultStepSize } + } + + @Test + fun testSetStartLimitWithPStatesAndParams() { + val firstPState = 1000.0 + val cpuCapacity = 4100.0 + val minSpeed = firstPState + val threshold = 0.5 + val stepSize = 0.02 * cpuCapacity + val governor = ConservativeScalingGovernor(threshold, stepSize) + + val policy = mockk(relaxUnitFun = true) + every { policy.max } returns cpuCapacity + every { policy.min } returns firstPState + + var target = 0.0 + every { policy.target } answers { target } + every { policy.target = any() } propertyType Double::class answers { target = value } + + val logic = governor.createLogic(policy) + logic.onStart() + assertEquals(threshold, governor.threshold) + logic.onLimit(0.5) + + /* Upwards scaling */ + logic.onLimit(threshold + 0.2) + + /* Downwards scaling */ + logic.onLimit(threshold + 0.1) + + verify(exactly = 2) { policy.target = minSpeed } + verify(exactly = 1) { policy.target = minSpeed + stepSize } + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt new file mode 100644 index 00000000..ca759e39 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt @@ -0,0 +1,81 @@ +/* + * 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.compute.kernel.cpufreq + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +/** + * Test suite for the [OnDemandScalingGovernor] + */ +internal class OnDemandScalingGovernorTest { + @Test + fun testSetStartLimitWithoutPStates() { + val cpuCapacity = 4100.0 + val minSpeed = cpuCapacity / 2 + val defaultThreshold = 0.8 + val governor = OnDemandScalingGovernor() + + val policy = mockk(relaxUnitFun = true) + every { policy.min } returns minSpeed + every { policy.max } returns cpuCapacity + + val logic = governor.createLogic(policy) + logic.onStart() + assertEquals(defaultThreshold, governor.threshold) + verify(exactly = 1) { policy.target = minSpeed } + + logic.onLimit(0.5) + verify(exactly = 1) { policy.target = minSpeed + 0.5 * (cpuCapacity - minSpeed) / 100 } + + logic.onLimit(defaultThreshold) + verify(exactly = 1) { policy.target = cpuCapacity } + } + + @Test + fun testSetStartLimitWithPStatesAndParams() { + val firstPState = 1000.0 + val cpuCapacity = 4100.0 + val threshold = 0.5 + val governor = OnDemandScalingGovernor(threshold) + + val policy = mockk(relaxUnitFun = true) + every { policy.max } returns cpuCapacity + every { policy.min } returns firstPState + + val logic = governor.createLogic(policy) + + logic.onStart() + assertEquals(threshold, governor.threshold) + verify(exactly = 1) { policy.target = firstPState } + + logic.onLimit(0.1) + verify(exactly = 1) { policy.target = firstPState + 0.1 * (cpuCapacity - firstPState) / 100 } + + logic.onLimit(threshold) + verify(exactly = 1) { policy.target = cpuCapacity } + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt new file mode 100644 index 00000000..a4bb24f2 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt @@ -0,0 +1,50 @@ +/* + * 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.compute.kernel.cpufreq + +import io.mockk.every +import io.mockk.spyk +import io.mockk.verify +import org.junit.jupiter.api.Test + +/** + * Test suite for the [PerformanceScalingGovernor] + */ +internal class PerformanceScalingGovernorTest { + @Test + fun testSetStartLimit() { + val policy = spyk() + val logic = PerformanceScalingGovernor().createLogic(policy) + + every { policy.max } returns 4100.0 + + logic.onStart() + verify(exactly = 1) { policy.target = 4100.0 } + + logic.onLimit(0.0) + verify(exactly = 1) { policy.target = 4100.0 } + + logic.onLimit(1.0) + verify(exactly = 1) { policy.target = 4100.0 } + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt new file mode 100644 index 00000000..662d55fb --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt @@ -0,0 +1,72 @@ +/* + * 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.compute.kernel.cpufreq + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.Test + +/** + * Test suite for the [PowerSaveScalingGovernor] + */ +internal class PowerSaveScalingGovernorTest { + @Test + fun testSetStartLimitWithoutPStates() { + val cpuCapacity = 4100.0 + val minSpeed = cpuCapacity / 2 + val policy = mockk(relaxUnitFun = true) + val logic = PowerSaveScalingGovernor().createLogic(policy) + + every { policy.max } returns cpuCapacity + every { policy.min } returns minSpeed + + logic.onStart() + + logic.onLimit(0.0) + verify(exactly = 1) { policy.target = minSpeed } + + logic.onLimit(1.0) + verify(exactly = 1) { policy.target = minSpeed } + } + + @Test + fun testSetStartLimitWithPStates() { + val cpuCapacity = 4100.0 + val firstPState = 1000.0 + val policy = mockk(relaxUnitFun = true) + val logic = PowerSaveScalingGovernor().createLogic(policy) + + every { policy.max } returns cpuCapacity + every { policy.min } returns firstPState + + logic.onStart() + verify(exactly = 1) { policy.target = firstPState } + + logic.onLimit(0.0) + verify(exactly = 1) { policy.target = firstPState } + + logic.onLimit(1.0) + verify(exactly = 1) { policy.target = firstPState } + } +} -- cgit v1.2.3 From ba3efea6c5d2f4d2fbd2ecc9364817f541000839 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Mon, 21 Jun 2021 21:33:06 +0200 Subject: simulator: Add support for attaching network adapter to machine This change bridges the compute and network simulation module by adding support for network adapters in the compute module. With these network adapters, compute workloads can communicate over the network that the adapters are connected to. --- .../opendc-simulator-compute/build.gradle.kts | 1 + .../opendc/simulator/compute/SimAbstractMachine.kt | 42 ++++++++++++++++++ .../org/opendc/simulator/compute/SimMachine.kt | 6 +++ .../opendc/simulator/compute/SimMachineContext.kt | 5 +++ .../simulator/compute/SimNetworkInterface.kt | 51 ++++++++++++++++++++++ .../simulator/compute/device/SimNetworkAdapter.kt | 36 +++++++++++++++ .../simulator/compute/device/SimPeripheral.kt | 33 ++++++++++++++ .../opendc/simulator/compute/model/MachineModel.kt | 7 ++- .../simulator/compute/model/NetworkAdapter.kt | 36 +++++++++++++++ .../org/opendc/simulator/compute/SimMachineTest.kt | 37 +++++++++++++--- 10 files changed, 248 insertions(+), 6 deletions(-) create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimNetworkInterface.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimNetworkAdapter.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPeripheral.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt (limited to 'opendc-simulator/opendc-simulator-compute') diff --git a/opendc-simulator/opendc-simulator-compute/build.gradle.kts b/opendc-simulator/opendc-simulator-compute/build.gradle.kts index 41cdd40c..74384480 100644 --- a/opendc-simulator/opendc-simulator-compute/build.gradle.kts +++ b/opendc-simulator/opendc-simulator-compute/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { api(platform(projects.opendcPlatform)) api(projects.opendcSimulator.opendcSimulatorResources) api(projects.opendcSimulator.opendcSimulatorPower) + api(projects.opendcSimulator.opendcSimulatorNetwork) implementation(projects.opendcSimulator.opendcSimulatorCore) implementation(projects.opendcUtils) implementation(libs.yaml) diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt index ca508054..99f9397d 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt @@ -25,8 +25,11 @@ package org.opendc.simulator.compute import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import org.opendc.simulator.compute.device.SimNetworkAdapter +import org.opendc.simulator.compute.device.SimPeripheral import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit +import org.opendc.simulator.compute.model.NetworkAdapter import org.opendc.simulator.compute.workload.SimWorkload import org.opendc.simulator.resources.* import kotlin.coroutines.Continuation @@ -68,6 +71,16 @@ public abstract class SimAbstractMachine( */ protected val memory: SimMemory = Memory(SimResourceSource(model.memory.sumOf { it.size }.toDouble(), interpreter), model.memory) + /** + * The network interfaces available to the machine. + */ + protected val net: List = model.net.mapIndexed { i, adapter -> NetworkAdapterImpl(adapter, i) } + + /** + * The peripherals of the machine. + */ + public override val peripherals: List = net.map { it as SimNetworkAdapter } + /** * A flag to indicate that the machine is terminated. */ @@ -166,6 +179,8 @@ public abstract class SimAbstractMachine( override val memory: SimMemory = this@SimAbstractMachine.memory + override val net: List = this@SimAbstractMachine.net + override fun close() = cancel() } @@ -175,4 +190,31 @@ public abstract class SimAbstractMachine( private class Memory(source: SimResourceSource, override val models: List) : SimMemory, SimResourceProvider by source { override fun toString(): String = "SimAbstractMachine.Memory" } + + /** + * The [SimNetworkAdapter] implementation for a machine. + */ + private class NetworkAdapterImpl( + model: NetworkAdapter, + index: Int + ) : SimNetworkAdapter(), SimNetworkInterface { + override val name: String = "eth$index" + + override val bandwidth: Double = model.bandwidth + + override val provider: SimResourceProvider + get() = _rx + + override fun createConsumer(): SimResourceConsumer = _tx + + override val tx: SimResourceProvider + get() = _tx + private val _tx = SimResourceForwarder() + + override val rx: SimResourceConsumer + get() = _rx + private val _rx = SimResourceForwarder() + + override fun toString(): String = "SimAbstractMachine.NetworkAdapterImpl[name=$name,bandwidth=$bandwidth]" + } } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt index 4e7d191c..0f4674d5 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt @@ -23,6 +23,7 @@ package org.opendc.simulator.compute import kotlinx.coroutines.flow.StateFlow +import org.opendc.simulator.compute.device.SimPeripheral import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.workload.SimWorkload @@ -35,6 +36,11 @@ public interface SimMachine : AutoCloseable { */ public val model: MachineModel + /** + * The peripherals attached to the machine. + */ + public val peripherals: List + /** * A [StateFlow] representing the CPU usage of the simulated machine. */ diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt index 391442ec..68a7fb63 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt @@ -50,6 +50,11 @@ public interface SimMachineContext : AutoCloseable { */ public val memory: SimMemory + /** + * The network interfaces available to the workload. + */ + public val net: List + /** * Stop the workload. */ diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimNetworkInterface.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimNetworkInterface.kt new file mode 100644 index 00000000..1ac126ae --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimNetworkInterface.kt @@ -0,0 +1,51 @@ +/* + * 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.compute + +import org.opendc.simulator.resources.SimResourceConsumer +import org.opendc.simulator.resources.SimResourceProvider + +/** + * A firmware interface to a network adapter. + */ +public interface SimNetworkInterface { + /** + * The name of the network interface. + */ + public val name: String + + /** + * The unidirectional bandwidth of the network interface in Mbps. + */ + public val bandwidth: Double + + /** + * The resource provider for the transmit channel of the network interface. + */ + public val tx: SimResourceProvider + + /** + * The resource consumer for the receive channel of the network interface. + */ + public val rx: SimResourceConsumer +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimNetworkAdapter.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimNetworkAdapter.kt new file mode 100644 index 00000000..dfb4ecf3 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimNetworkAdapter.kt @@ -0,0 +1,36 @@ +/* + * 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.compute.device + +import org.opendc.simulator.compute.SimMachine +import org.opendc.simulator.network.SimNetworkPort + +/** + * A simulated network interface card (NIC or network adapter) that can be attached to a [SimMachine]. + */ +public abstract class SimNetworkAdapter : SimNetworkPort(), SimPeripheral { + /** + * The unidirectional bandwidth of the network adapter in Mbps. + */ + public abstract val bandwidth: Double +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPeripheral.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPeripheral.kt new file mode 100644 index 00000000..268271be --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPeripheral.kt @@ -0,0 +1,33 @@ +/* + * 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.compute.device + +import org.opendc.simulator.compute.SimMachine + +/** + * A component that can be attached to a [SimMachine]. + * + * This interface represents the physical view of the peripheral and should be used to configure the physical properties + * of the peripheral. + */ +public interface SimPeripheral diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt index 4b6fd7bb..d40aff53 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt @@ -27,5 +27,10 @@ package org.opendc.simulator.compute.model * * @property cpus The list of processing units available to the image. * @property memory The list of memory units available to the image. + * @property net A list of network adapters available for the machine. */ -public data class MachineModel(public val cpus: List, public val memory: List) +public data class MachineModel( + public val cpus: List, + public val memory: List, + public val net: List = emptyList() +) diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt new file mode 100644 index 00000000..46472144 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt @@ -0,0 +1,36 @@ +/* + * 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.compute.model + +/** + * A description of a network adapter that is + * + * @property vendor The vendor of the network adapter. + * @property modelName The model name of the network adapter. + * @property bandwidth The bandwidth of the network adapter in Mbps. + */ +public data class NetworkAdapter( + public val vendor: String, + public val modelName: String, + public val bandwidth: Double +) 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 dcf509e2..47ae119c 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 @@ -30,10 +30,8 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows -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.compute.device.SimNetworkAdapter +import org.opendc.simulator.compute.model.* import org.opendc.simulator.compute.power.ConstantPowerModel import org.opendc.simulator.compute.power.LinearPowerModel import org.opendc.simulator.compute.power.SimplePowerDriver @@ -41,6 +39,7 @@ 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.network.SimNetworkSink import org.opendc.simulator.power.SimPowerSource import org.opendc.simulator.resources.SimResourceInterpreter import org.opendc.simulator.resources.consumer.SimWorkConsumer @@ -58,7 +57,8 @@ class SimMachineTest { machineModel = MachineModel( cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + net = listOf(NetworkAdapter("Mellanox", "ConnectX-5", 25000.0)) ) } @@ -232,6 +232,33 @@ class SimMachineTest { } } + @Test + fun testNetUsage() = runBlockingSimulation { + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val machine = SimBareMetalMachine( + interpreter, + machineModel, + SimplePowerDriver(ConstantPowerModel(0.0)) + ) + + val adapter = (machine.peripherals[0] as SimNetworkAdapter) + adapter.connect(SimNetworkSink(interpreter, adapter.bandwidth)) + + try { + machine.run(object : SimWorkload { + override fun onStart(ctx: SimMachineContext) { + val lifecycle = SimWorkloadLifecycle(ctx) + val iface = ctx.net[0] + iface.tx.startConsumer(lifecycle.waitFor(SimWorkConsumer(iface.bandwidth, utilization = 0.8))) + } + }) + + assertEquals(1250, clock.millis()) + } finally { + machine.close() + } + } + @Test fun testCancellation() = runBlockingSimulation { val machine = SimBareMetalMachine( -- cgit v1.2.3