diff options
11 files changed, 66 insertions, 225 deletions
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt index 1b9733d1..b8cb8412 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt @@ -1,8 +1,10 @@ package org.opendc.simulator.compute.power /** - * A power model which produces a constant value [constant]. + * A power model which produces a constant value [power]. */ -public class ConstantPowerModel(private val constant: Double) : PowerModel { - public override fun computePower(utilization: Double): Double = constant +public class ConstantPowerModel(private val power: Double) : PowerModel { + public override fun computePower(utilization: Double): Double = power + + override fun toString(): String = "ConstantPowerModel[power=$power]" } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt index e5bc013c..48edace6 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt @@ -5,21 +5,15 @@ import kotlin.math.pow /** * The cubic power model partially adapted from CloudSim. * - * @param maxPower The maximum power draw in Watts of the server. - * @param staticPowerPercent The static power percentage. - * @property staticPower The static power consumption that is not dependent on resource usage. - * It is the amount of energy consumed even when the host is idle. - * @property constPower The constant power consumption for each fraction of resource used. + * @param maxPower The maximum power draw of the server in W. + * @param idlePower The power draw of the server in idle state in W. */ -public class CubicPowerModel( - private var maxPower: Double, - staticPowerPercent: Double -) : PowerModel { - private var staticPower: Double = staticPowerPercent * maxPower - private var constPower: Double = (maxPower - staticPower) / 100.0.pow(3) +public class CubicPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel { + private val factor: Double = (maxPower - idlePower) / 100.0.pow(3) public override fun computePower(utilization: Double): Double { - require(utilization in 0.0..1.0) { "CPU utilization must be in [0, 1]" } - return staticPower + constPower * (utilization * 100).pow(3) + return idlePower + factor * (utilization * 100).pow(3) } + + override fun toString(): String = "CubicPowerModel[max=$maxPower,idle=$idlePower]" } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt index ce9b8197..85613a57 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt @@ -3,6 +3,8 @@ package org.opendc.simulator.compute.power import org.yaml.snakeyaml.Yaml import kotlin.math.ceil import kotlin.math.floor +import kotlin.math.max +import kotlin.math.min /** * The linear interpolation power model partially adapted from CloudSim. @@ -10,30 +12,30 @@ import kotlin.math.floor * * @param hardwareName The name of the hardware vendor. * @see <a href="http://www.spec.org/power_ssj2008/results/res2011q1/">Machines used in the SPEC benchmark</a> - * @property averagePowerValues A [List] of average active power measured by the power analyzer(s) - * and accumulated by the PTDaemon (Power and Temperature Daemon) for this - * measurement interval, displayed as watts (W). */ -public class InterpolationPowerModel( - hardwareName: String, -) : PowerModel { +public class InterpolationPowerModel(hardwareName: String) : PowerModel { + /** + * A [List] of average active power measured by the power analyzer(s) and accumulated by the + * PTDaemon (Power and Temperature Daemon) for this measurement interval, displayed as watts (W). + */ private val averagePowerValues: List<Double> = loadAveragePowerValue(hardwareName) public override fun computePower(utilization: Double): Double { - require(utilization in 0.0..1.0) { "CPU utilization must be in [0, 1]" } - - val cpuUtilFlr = floor(utilization * 10).toInt() - val cpuUtilCil = ceil(utilization * 10).toInt() - val powerFlr: Double = getAveragePowerValue(cpuUtilFlr) - val powerCil: Double = getAveragePowerValue(cpuUtilCil) + val clampedUtilization = min(1.0, max(0.0, utilization)) + val utilizationFlr = floor(clampedUtilization * 10).toInt() + val utilizationCil = ceil(clampedUtilization * 10).toInt() + val powerFlr: Double = getAveragePowerValue(utilizationFlr) + val powerCil: Double = getAveragePowerValue(utilizationCil) val delta = (powerCil - powerFlr) / 10 return if (utilization % 0.1 == 0.0) - getAveragePowerValue((utilization * 10).toInt()) + getAveragePowerValue((clampedUtilization * 10).toInt()) else - powerFlr + delta * (utilization - cpuUtilFlr.toDouble() / 10) * 100 + powerFlr + delta * (clampedUtilization - utilizationFlr.toDouble() / 10) * 100 } + override fun toString(): String = "InterpolationPowerModel[entries=${averagePowerValues.size}]" + /** * Gets the power consumption for a given utilization percentage. * diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt index 56a75bb6..1a0cc07b 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt @@ -3,21 +3,18 @@ package org.opendc.simulator.compute.power /** * The linear power model partially adapted from CloudSim. * - * @param maxPower The maximum power draw in Watts of the server. - * @param staticPowerPercent The static power percentage. - * @property staticPower The static power consumption that is not dependent on resource usage. - * It is the amount of energy consumed even when the host is idle. - * @property constPower The constant power consumption for each fraction of resource used. + * @param maxPower The maximum power draw of the server in W. + * @param idlePower The power draw of the server in idle state in W. */ -public class LinearPowerModel( - private var maxPower: Double, - staticPowerPercent: Double -) : PowerModel { - private var staticPower: Double = staticPowerPercent * maxPower - private var constPower: Double = (maxPower - staticPower) / 100 +public class LinearPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel { + /** + * The linear interpolation factor of the model. + */ + private val factor: Double = (maxPower - idlePower) / 100 public override fun computePower(utilization: Double): Double { - require(utilization in 0.0..1.0) { "CPU utilization must be in [0, 1]" } - return staticPower + constPower * utilization * 100 + return idlePower + factor * utilization * 100 } + + override fun toString(): String = "LinearPowerModel[max=$maxPower,idle=$idlePower]" } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerModel.kt deleted file mode 100644 index 722f478d..00000000 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerModel.kt +++ /dev/null @@ -1,96 +0,0 @@ -package org.opendc.simulator.compute.power - -import org.opendc.simulator.compute.SimBareMetalMachine -import java.time.Clock -import java.util.* - -/** - * The CPU power model derived from the iCanCloud simulator. - * - * @param machine The [SimBareMetalMachine] that the model is measuring. - * @param clock The virtual [Clock] to track the time spent at each p-state. - * @property cpuPowerMeter A [MutableMap] that contains CPU frequencies ([Double]) in GHz - * as keys and the time ([Long]) spent in that frequency range in seconds. - * @property pStatesToPower A [TreeMap] that contains the frequency ([Double]) of corresponding p-state in GHz - * as keys and the energy ([Double]) consumption of that state in Watts. - * @property pStatesRange A [Pair] in which the fist and second elements are the lower and upper bounds of the - * consumption values of the p-states respectively. - * @property lastMeasureTime The last update time of the [cpuPowerMeter]. - * @property currPState The p-state that the model is currently in. - */ -public class PStatePowerModel( - private val machine: SimBareMetalMachine, - private val clock: Clock, -) { - // TODO: Extract the power meter out of the model. - private val cpuPowerMeter = mutableMapOf<Double, Long>() - private val pStatesToPower = TreeMap<Double, Double>() - private val pStatesRange: Pair<Double, Double> - private var lastMeasureTime: Long - private var currPState: Double - - init { - loadPStates(this) - pStatesRange = Pair(pStatesToPower.keys.first(), pStatesToPower.keys.last()) - pStatesToPower.keys.forEach { cpuPowerMeter[it] = 0L } - currPState = pStatesRange.first - lastMeasureTime = getClockInstant() - updateCpuPowerMeter() - } - - /** Recorde the elapsed time to the corresponding p-state. */ - public fun updateCpuPowerMeter() { - val newMeasureTime = getClockInstant() - val newMaxFreq: Double = getMaxCpuSpeedInGHz() - assert(newMaxFreq in pStatesRange.first..pStatesRange.second) { - "The maximum frequency $newMaxFreq is not in the range of the P-state frequency " + - "from ${pStatesRange.first} to ${pStatesRange.second}." - } - - // Update the current p-state level on which the CPU is running. - val newPState = pStatesToPower.ceilingKey(newMaxFreq) - - // Add the time elapsed to the previous state. - cpuPowerMeter.merge(currPState, newMeasureTime - lastMeasureTime, Long::plus) - - // Update the current states. - currPState = newPState - lastMeasureTime = newMeasureTime - } - - /** Get the power value of the energy consumption level at which the CPU is working. */ - public fun getInstantCpuPower(): Double = - pStatesToPower.getOrDefault(currPState, 0.0) - - /** Get the accumulated power consumption up until now. */ - public fun getAccumulatedCpuPower(): Double = - pStatesToPower.keys - .map { - pStatesToPower.getOrDefault(it, 0.0) * - cpuPowerMeter.getOrDefault(it, 0.0).toDouble() - }.sum() - - private fun getClockInstant() = clock.millis() / 1000 - - /** Get the maximum frequency of the CPUs in GHz as that of the package. - * @see <a href="https://www.intel.vn/content/dam/www/public/us/en/documents/datasheets/10th-gen-core-families-datasheet-vol-1-datasheet.pdf"> - * on page 34. - */ - private fun getMaxCpuSpeedInGHz() = (machine.speed.maxOrNull() ?: 0.0) / 1000 - - public companion object PStatesLoader { - private fun loadPStates(pStatePowerModel: PStatePowerModel) { - // TODO: Dynamically load configuration. - // See P4 of https://www.intel.com/content/dam/support/us/en/documents/motherboards/server/sb/power_management_of_intel_architecture_servers.pdf - pStatePowerModel.pStatesToPower.putAll( - sortedMapOf( - 3.6 to 103.0, - 3.4 to 94.0, - 3.2 to 85.0, - 3.0 to 76.0, - 2.8 to 8.0, - ) - ) - } - } -} diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt index 19dff88c..1387e65a 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt @@ -7,10 +7,10 @@ import org.opendc.simulator.compute.SimMachine */ public interface PowerModel { /** - * Compute the power consumption of the CPU based on its utilization. + * Computes CPU power consumption for each host. * - * @param utilization The CPU utilization percentage in [0, 1]. - * @return The power consumption of the CPU in terms of watts (W). + * @param utilization The CPU utilization percentage. + * @return A [Double] value of CPU power consumption. */ public fun computePower(utilization: Double): Double } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt index b78421d8..da40ca85 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt @@ -5,21 +5,15 @@ import kotlin.math.sqrt /** * The square root power model partially adapted from CloudSim. * - * @param maxPower The maximum power draw in Watts of the server. - * @param staticPowerPercent The static power percentage. - * @property staticPower The static power consumption that is not dependent on resource usage. - * It is the amount of energy consumed even when the host is idle. - * @property constPower The constant power consumption for each fraction of resource used. + * @param maxPower The maximum power draw of the server in W. + * @param idlePower The power draw of the server in idle state in W. */ -public class SqrtPowerModel( - private var maxPower: Double, - staticPowerPercent: Double -) : PowerModel { - private var staticPower: Double = staticPowerPercent * maxPower - private var constPower: Double = (maxPower - staticPower) / sqrt(100.0) +public class SqrtPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel { + private val factor: Double = (maxPower - idlePower) / sqrt(100.0) override fun computePower(utilization: Double): Double { - require(utilization in 0.0..1.0) { "CPU utilization must be in [0, 1]" } - return staticPower + constPower * sqrt(utilization * 100) + return idlePower + factor * sqrt(utilization * 100) } + + override fun toString(): String = "SqrtPowerModel[max=$maxPower,idle=$idlePower]" } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt index b5953daa..4f914ddf 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt @@ -5,21 +5,15 @@ import kotlin.math.pow /** * The square power model partially adapted from CloudSim. * - * @param maxPower The maximum power draw in Watts of the server. - * @param staticPowerPercent The static power percentage. - * @property staticPower The static power consumption that is not dependent on resource usage. - * It is the amount of energy consumed even when the host is idle. - * @property constPower The constant power consumption for each fraction of resource used. + * @param maxPower The maximum power draw of the server in W. + * @param idlePower The power draw of the server in idle state in W. */ -public class SquarePowerModel( - private var maxPower: Double, - staticPowerPercent: Double -) : PowerModel { - private var staticPower: Double = staticPowerPercent * maxPower - private var constPower: Double = (maxPower - staticPower) / 100.0.pow(2) +public class SquarePowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel { + private val factor: Double = (maxPower - idlePower) / 100.0.pow(2) override fun computePower(utilization: Double): Double { - require(utilization in 0.0..1.0) { "CPU utilization must be in [0, 1]" } - return staticPower + constPower * (utilization * 100).pow(2) + return idlePower + factor * (utilization * 100).pow(2) } + + override fun toString(): String = "SquarePowerModel[max=$maxPower,idle=$idlePower]" } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt index 50f04a4f..19dfcadd 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt @@ -7,6 +7,11 @@ package org.opendc.simulator.compute.power */ public class ZeroIdlePowerDecorator(private val delegate: PowerModel) : PowerModel { override fun computePower(utilization: Double): Double { - return if (utilization == 0.0) 0.0 else delegate.computePower(utilization) + return if (utilization == 0.0) + 0.0 + else + delegate.computePower(utilization) } + + override fun toString(): String = "ZeroIdlePowerDecorator[delegate=$delegate]" } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerModelTest.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerModelTest.kt deleted file mode 100644 index 9116f928..00000000 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerModelTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.opendc.simulator.compute.power - -import io.mockk.* -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.opendc.simulator.compute.SimBareMetalMachine -import java.time.Clock - -internal class PStatePowerModelTest { - @Test - fun `update CPU power meter with P-states`() { - val p0Power = 8.0 - val p3Power = 94.0 - val p4Power = 103.0 - val expectedP0Power = 8.0 * 10 - val expectedP0P4Power = expectedP0Power + 103.0 * 10 - - val clock = mockkClass(Clock::class) - val machine = mockkClass(SimBareMetalMachine::class) - every { clock.millis() } returnsMany listOf(0L, 0L, 10_000L, 20_000L) - every { machine.speed } returns - listOf(2.8, 2.8, 2.8, 2.8).map { it * 1000 } andThen // Max. 2.8MHz covered by P0 - listOf(1.5, 3.1, 3.3, 3.6).map { it * 1000 } andThen // Max. 3.6MHz covered by P4 - listOf(1.5, 3.1, 3.1, 3.3).map { it * 1000 } // Max. 3.3MHz covered by P3 - - // Power meter initialization. - val pStatePowerModel = PStatePowerModel(machine, clock) - verify(exactly = 2) { clock.millis() } - verify(exactly = 1) { machine.speed } - assertEquals(p0Power, pStatePowerModel.getInstantCpuPower()) - - // The first measure. - pStatePowerModel.updateCpuPowerMeter() - assertEquals(p4Power, pStatePowerModel.getInstantCpuPower()) - assertEquals(expectedP0Power, pStatePowerModel.getAccumulatedCpuPower()) - - // The second measure. - pStatePowerModel.updateCpuPowerMeter() - assertEquals(p3Power, pStatePowerModel.getInstantCpuPower()) - assertEquals(expectedP0P4Power, pStatePowerModel.getAccumulatedCpuPower()) - - verify(exactly = 4) { clock.millis() } - } -} diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/MachinePowerModelTest.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt index f42e2e73..8ec9910c 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/MachinePowerModelTest.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt @@ -1,6 +1,5 @@ package org.opendc.simulator.compute.power -import kotlinx.coroutines.ExperimentalCoroutinesApi import org.junit.jupiter.api.Assertions.assertAll import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -11,8 +10,7 @@ import org.junit.jupiter.params.provider.MethodSource import java.util.stream.Stream import kotlin.math.pow -@OptIn(ExperimentalCoroutinesApi::class) -internal class MachinePowerModelTest { +internal class PowerModelTest { private val epsilon = 10.0.pow(-3) private val cpuUtil = 0.9 @@ -42,11 +40,6 @@ internal class MachinePowerModelTest { val powerModel = InterpolationPowerModel("IBMx3550M3_XeonX5675") assertAll( - { assertThrows<IllegalArgumentException> { powerModel.computePower(-1.3) } }, - { assertThrows<IllegalArgumentException> { powerModel.computePower(1.3) } }, - ) - - assertAll( { assertEquals(58.4, powerModel.computePower(0.0)) }, { assertEquals(58.4 + (98 - 58.4) / 5, powerModel.computePower(0.02)) }, { assertEquals(98.0, powerModel.computePower(0.1)) }, @@ -63,10 +56,10 @@ internal class MachinePowerModelTest { @JvmStatic fun MachinePowerModelArgs(): Stream<Arguments> = Stream.of( Arguments.of(ConstantPowerModel(0.0), 0.0), - Arguments.of(LinearPowerModel(350.0, 200 / 350.0), 335.0), - Arguments.of(SquarePowerModel(350.0, 200 / 350.0), 321.5), - Arguments.of(CubicPowerModel(350.0, 200 / 350.0), 309.35), - Arguments.of(SqrtPowerModel(350.0, 200 / 350.0), 342.302), + Arguments.of(LinearPowerModel(350.0, 200.0), 335.0), + Arguments.of(SquarePowerModel(350.0, 200.0), 321.5), + Arguments.of(CubicPowerModel(350.0, 200.0), 309.35), + Arguments.of(SqrtPowerModel(350.0, 200.0), 342.302), ) } } |
