diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt index e6b36dba6..f8c7afbd4 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt @@ -111,7 +111,7 @@ private fun HostJSONSpec.toHostSpecs( ): HostSpec { val unknownProcessingNode = ProcessingNode("unknown", "unknown", "unknown", cpus.sumOf { it.coreCount }) - val units = cpus.flatMap { cpu -> List(cpu.count) { cpu.toProcessingUnit(unknownProcessingNode) }.flatten() } + val units = cpus.flatMap { cpu -> List(cpu.count) { cpu.toProcessingUnits(unknownProcessingNode) }.flatten() } val unknownMemoryUnit = MemoryUnit(memory.vendor, memory.modelName, memory.memorySpeed, memory.memorySize) val machineModel = @@ -140,7 +140,9 @@ private fun HostJSONSpec.toHostSpecs( */ private var globalCoreId = 0 -private fun CPUJSONSpec.toProcessingUnit(unknownProcessingNode: ProcessingNode): List { +private fun CPUJSONSpec.toProcessingUnits(unknownProcessingNode: ProcessingNode): List { val units = List(coreCount) { ProcessingUnit(unknownProcessingNode, globalCoreId++, coreSpeed) } return units + +// return listOf(ProcessingUnit(unknownProcessingNode, globalCoreId++, coreSpeed)) } diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/JSONSpecs.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/JSONSpecs.kt index 5e0af5418..8f73f524d 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/JSONSpecs.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/JSONSpecs.kt @@ -64,7 +64,7 @@ public data class HostJSONSpec( val name: String = "Host", val cpus: List, val memory: MemoryJSONSpec, - val powerModel: PowerModelJSONSpec = PowerModelJSONSpec("linear", 350.0, 200.0, 400.0), + val powerModel: PowerModelJSONSpec = PowerModelJSONSpec("linear", 350.0, 400.0, 200.0), val count: Int = 1, ) @@ -109,6 +109,10 @@ public data class MemoryJSONSpec( public data class PowerModelJSONSpec( val modelType: String, val power: Double = 400.0, - val idlePower: Double, val maxPower: Double, -) + val idlePower: Double, +) { + init { + require(maxPower >= idlePower) { "The max power of a power model can not be less than the idle power" } + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt index 2966c9346..0ab305ee9 100644 --- a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt +++ b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt @@ -125,8 +125,8 @@ class ScenarioIntegrationTest { { assertEquals(66977091124, monitor.activeTime) { "Incorrect active time" } }, { assertEquals(3160267873, monitor.stealTime) { "Incorrect steal time" } }, { assertEquals(0, monitor.lostTime) { "Incorrect lost time" } }, - { assertEquals(1.9469839319124512E7, monitor.powerDraw, 1E4) { "Incorrect power draw" } }, - { assertEquals(5.840705003360067E9, monitor.energyUsage, 1E5) { "Incorrect energy usage" } }, + { assertEquals(2.0774585843587227E7, monitor.powerDraw, 1E4) { "Incorrect power draw" } }, + { assertEquals(6.232122296636381E9, monitor.energyUsage, 1E4) { "Incorrect energy usage" } }, ) } @@ -167,8 +167,8 @@ class ScenarioIntegrationTest { { assertEquals(9741285381, monitor.activeTime) { "Active time incorrect" } }, { assertEquals(152, monitor.stealTime) { "Steal time incorrect" } }, { assertEquals(0, monitor.lostTime) { "Lost time incorrect" } }, - { assertEquals(2337040.5458753705, monitor.powerDraw, 1E4) { "Incorrect power draw" } }, - { assertEquals(7.010994945790212E8, monitor.energyUsage, 1E4) { "Incorrect energy usage" } }, + { assertEquals(2539987.394500494, monitor.powerDraw, 1E4) { "Incorrect power draw" } }, + { assertEquals(7.619825262052509E8, monitor.energyUsage, 1E4) { "Incorrect energy usage" } }, ) } diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/env/multi.json b/opendc-experiments/opendc-experiments-base/src/test/resources/env/multi.json index b87877afc..d23dbfe36 100644 --- a/opendc-experiments/opendc-experiments-base/src/test/resources/env/multi.json +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/env/multi.json @@ -16,12 +16,6 @@ ], "memory": { "memorySize": 256000 - }, - "powerModel": { - "modelType": "linear", - "power": 350.0, - "maxPower": 350.0, - "idlePower": 200.0 } } ] @@ -42,12 +36,6 @@ ], "memory": { "memorySize": 64000 - }, - "powerModel": { - "modelType": "linear", - "power": 350.0, - "maxPower": 350.0, - "idlePower": 200.0 } } ] @@ -68,12 +56,6 @@ ], "memory": { "memorySize": 128000 - }, - "powerModel": { - "modelType": "linear", - "power": 350.0, - "maxPower": 350.0, - "idlePower": 200.0 } } ] diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/env/single.json b/opendc-experiments/opendc-experiments-base/src/test/resources/env/single.json index 9862f71ad..2d68b234d 100644 --- a/opendc-experiments/opendc-experiments-base/src/test/resources/env/single.json +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/env/single.json @@ -16,12 +16,6 @@ ], "memory": { "memorySize": 128000 - }, - "powerModel": { - "modelType": "linear", - "power": 350.0, - "maxPower": 350.0, - "idlePower": 200.0 } } ] diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java index 7ba9eaed1..537fb8d85 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java @@ -163,6 +163,12 @@ private abstract static class MaxIdlePowerModel implements CpuPowerModel { this.idlePower = idlePower; } + // Clamps the provided utilization in the range of 0.0 and 1.0 + // This is done to avoid floating point errors + public double clampUtilization(double utilization) { + return Math.max(0.0, Math.min(1.0, utilization)); + } + @Override public String toString() { return getClass().getSimpleName() + "[max=" + maxPower + ",idle=" + idlePower + "]"; @@ -174,12 +180,14 @@ private static final class SqrtPowerModel extends MaxIdlePowerModel { SqrtPowerModel(double maxPower, double idlePower) { super(maxPower, idlePower); - this.factor = (maxPower - idlePower) / Math.sqrt(100); + this.factor = (maxPower - idlePower); } @Override public double computePower(double utilization) { - return idlePower + factor * Math.sqrt(utilization * 100); + utilization = clampUtilization(utilization); + + return idlePower + factor * Math.sqrt(utilization); } @Override @@ -198,12 +206,14 @@ private static final class LinearPowerModel extends MaxIdlePowerModel { LinearPowerModel(double maxPower, double idlePower) { super(maxPower, idlePower); - this.factor = (maxPower - idlePower) / 100; + this.factor = maxPower - idlePower; } @Override public double computePower(double utilization) { - return idlePower + factor * utilization * 100; + utilization = clampUtilization(utilization); + + return idlePower + factor * utilization; } @Override @@ -222,12 +232,14 @@ private static final class SquarePowerModel extends MaxIdlePowerModel { SquarePowerModel(double maxPower, double idlePower) { super(maxPower, idlePower); - this.factor = (maxPower - idlePower) / Math.pow(100, 2); + this.factor = (maxPower - idlePower); } @Override public double computePower(double utilization) { - return idlePower + factor * Math.pow(utilization * 100, 2); + utilization = clampUtilization(utilization); + + return idlePower + factor * Math.pow(utilization, 2); } @Override @@ -246,12 +258,14 @@ private static final class CubicPowerModel extends MaxIdlePowerModel { CubicPowerModel(double maxPower, double idlePower) { super(maxPower, idlePower); - this.factor = (maxPower - idlePower) / Math.pow(100, 3); + this.factor = (maxPower - idlePower); } @Override public double computePower(double utilization) { - return idlePower + factor * Math.pow(utilization * 100, 3); + utilization = clampUtilization(utilization); + + return idlePower + factor * Math.pow(utilization, 3); } @Override diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt index e85758ae5..e3bea821a 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt @@ -78,6 +78,90 @@ internal class PowerModelTest { ) } + @Test + fun `test linear model`() { + val powerModel = CpuPowerModels.linear(400.0, 200.0) + + assertAll( + { assertEquals(200.0, powerModel.computePower(-0.1)) }, + { assertEquals(200.0, powerModel.computePower(0.0)) }, + { assertEquals(220.0, powerModel.computePower(0.1)) }, + { assertEquals(240.0, powerModel.computePower(0.2)) }, + { assertEquals(260.0, powerModel.computePower(0.3)) }, + { assertEquals(280.0, powerModel.computePower(0.4)) }, + { assertEquals(300.0, powerModel.computePower(0.5)) }, + { assertEquals(320.0, powerModel.computePower(0.6)) }, + { assertEquals(340.0, powerModel.computePower(0.7)) }, + { assertEquals(360.0, powerModel.computePower(0.8)) }, + { assertEquals(380.0, powerModel.computePower(0.9)) }, + { assertEquals(400.0, powerModel.computePower(1.0)) }, + { assertEquals(400.0, powerModel.computePower(1.1)) }, + ) + } + + @Test + fun `test sqrt model`() { + val powerModel = CpuPowerModels.sqrt(400.0, 200.0) + + assertAll( + { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) }, + { assertEquals(200.0, powerModel.computePower(0.0), 1.0) }, + { assertEquals(263.0, powerModel.computePower(0.1), 1.0) }, + { assertEquals(289.0, powerModel.computePower(0.2), 1.0) }, + { assertEquals(309.0, powerModel.computePower(0.3), 1.0) }, + { assertEquals(326.0, powerModel.computePower(0.4), 1.0) }, + { assertEquals(341.0, powerModel.computePower(0.5), 1.0) }, + { assertEquals(354.0, powerModel.computePower(0.6), 1.0) }, + { assertEquals(367.0, powerModel.computePower(0.7), 1.0) }, + { assertEquals(378.0, powerModel.computePower(0.8), 1.0) }, + { assertEquals(389.0, powerModel.computePower(0.9), 1.0) }, + { assertEquals(400.0, powerModel.computePower(1.0), 1.0) }, + { assertEquals(400.0, powerModel.computePower(1.1), 1.0) }, + ) + } + + @Test + fun `test square model`() { + val powerModel = CpuPowerModels.square(400.0, 200.0) + + assertAll( + { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) }, + { assertEquals(200.0, powerModel.computePower(0.0), 1.0) }, + { assertEquals(202.0, powerModel.computePower(0.1), 1.0) }, + { assertEquals(208.0, powerModel.computePower(0.2), 1.0) }, + { assertEquals(218.0, powerModel.computePower(0.3), 1.0) }, + { assertEquals(232.0, powerModel.computePower(0.4), 1.0) }, + { assertEquals(250.0, powerModel.computePower(0.5), 1.0) }, + { assertEquals(272.0, powerModel.computePower(0.6), 1.0) }, + { assertEquals(298.0, powerModel.computePower(0.7), 1.0) }, + { assertEquals(328.0, powerModel.computePower(0.8), 1.0) }, + { assertEquals(362.0, powerModel.computePower(0.9), 1.0) }, + { assertEquals(400.0, powerModel.computePower(1.0), 1.0) }, + { assertEquals(400.0, powerModel.computePower(1.1), 1.0) }, + ) + } + + @Test + fun `test cubic model`() { + val powerModel = CpuPowerModels.cubic(400.0, 200.0) + + assertAll( + { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) }, + { assertEquals(200.0, powerModel.computePower(0.0), 1.0) }, + { assertEquals(200.0, powerModel.computePower(0.1), 1.0) }, + { assertEquals(201.0, powerModel.computePower(0.2), 1.0) }, + { assertEquals(205.0, powerModel.computePower(0.3), 1.0) }, + { assertEquals(212.0, powerModel.computePower(0.4), 1.0) }, + { assertEquals(225.0, powerModel.computePower(0.5), 1.0) }, + { assertEquals(243.0, powerModel.computePower(0.6), 1.0) }, + { assertEquals(268.0, powerModel.computePower(0.7), 1.0) }, + { assertEquals(302.0, powerModel.computePower(0.8), 1.0) }, + { assertEquals(345.0, powerModel.computePower(0.9), 1.0) }, + { assertEquals(400.0, powerModel.computePower(1.0), 1.0) }, + { assertEquals(400.0, powerModel.computePower(1.1), 1.0) }, + ) + } + @Suppress("unused") private companion object { @JvmStatic