From 84468f4e3a331d7ea073ac7033b3d9937168ed9f Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 2 Jun 2021 23:23:55 +0200 Subject: simulator: Split CPUFreq subsystem in compute simulator This change splits the functionality present in the CPUFreq subsystem of the compute simulation. Currently, the DVFS functionality is embedded in SimBareMetalMachine. However, this functionality should not exist within the firmware layer of a machine. Instead, the operating system should perform this logic (in OpenDC this should be the hypervisor). Furthermore, this change moves the scaling driver into the power package. The power driver is a machine/firmware specific implementation that computes the power consumption of a machine. --- .../simulator/compute/SimMachineBenchmarks.kt | 15 +-- .../simulator/compute/SimBareMetalMachine.kt | 29 +---- .../compute/cpufreq/PStateScalingDriver.kt | 86 -------------- .../simulator/compute/cpufreq/ScalingDriver.kt | 53 --------- .../compute/cpufreq/SimpleScalingDriver.kt | 49 -------- .../simulator/compute/power/PStatePowerDriver.kt | 60 ++++++++++ .../opendc/simulator/compute/power/PowerDriver.kt | 48 ++++++++ .../simulator/compute/power/SimplePowerDriver.kt | 39 ++++++ .../opendc/simulator/compute/SimHypervisorTest.kt | 11 +- .../org/opendc/simulator/compute/SimMachineTest.kt | 27 ++++- .../compute/SimSpaceSharedHypervisorTest.kt | 21 ++-- .../compute/cpufreq/PStateScalingDriverTest.kt | 132 --------------------- .../compute/power/PStatePowerDriverTest.kt | 125 +++++++++++++++++++ 13 files changed, 315 insertions(+), 380 deletions(-) delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriverTest.kt create mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerDriverTest.kt (limited to 'opendc-simulator/opendc-simulator-compute/src') 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 bc21edc6..fb753de2 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,12 +25,11 @@ package org.opendc.simulator.compute import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch -import org.opendc.simulator.compute.cpufreq.PerformanceScalingGovernor -import org.opendc.simulator.compute.cpufreq.SimpleScalingDriver 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.SimulationCoroutineScope import org.opendc.simulator.core.runBlockingSimulation @@ -84,8 +83,7 @@ class SimMachineBenchmarks { fun benchmarkBareMetal(state: Workload) { return scope.runBlockingSimulation { val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) return@runBlockingSimulation machine.run(SimTraceWorkload(state.trace)) } @@ -95,8 +93,7 @@ class SimMachineBenchmarks { fun benchmarkSpaceSharedHypervisor(state: Workload) { return scope.runBlockingSimulation { val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimSpaceSharedHypervisor(interpreter) @@ -117,8 +114,7 @@ class SimMachineBenchmarks { fun benchmarkFairShareHypervisorSingle(state: Workload) { return scope.runBlockingSimulation { val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimFairShareHypervisor(interpreter) @@ -139,8 +135,7 @@ class SimMachineBenchmarks { fun benchmarkFairShareHypervisorDouble(state: Workload) { return scope.runBlockingSimulation { val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimFairShareHypervisor(interpreter) 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 7a49f29a..c453cdf3 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,10 +22,8 @@ package org.opendc.simulator.compute -import kotlinx.coroutines.* -import org.opendc.simulator.compute.cpufreq.ScalingDriver -import org.opendc.simulator.compute.cpufreq.ScalingGovernor import org.opendc.simulator.compute.model.ProcessingUnit +import org.opendc.simulator.compute.power.PowerDriver import org.opendc.simulator.resources.* import org.opendc.simulator.resources.SimResourceInterpreter @@ -37,16 +35,13 @@ import org.opendc.simulator.resources.SimResourceInterpreter * * @param interpreter The [SimResourceInterpreter] to drive the simulation. * @param model The machine model to simulate. - * @param scalingGovernor The CPU frequency scaling governor to use. - * @param scalingDriver The CPU frequency scaling driver to use. + * @param powerDriver The power driver to use. * @param parent The parent simulation system. */ -@OptIn(ExperimentalCoroutinesApi::class, InternalCoroutinesApi::class) public class SimBareMetalMachine( interpreter: SimResourceInterpreter, model: SimMachineModel, - scalingGovernor: ScalingGovernor, - scalingDriver: ScalingDriver, + powerDriver: PowerDriver, parent: SimResourceSystem? = null, ) : SimAbstractMachine(interpreter, parent, model) { override val cpus: List = model.cpus.map { cpu -> @@ -54,20 +49,9 @@ public class SimBareMetalMachine( } /** - * Construct the [ScalingDriver.Logic] for this machine. + * Construct the [PowerDriver.Logic] for this machine. */ - private val scalingDriver = scalingDriver.createLogic(this) - - /** - * The scaling contexts associated with each CPU. - */ - private val scalingGovernors = cpus.map { cpu -> - scalingGovernor.createLogic(this.scalingDriver.createContext(cpu)) - } - - init { - scalingGovernors.forEach { it.onStart() } - } + private val powerDriver = powerDriver.createLogic(this, cpus) /** * The power draw of the machine. @@ -78,8 +62,7 @@ public class SimBareMetalMachine( override fun updateUsage(usage: Double) { super.updateUsage(usage) - scalingGovernors.forEach { it.onLimit() } - powerDraw = scalingDriver.computePower() + powerDraw = powerDriver.computePower() } /** diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt deleted file mode 100644 index 6f44d778..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt +++ /dev/null @@ -1,86 +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.SimMachine -import org.opendc.simulator.compute.SimProcessingUnit -import org.opendc.simulator.compute.power.PowerModel -import java.util.* -import kotlin.math.max -import kotlin.math.min - -/** - * A [ScalingDriver] that scales the frequency of the processor based on a discrete set of frequencies. - * - * @param states A map describing the states of the driver. - */ -public class PStateScalingDriver(states: Map) : ScalingDriver { - /** - * The P-States defined by the user and ordered by key. - */ - private val states = TreeMap(states) - - override fun createLogic(machine: SimMachine): ScalingDriver.Logic = object : ScalingDriver.Logic { - /** - * The scaling contexts. - */ - private val contexts = mutableListOf() - - override fun createContext(cpu: SimProcessingUnit): ScalingContext { - val ctx = ScalingContextImpl(machine, cpu) - contexts.add(ctx) - return ctx - } - - override fun computePower(): Double { - var targetFreq = 0.0 - var totalSpeed = 0.0 - - for (ctx in contexts) { - targetFreq = max(ctx.target, targetFreq) - totalSpeed += ctx.cpu.speed - } - - val maxFreq = states.lastKey() - val (actualFreq, model) = states.ceilingEntry(min(maxFreq, targetFreq)) - val utilization = totalSpeed / (actualFreq * contexts.size) - return model.computePower(utilization) - } - - override fun toString(): String = "PStateScalingDriver.Logic" - } - - private class ScalingContextImpl( - override val machine: SimMachine, - override val cpu: SimProcessingUnit - ) : ScalingContext { - var target = cpu.model.frequency - private set - - override fun setTarget(freq: Double) { - target = freq - } - - override fun toString(): String = "PStateScalingDriver.Context" - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt deleted file mode 100644 index b4fd7550..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt +++ /dev/null @@ -1,53 +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.SimMachine -import org.opendc.simulator.compute.SimProcessingUnit - -/** - * A [ScalingDriver] is responsible for switching the processor to the correct frequency. - */ -public interface ScalingDriver { - /** - * Create the scaling logic for the specified [machine] - */ - public fun createLogic(machine: SimMachine): Logic - - /** - * The logic of the scaling driver. - */ - public interface Logic { - /** - * Create the [ScalingContext] for the specified [cpu] instance. - */ - public fun createContext(cpu: SimProcessingUnit): ScalingContext - - /** - * Compute the power consumption of the processor. - * - * @return The power consumption of the processor in W. - */ - public fun computePower(): Double - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt deleted file mode 100644 index cf0bbb28..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt +++ /dev/null @@ -1,49 +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.SimMachine -import org.opendc.simulator.compute.SimProcessingUnit -import org.opendc.simulator.compute.power.PowerModel - -/** - * A [ScalingDriver] that ignores the instructions of the [ScalingGovernor] and directly computes the power consumption - * based on the specified [power model][model]. - */ -public class SimpleScalingDriver(private val model: PowerModel) : ScalingDriver { - override fun createLogic(machine: SimMachine): ScalingDriver.Logic = object : ScalingDriver.Logic { - override fun createContext(cpu: SimProcessingUnit): ScalingContext { - return object : ScalingContext { - override val machine: SimMachine = machine - - override val cpu: SimProcessingUnit = cpu - - override fun setTarget(freq: Double) {} - } - } - - override fun computePower(): Double = model.computePower(machine.usage.value) - - override fun toString(): String = "SimpleScalingDriver.Logic" - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt new file mode 100644 index 00000000..6328c8e4 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt @@ -0,0 +1,60 @@ +/* + * 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.power + +import org.opendc.simulator.compute.SimMachine +import org.opendc.simulator.compute.SimProcessingUnit +import java.util.* +import kotlin.math.max +import kotlin.math.min + +/** + * A [PowerDriver] that computes the power draw using multiple [PowerModel]s based on multiple frequency states. + * + * @param states A map describing the states of the driver. + */ +public class PStatePowerDriver(states: Map) : PowerDriver { + /** + * The P-States defined by the user and ordered by key. + */ + private val states = TreeMap(states) + + override fun createLogic(machine: SimMachine, cpus: List): PowerDriver.Logic = object : PowerDriver.Logic { + override fun computePower(): Double { + var targetFreq = 0.0 + var totalSpeed = 0.0 + + for (cpu in cpus) { + targetFreq = max(cpu.capacity, targetFreq) + totalSpeed += cpu.speed + } + + val maxFreq = states.lastKey() + val (actualFreq, model) = states.ceilingEntry(min(maxFreq, targetFreq)) + val utilization = totalSpeed / (actualFreq * cpus.size) + return model.computePower(utilization) + } + + override fun toString(): String = "PStatePowerDriver.Logic" + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.kt new file mode 100644 index 00000000..a1a2b911 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.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.power + +import org.opendc.simulator.compute.SimMachine +import org.opendc.simulator.compute.SimProcessingUnit + +/** + * A [PowerDriver] is responsible for switching the processor to the correct frequency. + */ +public interface PowerDriver { + /** + * Create the scaling logic for the specified [machine] + */ + public fun createLogic(machine: SimMachine, cpus: List): Logic + + /** + * The logic of the scaling driver. + */ + public interface Logic { + /** + * Compute the power consumption of the processor. + * + * @return The power consumption of the processor in W. + */ + public fun computePower(): Double + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.kt new file mode 100644 index 00000000..5c5ceff5 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.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.power + +import org.opendc.simulator.compute.SimMachine +import org.opendc.simulator.compute.SimProcessingUnit + +/** + * A [PowerDriver] that computes the power consumption based on a single specified [power model][model]. + */ +public class SimplePowerDriver(private val model: PowerModel) : PowerDriver { + override fun createLogic(machine: SimMachine, cpus: List): PowerDriver.Logic = object : PowerDriver.Logic { + override fun computePower(): Double { + return model.computePower(machine.usage.value) + } + + override fun toString(): String = "SimplePowerDriver.Logic" + } +} 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 index 1709cc23..0bcfd9c6 100644 --- 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 @@ -32,12 +32,11 @@ 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.cpufreq.SimpleScalingDriver 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 @@ -95,7 +94,7 @@ internal class SimHypervisorTest { ) val platform = SimResourceInterpreter(coroutineContext, clock) - val machine = SimBareMetalMachine(platform, model, PerformanceScalingGovernor(), SimpleScalingDriver(ConstantPowerModel(0.0))) + val machine = SimBareMetalMachine(platform, model, SimplePowerDriver(ConstantPowerModel(0.0))) val hypervisor = SimFairShareHypervisor(platform, null, listener) launch { @@ -168,8 +167,7 @@ internal class SimHypervisorTest { val platform = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - platform, model, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimFairShareHypervisor(platform, null, listener) @@ -210,8 +208,7 @@ internal class SimHypervisorTest { val platform = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - platform, model, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimFairShareHypervisor(platform) 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 7cc3c6dd..69f562d2 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 @@ -29,12 +29,11 @@ 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.cpufreq.PerformanceScalingGovernor -import org.opendc.simulator.compute.cpufreq.SimpleScalingDriver 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.core.runBlockingSimulation import org.opendc.simulator.resources.SimResourceInterpreter @@ -58,7 +57,11 @@ class SimMachineTest { @Test fun testFlopsWorkload() = runBlockingSimulation { - val machine = SimBareMetalMachine(SimResourceInterpreter(coroutineContext, clock), machineModel, PerformanceScalingGovernor(), SimpleScalingDriver(ConstantPowerModel(0.0))) + val machine = SimBareMetalMachine( + SimResourceInterpreter(coroutineContext, clock), + machineModel, + SimplePowerDriver(ConstantPowerModel(0.0)) + ) try { machine.run(SimFlopsWorkload(2_000, utilization = 1.0)) @@ -77,7 +80,11 @@ class SimMachineTest { cpus = List(cpuNode.coreCount * 2) { ProcessingUnit(cpuNode, it % 2, 1000.0) }, memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) - val machine = SimBareMetalMachine(SimResourceInterpreter(coroutineContext, clock), machineModel, PerformanceScalingGovernor(), SimpleScalingDriver(ConstantPowerModel(0.0))) + val machine = SimBareMetalMachine( + SimResourceInterpreter(coroutineContext, clock), + machineModel, + SimplePowerDriver(ConstantPowerModel(0.0)) + ) try { machine.run(SimFlopsWorkload(2_000, utilization = 1.0)) @@ -91,7 +98,11 @@ class SimMachineTest { @Test fun testUsage() = runBlockingSimulation { - val machine = SimBareMetalMachine(SimResourceInterpreter(coroutineContext, clock), machineModel, PerformanceScalingGovernor(), SimpleScalingDriver(ConstantPowerModel(0.0))) + val machine = SimBareMetalMachine( + SimResourceInterpreter(coroutineContext, clock), + machineModel, + SimplePowerDriver(ConstantPowerModel(0.0)) + ) val res = mutableListOf() val job = launch { machine.usage.toList(res) } @@ -108,7 +119,11 @@ class SimMachineTest { @Test fun testClose() = runBlockingSimulation { - val machine = SimBareMetalMachine(SimResourceInterpreter(coroutineContext, clock), machineModel, PerformanceScalingGovernor(), SimpleScalingDriver(ConstantPowerModel(0.0))) + val machine = SimBareMetalMachine( + SimResourceInterpreter(coroutineContext, clock), + machineModel, + SimplePowerDriver(ConstantPowerModel(0.0)) + ) machine.close() assertDoesNotThrow { machine.close() } 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 index dd824557..dba3e9a1 100644 --- 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 @@ -30,12 +30,11 @@ 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.cpufreq.PerformanceScalingGovernor -import org.opendc.simulator.compute.cpufreq.SimpleScalingDriver 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 @@ -79,8 +78,7 @@ internal class SimSpaceSharedHypervisorTest { val interpreter = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - SimResourceInterpreter(coroutineContext, clock), machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + SimResourceInterpreter(coroutineContext, clock), machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimSpaceSharedHypervisor(interpreter) @@ -116,8 +114,7 @@ internal class SimSpaceSharedHypervisorTest { val workload = SimRuntimeWorkload(duration) val interpreter = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimSpaceSharedHypervisor(interpreter) @@ -140,8 +137,7 @@ internal class SimSpaceSharedHypervisorTest { val workload = SimFlopsWorkload((duration * 3.2).toLong(), 1.0) val interpreter = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimSpaceSharedHypervisor(interpreter) @@ -162,8 +158,7 @@ internal class SimSpaceSharedHypervisorTest { val duration = 5 * 60L * 1000 val interpreter = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimSpaceSharedHypervisor(interpreter) @@ -189,8 +184,7 @@ internal class SimSpaceSharedHypervisorTest { fun testConcurrentWorkloadFails() = runBlockingSimulation { val interpreter = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimSpaceSharedHypervisor(interpreter) @@ -214,8 +208,7 @@ internal class SimSpaceSharedHypervisorTest { fun testConcurrentWorkloadSucceeds() = runBlockingSimulation { val interpreter = SimResourceInterpreter(coroutineContext, clock) val machine = SimBareMetalMachine( - interpreter, machineModel, PerformanceScalingGovernor(), - SimpleScalingDriver(ConstantPowerModel(0.0)) + interpreter, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) val hypervisor = SimSpaceSharedHypervisor(interpreter) diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriverTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriverTest.kt deleted file mode 100644 index bbea3ee2..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriverTest.kt +++ /dev/null @@ -1,132 +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 org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.opendc.simulator.compute.SimBareMetalMachine -import org.opendc.simulator.compute.SimProcessingUnit -import org.opendc.simulator.compute.power.ConstantPowerModel -import org.opendc.simulator.compute.power.LinearPowerModel - -/** - * Test suite for [PStateScalingDriver]. - */ -internal class PStateScalingDriverTest { - @Test - fun testPowerWithoutGovernor() { - val machine = mockk() - - val driver = PStateScalingDriver( - sortedMapOf( - 2800.0 to ConstantPowerModel(200.0), - 3300.0 to ConstantPowerModel(300.0), - 3600.0 to ConstantPowerModel(350.0), - ) - ) - - val logic = driver.createLogic(machine) - assertEquals(200.0, logic.computePower()) - } - - @Test - fun testPowerWithSingleGovernor() { - val machine = mockk() - val cpu = mockk() - - every { cpu.model.frequency } returns 4100.0 - every { cpu.speed } returns 1200.0 - - val driver = PStateScalingDriver( - sortedMapOf( - 2800.0 to ConstantPowerModel(200.0), - 3300.0 to ConstantPowerModel(300.0), - 3600.0 to ConstantPowerModel(350.0), - ) - ) - - val logic = driver.createLogic(machine) - - val scalingContext = logic.createContext(cpu) - scalingContext.setTarget(3200.0) - - assertEquals(300.0, logic.computePower()) - } - - @Test - fun testPowerWithMultipleGovernors() { - val machine = mockk() - val cpu = mockk() - - every { cpu.model.frequency } returns 4100.0 - every { cpu.speed } returns 1200.0 - - val driver = PStateScalingDriver( - sortedMapOf( - 2800.0 to ConstantPowerModel(200.0), - 3300.0 to ConstantPowerModel(300.0), - 3600.0 to ConstantPowerModel(350.0), - ) - ) - - val logic = driver.createLogic(machine) - - val scalingContextA = logic.createContext(cpu) - scalingContextA.setTarget(1000.0) - - val scalingContextB = logic.createContext(cpu) - scalingContextB.setTarget(3400.0) - - assertEquals(350.0, logic.computePower()) - } - - @Test - fun testPowerBasedOnUtilization() { - val machine = mockk() - val cpu = mockk() - - every { cpu.model.frequency } returns 4200.0 - - val driver = PStateScalingDriver( - sortedMapOf( - 2800.0 to LinearPowerModel(200.0, 100.0), - 3300.0 to LinearPowerModel(250.0, 150.0), - 4000.0 to LinearPowerModel(300.0, 200.0), - ) - ) - - val logic = driver.createLogic(machine) - - val scalingContext = logic.createContext(cpu) - - every { cpu.speed } returns 1400.0 - scalingContext.setTarget(1400.0) - assertEquals(150.0, logic.computePower()) - - every { cpu.speed } returns 1400.0 - scalingContext.setTarget(4000.0) - assertEquals(235.0, logic.computePower()) - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerDriverTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerDriverTest.kt new file mode 100644 index 00000000..35fd7c4c --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerDriverTest.kt @@ -0,0 +1,125 @@ +/* + * 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.power + +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.opendc.simulator.compute.SimBareMetalMachine +import org.opendc.simulator.compute.SimProcessingUnit + +/** + * Test suite for [PStatePowerDriver]. + */ +internal class PStatePowerDriverTest { + @Test + fun testPowerBaseline() { + val machine = mockk() + + val driver = PStatePowerDriver( + sortedMapOf( + 2800.0 to ConstantPowerModel(200.0), + 3300.0 to ConstantPowerModel(300.0), + 3600.0 to ConstantPowerModel(350.0), + ) + ) + + val logic = driver.createLogic(machine, emptyList()) + assertEquals(200.0, logic.computePower()) + } + + @Test + fun testPowerWithSingleCpu() { + val machine = mockk() + val cpu = mockk() + + every { cpu.capacity } returns 3200.0 + every { cpu.speed } returns 1200.0 + + val driver = PStatePowerDriver( + sortedMapOf( + 2800.0 to ConstantPowerModel(200.0), + 3300.0 to ConstantPowerModel(300.0), + 3600.0 to ConstantPowerModel(350.0), + ) + ) + + val logic = driver.createLogic(machine, listOf(cpu)) + + assertEquals(300.0, logic.computePower()) + } + + @Test + fun testPowerWithMultipleCpus() { + val machine = mockk() + val cpus = listOf( + mockk(), + mockk() + ) + + every { cpus[0].capacity } returns 1000.0 + every { cpus[0].speed } returns 1200.0 + + every { cpus[1].capacity } returns 3500.0 + every { cpus[1].speed } returns 1200.0 + + val driver = PStatePowerDriver( + sortedMapOf( + 2800.0 to ConstantPowerModel(200.0), + 3300.0 to ConstantPowerModel(300.0), + 3600.0 to ConstantPowerModel(350.0), + ) + ) + + val logic = driver.createLogic(machine, cpus) + + assertEquals(350.0, logic.computePower()) + } + + @Test + fun testPowerBasedOnUtilization() { + val machine = mockk() + val cpu = mockk() + + every { cpu.model.frequency } returns 4200.0 + + val driver = PStatePowerDriver( + sortedMapOf( + 2800.0 to LinearPowerModel(200.0, 100.0), + 3300.0 to LinearPowerModel(250.0, 150.0), + 4000.0 to LinearPowerModel(300.0, 200.0), + ) + ) + + val logic = driver.createLogic(machine, listOf(cpu)) + + every { cpu.speed } returns 1400.0 + every { cpu.capacity } returns 1400.0 + assertEquals(150.0, logic.computePower()) + + every { cpu.speed } returns 1400.0 + every { cpu.capacity } returns 4000.0 + assertEquals(235.0, logic.computePower()) + } +} -- cgit v1.2.3