diff options
20 files changed, 871 insertions, 15 deletions
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 c1617304..fd66ca11 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 @@ -32,6 +32,7 @@ import org.opendc.compute.topology.specs.HostSpec import org.opendc.compute.topology.specs.PowerSourceSpec import org.opendc.compute.topology.specs.TopologySpec import org.opendc.compute.topology.specs.toDistributionPolicy +import org.opendc.compute.topology.specs.toVirtualizationOverheadModel import org.opendc.simulator.compute.models.CpuModel import org.opendc.simulator.compute.models.GpuModel import org.opendc.simulator.compute.models.MachineModel @@ -171,6 +172,7 @@ private fun HostJSONSpec.toHostSpec(clusterName: String): HostSpec { val unknownMemoryUnit = MemoryUnit(memory.vendor, memory.modelName, memory.memorySpeed.toMHz(), memory.memorySize.toMiB().toLong()) val gpuUnits = List(gpu?.count ?: 0) { + val virtualizationOverheadModel = gpu?.virtualizationOverHeadModel?.toVirtualizationOverheadModel() GpuModel( globalGpuId++, gpu!!.coreCount, @@ -180,6 +182,7 @@ private fun HostJSONSpec.toHostSpec(clusterName: String): HostSpec { gpu.vendor, gpu.modelName, gpu.architecture, + virtualizationOverheadModel, ) } diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt index f5c8ab31..667e9cbd 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt @@ -35,6 +35,7 @@ import org.opendc.simulator.compute.power.batteries.policy.DoubleThresholdBatter import org.opendc.simulator.compute.power.batteries.policy.RunningMeanBatteryPolicy import org.opendc.simulator.compute.power.batteries.policy.RunningMeanPlusBatteryPolicy import org.opendc.simulator.compute.power.batteries.policy.SingleThresholdBatteryPolicy +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModelFactory.VirtualizationOverheadModelEnum import org.opendc.simulator.engine.engine.FlowEngine import org.opendc.simulator.engine.graph.distributionPolicies.FlowDistributorFactory.DistributionPolicy @@ -69,8 +70,12 @@ public data class ClusterJSONSpec( * @param name The name of the host. * @param cpu The CPU available in this cluster * @param memory The amount of RAM memory available in Byte - * @param powerModel The power model used to determine the power draw of a host * @param count The power model used to determine the power draw of a host + * @param gpu The GPU available in this cluster (optional) + * @param cpuPowerModel The power model used to determine the power draw of the CPU + * @param gpuPowerModel The power model used to determine the power draw of the GPU + * @param cpuDistributionPolicy The distribution policy used to distribute CPU resources + * @param gpuDistributionPolicy The distribution policy used to distribute GPU resources */ @Serializable public data class HostJSONSpec( @@ -133,6 +138,7 @@ public data class GPUJSONSpec( val vendor: String = "unknown", val modelName: String = "unknown", val architecture: String = "unknown", + val virtualizationOverHeadModel: VirtualizationOverheadModelSpec = NoVirtualizationOverheadModelSpec(), ) @Serializable @@ -216,6 +222,48 @@ public data class MaxMinFairnessDistributionPolicySpec( override val type: DistributionPolicy = DistributionPolicy.MAX_MIN_FAIRNESS, ) : DistributionPolicySpec +@Serializable +public sealed interface VirtualizationOverheadModelSpec { + public val type: VirtualizationOverheadModelEnum +} + +@Serializable +@SerialName("NONE") +public data class NoVirtualizationOverheadModelSpec( + override val type: VirtualizationOverheadModelEnum = + VirtualizationOverheadModelEnum.NONE, +) : VirtualizationOverheadModelSpec + +@Serializable +@SerialName("CONSTANT") +public data class ConstantVirtualizationOverheadModelSpec( + override val type: VirtualizationOverheadModelEnum = VirtualizationOverheadModelEnum.CONSTANT, + val percentageOverhead: Double? = -1.0, +) : VirtualizationOverheadModelSpec + +@Serializable +@SerialName("SHARE_BASED") +public data class ShareBasedVirtualizationOverheadModelSpec( + override val type: VirtualizationOverheadModelEnum = VirtualizationOverheadModelEnum.SHARE_BASED, +) : VirtualizationOverheadModelSpec + +public fun VirtualizationOverheadModelSpec.toVirtualizationOverheadModel(): VirtualizationOverheadModelEnum { + return when (this) { + is NoVirtualizationOverheadModelSpec -> VirtualizationOverheadModelEnum.NONE + is ConstantVirtualizationOverheadModelSpec -> + VirtualizationOverheadModelEnum.CONSTANT.apply { + if (percentageOverhead != null) { + // -1.0 is used to indicate that no percentage overhead is specified + if (percentageOverhead != -1.0 && (percentageOverhead < 0.0 || percentageOverhead > 1.0)) { + throw IllegalArgumentException("Percentage overhead must be between 0.0 and 1.0") + } + setProperty("percentageOverhead", percentageOverhead) + } + } + is ShareBasedVirtualizationOverheadModelSpec -> VirtualizationOverheadModelEnum.SHARE_BASED + } +} + /** * Definition of a power source used for JSON input. * diff --git a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/VirtualizationOverheadTests.kt b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/VirtualizationOverheadTests.kt new file mode 100644 index 00000000..18936a15 --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/VirtualizationOverheadTests.kt @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2024 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.experiments.base + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertInstanceOf +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertAll +import org.opendc.compute.workload.Task +import org.opendc.simulator.compute.virtualization.OverheadModels.ConstantVirtualizationOverhead +import org.opendc.simulator.compute.virtualization.OverheadModels.NoVirtualizationOverHead +import org.opendc.simulator.compute.virtualization.OverheadModels.ShareBasedVirtualizationOverhead +import org.opendc.simulator.compute.workload.trace.TraceFragment +import java.util.ArrayList + +class VirtualizationOverheadTests { + /** + * Test that the different virtualization overhead models are loaded correctly from a topology file. + */ + @Test + fun loadsVirtualizationOverheadModelCorrectly() { + val noModelTopology = createTopology("virtualizationOverhead/single_gpu_no_model.json") + val noOverHeadTopology = createTopology("virtualizationOverhead/single_gpu_no_overhead.json") + val constantOverHeadTopology = createTopology("virtualizationOverhead/single_gpu_constant_overhead.json") + val customConstantOverHeadTopology = createTopology("virtualizationOverhead/single_gpu_custom_constant_overhead.json") + val shareBasedOverheadTopology = createTopology("virtualizationOverhead/single_gpu_share_based_overhead.json") + + assertAll( + { + assertInstanceOf( + NoVirtualizationOverHead::class.java, + noModelTopology[0].hostSpecs[0].model.gpuModels[0].virtualizationOverheadModel, + "Did not load default model correctly, when no model was given.", + ) + }, + // no overhead + { + assertInstanceOf( + NoVirtualizationOverHead::class.java, + noOverHeadTopology[0].hostSpecs[0].model.gpuModels[0].virtualizationOverheadModel, + "Did not load no overhead model correctly.", + ) + }, + // default constant overhead + { + assertInstanceOf( + ConstantVirtualizationOverhead::class.java, + constantOverHeadTopology[0].hostSpecs[0].model.gpuModels[0].virtualizationOverheadModel, + "Did not load constant overhead model correctly.", + ) + }, + { + assertEquals( + 0.05, + ( + constantOverHeadTopology[0].hostSpecs[0].model.gpuModels[0].virtualizationOverheadModel + as ConstantVirtualizationOverhead + ).percentageOverhead, + "Constant overhead should have 5% overhead", + ) + }, + // custom constant overhead + { + assertInstanceOf( + ConstantVirtualizationOverhead::class.java, + customConstantOverHeadTopology[0].hostSpecs[0].model.gpuModels[0].virtualizationOverheadModel, + "Did not load constant overhead model correctly, when overhead factor was given.", + ) + }, + { + assertEquals( + 0.25, + ( + customConstantOverHeadTopology[0].hostSpecs[0].model.gpuModels[0].virtualizationOverheadModel + as ConstantVirtualizationOverhead + ).percentageOverhead, + "Custom constant overhead should have 25% overhead", + ) + }, + // share-based overhead + { + assertInstanceOf( + ShareBasedVirtualizationOverhead::class.java, + shareBasedOverheadTopology[0].hostSpecs[0].model.gpuModels[0].virtualizationOverheadModel, + "Did not load shared based overhead model correctly", + ) + }, + ) + } + + /** + * Test that the NoVirtualizationOverhead model does not apply any overhead. + */ + @Test + fun noVirtualizationOverheadModelTest() { + val topology = createTopology("virtualizationOverhead/single_gpu_no_overhead.json") + val workload: ArrayList<Task> = + arrayListOf( + createTestTask( + name = "0", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 1000.0, 1, 1000.0, 1), + ), + ), + ) + + val monitor = runTest(topology, workload) + assertEquals(1000.0, monitor.taskGpuDemands["0"]?.get(1), "Task 0 should have gpu demand 1000.0") + assertEquals(1000.0, monitor.taskGpuSupplied["0"]?.get(1), "Task 0 should have gpu supplied 1000.0 ") + assertEquals(1000.0, monitor.hostGpuDemands["H01"]?.get(1)?.get(0), "Host H01 should have gpu demand 1000.0") + assertEquals(1000.0, monitor.hostGpuSupplied["H01"]?.get(1)?.get(0), "Host H01 should have gpu supply 1000.0") + } + + /** + * Test that the constant overhead model does apply the correct amount of overhead. + */ + @Test + fun constantVirtualizationOverheadModelTest() { + val topology = createTopology("virtualizationOverhead/single_gpu_constant_overhead.json") + val workload: ArrayList<Task> = + arrayListOf( + createTestTask( + name = "0", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 1000.0, 1, 1000.0, 1), + ), + ), + ) + + val monitor = runTest(topology, workload) + assertAll( + { assertEquals(1000.0, monitor.taskGpuDemands["0"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(0.95 * 1000.0, monitor.taskGpuSupplied["0"]?.get(1), "Task 0 should have gpu supplied 950.0 ") }, + { assertEquals(1000.0, monitor.hostGpuDemands["H01"]?.get(1)?.get(0), "Host H01 should have gpu demand 1000.0") }, + { assertEquals(0.95 * 1000.0, monitor.hostGpuSupplied["H01"]?.get(1)?.get(0), "Host H01 should have gpu supply 950.0") }, + ) + } + + /** + * Test that the custom constant overhead model does not apply the correct amount of overhead. + */ + @Test + fun customConstantVirtualizationOverheadModelTest() { + val topology = createTopology("virtualizationOverhead/single_gpu_custom_constant_overhead.json") + val workload: ArrayList<Task> = + arrayListOf( + createTestTask( + name = "0", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 1000.0, 1, 1000.0, 1), + ), + ), + ) + + val monitor = runTest(topology, workload) + assertAll( + { assertEquals(1000.0, monitor.taskGpuDemands["0"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(0.75 * 1000.0, monitor.taskGpuSupplied["0"]?.get(1), "Task 0 should have gpu supplied 750.0 ") }, + { assertEquals(1000.0, monitor.hostGpuDemands["H01"]?.get(1)?.get(0), "Host H01 should have gpu demand 1000.0") }, + { assertEquals(0.75 * 1000.0, monitor.hostGpuSupplied["H01"]?.get(1)?.get(0), "Host H01 should have gpu supply 750.0") }, + ) + } + + /** + * Test that the share-based overhead model does not applies the correct amount of overhead, depending on the number of VMs. + */ + @Test + fun shareBasedVirtualizationOverheadModelTest() { + val topology = createTopology("virtualizationOverhead/single_gpu_share_based_overhead.json") + val workload1: ArrayList<Task> = + arrayListOf( + createTestTask( + name = "0", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 1000.0, 1, 1000.0, 1), + ), + ), + ) + + val workload2: ArrayList<Task> = + arrayListOf( + createTestTask( + name = "0", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 0.0, 0, 1000.0, 1), + ), + ), + createTestTask( + name = "1", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 0.0, 0, 1000.0, 1), + ), + ), + ) + + val workload3: ArrayList<Task> = + arrayListOf( + createTestTask( + name = "0", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 0.0, 0, 1000.0, 1), + ), + ), + createTestTask( + name = "1", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 0.0, 0, 1000.0, 1), + ), + ), + createTestTask( + name = "2", + fragments = + arrayListOf( + TraceFragment(10 * 60 * 1000, 0.0, 0, 1000.0, 1), + ), + ), + ) + + val monitor1 = runTest(topology, workload1) + val monitor2 = runTest(topology, workload2) + val monitor3 = runTest(topology, workload3) + + assertAll( + // Test with one VM + { assertEquals(1000.0, monitor1.taskGpuDemands["0"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(1000.0, monitor1.taskGpuSupplied["0"]?.get(1), "Task 0 should have gpu supplied 1000.0 ") }, + { assertEquals(1000.0, monitor1.hostGpuDemands["H01"]?.get(1)?.get(0), "Host H01 should have gpu demand 1000.0") }, + { assertEquals(1000.0, monitor1.hostGpuSupplied["H01"]?.get(1)?.get(0), "Host H01 should have gpu supply 1000.0") }, + // Test with two VMs + { assertEquals(1000.0, monitor2.taskGpuDemands["0"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(500.0, monitor2.taskGpuSupplied["0"]?.get(1), "Task 0 should have gpu supplied 500.0") }, + { assertEquals(1000.0, monitor2.taskGpuDemands["1"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(500.0, monitor2.taskGpuSupplied["1"]?.get(1), "Task 0 should have gpu supplied 500.0") }, + { assertEquals(2000.0, monitor2.hostGpuDemands["H01"]?.get(1)?.get(0), "Host H01 should have gpu demand 2000.0") }, + { assertEquals(1000.0, monitor2.hostGpuSupplied["H01"]?.get(1)?.get(0), "Host H01 should have gpu supply 1000.0") }, + // Test with three VMs + { assertEquals(1000.0, monitor3.taskGpuDemands["0"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(333.3, monitor3.taskGpuSupplied["0"]?.get(1) ?: 0.0, 0.05, "Task 0 should have gpu supplied 333.3 ") }, + { assertEquals(1000.0, monitor3.taskGpuDemands["1"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(333.3, monitor3.taskGpuSupplied["1"]?.get(1) ?: 0.0, 0.05, "Task 0 should have gpu supplied 333.3 ") }, + { assertEquals(1000.0, monitor3.taskGpuDemands["2"]?.get(1), "Task 0 should have gpu demand 1000.0") }, + { assertEquals(333.3, monitor3.taskGpuSupplied["2"]?.get(1) ?: 0.0, 0.05, "Task 0 should have gpu supplied 333.3 ") }, + { assertEquals(3000.0, monitor3.hostGpuDemands["H01"]?.get(1)?.get(0), "Host H01 should have gpu demand 3000.0") }, + { assertEquals(1000.0, monitor3.hostGpuSupplied["H01"]?.get(1)?.get(0), "Host H01 should have gpu supply 700.0") }, + ) + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/Gpus/single_gpu_full.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/Gpus/single_gpu_full.json index 8e4c3546..d3e897bd 100644 --- a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/Gpus/single_gpu_full.json +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/Gpus/single_gpu_full.json @@ -29,7 +29,10 @@ "memoryBandwidth": "900 GBps", "vendor": "NVIDIA", "modelName": "Tesla V100", - "architecture": "Volta" + "architecture": "Volta", + "virtualizationOverHeadModel": { + "type": "CONSTANT" + } }, "gpuPowerModel": { "modelType": "linear", diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_constant_overhead.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_constant_overhead.json new file mode 100644 index 00000000..d3651cba --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_constant_overhead.json @@ -0,0 +1,42 @@ +{ + "clusters": + [ + { + "name": "C01", + "hosts" : + [ + { + "name": "H01", + "cpu": + { + "coreCount": 1, + "coreSpeed": 2000 + }, + "memory": { + "memorySize": 140457600000 + }, + "cpuPowerModel": { + "modelType": "linear", + "power": 400.0, + "idlePower": 100.0, + "maxPower": 200.0 + }, + "gpu": + { + "coreCount": 3, + "coreSpeed": 2000, + "virtualizationOverHeadModel": { + "type": "CONSTANT" + } + }, + "gpuPowerModel": { + "modelType": "linear", + "power": 800.0, + "idlePower": 300.0, + "maxPower": 600.0 + } + } + ] + } + ] +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_custom_constant_overhead.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_custom_constant_overhead.json new file mode 100644 index 00000000..db30608e --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_custom_constant_overhead.json @@ -0,0 +1,43 @@ +{ + "clusters": + [ + { + "name": "C01", + "hosts" : + [ + { + "name": "H01", + "cpu": + { + "coreCount": 1, + "coreSpeed": 2000 + }, + "memory": { + "memorySize": 140457600000 + }, + "cpuPowerModel": { + "modelType": "linear", + "power": 400.0, + "idlePower": 100.0, + "maxPower": 200.0 + }, + "gpu": + { + "coreCount": 3, + "coreSpeed": 2000, + "virtualizationOverHeadModel": { + "type": "CONSTANT", + "percentageOverhead": 0.25 + } + }, + "gpuPowerModel": { + "modelType": "linear", + "power": 800.0, + "idlePower": 300.0, + "maxPower": 600.0 + } + } + ] + } + ] +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_no_model.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_no_model.json new file mode 100644 index 00000000..e272e924 --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_no_model.json @@ -0,0 +1,39 @@ +{ + "clusters": + [ + { + "name": "C01", + "hosts" : + [ + { + "name": "H01", + "cpu": + { + "coreCount": 1, + "coreSpeed": 2000 + }, + "memory": { + "memorySize": 140457600000 + }, + "cpuPowerModel": { + "modelType": "linear", + "power": 400.0, + "idlePower": 100.0, + "maxPower": 200.0 + }, + "gpu": + { + "coreCount": 3, + "coreSpeed": 2000 + }, + "gpuPowerModel": { + "modelType": "linear", + "power": 800.0, + "idlePower": 300.0, + "maxPower": 600.0 + } + } + ] + } + ] +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_no_overhead.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_no_overhead.json new file mode 100644 index 00000000..f4cc893d --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_no_overhead.json @@ -0,0 +1,42 @@ +{ + "clusters": + [ + { + "name": "C01", + "hosts" : + [ + { + "name": "H01", + "cpu": + { + "coreCount": 1, + "coreSpeed": 2000 + }, + "memory": { + "memorySize": 140457600000 + }, + "cpuPowerModel": { + "modelType": "linear", + "power": 400.0, + "idlePower": 100.0, + "maxPower": 200.0 + }, + "gpu": + { + "coreCount": 3, + "coreSpeed": 2000, + "virtualizationOverHeadModel": { + "type": "NONE" + } + }, + "gpuPowerModel": { + "modelType": "linear", + "power": 800.0, + "idlePower": 300.0, + "maxPower": 600.0 + } + } + ] + } + ] +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_share_based_overhead.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_share_based_overhead.json new file mode 100644 index 00000000..00fb665f --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/virtualizationOverhead/single_gpu_share_based_overhead.json @@ -0,0 +1,42 @@ +{ + "clusters": + [ + { + "name": "C01", + "hosts" : + [ + { + "name": "H01", + "cpu": + { + "coreCount": 1, + "coreSpeed": 2000 + }, + "memory": { + "memorySize": 140457600000 + }, + "cpuPowerModel": { + "modelType": "linear", + "power": 400.0, + "idlePower": 100.0, + "maxPower": 200.0 + }, + "gpu": + { + "coreCount": 3, + "coreSpeed": 1000, + "virtualizationOverHeadModel": { + "type": "SHARE_BASED" + } + }, + "gpuPowerModel": { + "modelType": "linear", + "power": 800.0, + "idlePower": 300.0, + "maxPower": 600.0 + } + } + ] + } + ] +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/gpu/SimGpu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/gpu/SimGpu.java index c5778dc0..99317a08 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/gpu/SimGpu.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/gpu/SimGpu.java @@ -29,6 +29,7 @@ import org.opendc.simulator.compute.ComputeResource; import org.opendc.simulator.compute.machine.PerformanceCounters; import org.opendc.simulator.compute.models.GpuModel; import org.opendc.simulator.compute.power.PowerModel; +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModel; import org.opendc.simulator.engine.engine.FlowEngine; import org.opendc.simulator.engine.graph.FlowConsumer; import org.opendc.simulator.engine.graph.FlowEdge; @@ -47,12 +48,12 @@ public final class SimGpu extends FlowNode implements FlowSupplier, FlowConsumer private final PowerModel gpuPowerModel; - private double currentGpuDemand = 0.0f; // cpu capacity demanded by the mux + private double currentGpuDemand = 0.0f; // gpu capacity demanded by the mux private double currentGpuUtilization = 0.0f; - private double currentGpuSupplied = 0.0f; // cpu capacity supplied to the mux + private double currentGpuSupplied = 0.0f; // gpu capacity supplied to the mux private double currentPowerDemand; // power demanded of the psu - private double currentPowerSupplied = 0.0f; // cpu capacity supplied by the psu + private double currentPowerSupplied = 0.0f; // gpu capacity supplied by the psu private double maxCapacity; @@ -60,6 +61,9 @@ public final class SimGpu extends FlowNode implements FlowSupplier, FlowConsumer private long lastCounterUpdate; private final double gpuFrequencyInv; + private final VirtualizationOverheadModel virtualizationOverheadModel; + private int consumerCount = 0; // Number of consumers connected to this GPU + private FlowEdge distributorEdge; private FlowEdge psuEdge; @@ -110,7 +114,12 @@ public final class SimGpu extends FlowNode implements FlowSupplier, FlowConsumer // Constructors //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - public SimGpu(FlowEngine engine, GpuModel gpuModel, PowerModel powerModel, int id) { + public SimGpu( + FlowEngine engine, + GpuModel gpuModel, + PowerModel powerModel, + int id, + VirtualizationOverheadModel overheadModel) { super(engine); this.id = id; this.gpuModel = gpuModel; @@ -123,6 +132,7 @@ public final class SimGpu extends FlowNode implements FlowSupplier, FlowConsumer this.gpuFrequencyInv = 1 / this.maxCapacity; this.currentPowerDemand = this.gpuPowerModel.computePower(this.currentGpuUtilization); + this.virtualizationOverheadModel = overheadModel; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -139,8 +149,8 @@ public final class SimGpu extends FlowNode implements FlowSupplier, FlowConsumer return Long.MAX_VALUE; } - - this.currentGpuSupplied = Math.min(this.currentGpuDemand, this.maxCapacity); + this.currentGpuSupplied = virtualizationOverheadModel.getSupply( + Math.min(this.currentGpuDemand, this.maxCapacity), this.consumerCount); this.pushOutgoingSupply(this.distributorEdge, this.currentGpuSupplied); return Long.MAX_VALUE; @@ -213,13 +223,31 @@ public final class SimGpu extends FlowNode implements FlowSupplier, FlowConsumer this.distributorEdge.pushSupply(newGpuSupply, true, resourceType); } + @Override + public void handleIncomingDemand(FlowEdge consumerEdge, double newGpuDemand) { + updateCounters(); + this.currentGpuDemand = newGpuDemand; + + this.currentGpuUtilization = Math.min(this.currentGpuDemand / this.maxCapacity, 1.0); + + // Calculate Power Demand and send to PSU + this.currentPowerDemand = this.gpuPowerModel.computePower(this.currentGpuUtilization); + + this.invalidate(); + } + /** * Handle new demand coming in from the mux */ @Override - public void handleIncomingDemand(FlowEdge consumerEdge, double newGpuDemand) { + public void handleIncomingDemand( + FlowEdge consumerEdge, double newGpuDemand, ResourceType resourceType, int consumerCount) { + if (resourceType != ResourceType.GPU) { + throw new IllegalArgumentException("Resource type must be GPU"); + } updateCounters(); this.currentGpuDemand = newGpuDemand; + this.consumerCount = consumerCount; this.currentGpuUtilization = Math.min(this.currentGpuDemand / this.maxCapacity, 1.0); diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java index 5f4a4fcd..7158356a 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java @@ -242,7 +242,8 @@ public class SimMachine { for (GpuModel gpuModel : machineModel.getGpuModels()) { // create a new GPU - SimGpu gpu = new SimGpu(engine, gpuModel, gpuPowerModel, gpuModel.getId()); + SimGpu gpu = new SimGpu( + engine, gpuModel, gpuPowerModel, gpuModel.getId(), gpuModel.getVirtualizationOverheadModel()); gpus.add(gpu); // Connect the GPU to the distributor new FlowEdge( diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/GpuModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/GpuModel.java index b804b061..e62c93da 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/GpuModel.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/GpuModel.java @@ -23,6 +23,9 @@ package org.opendc.simulator.compute.models; import java.util.Objects; +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModel; +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModelFactory; +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModelFactory.VirtualizationOverheadModelEnum; /** * A single logical compute unit of processor node, either virtual or physical. @@ -37,6 +40,7 @@ public final class GpuModel { private final String vendor; private final String modelName; private final String arch; + private VirtualizationOverheadModel virtualizationOverheadModel; /** * Construct a {@link GpuModel} instance. @@ -49,6 +53,7 @@ public final class GpuModel { * @param vendor The vendor of the GPU * @param modelName The name of the GPU * @param arch The architecture of the GPU + * @param virtualizationOverheadModel The virtualization overhead model of this GPU. */ public GpuModel( int id, @@ -58,7 +63,8 @@ public final class GpuModel { long memorySize, String vendor, String modelName, - String arch) { + String arch, + VirtualizationOverheadModelEnum virtualizationOverheadModel) { this.id = id; this.coreCount = coreCount; this.coreSpeed = coreSpeed; @@ -68,6 +74,8 @@ public final class GpuModel { this.vendor = vendor; this.modelName = modelName; this.arch = arch; + this.virtualizationOverheadModel = + VirtualizationOverheadModelFactory.getVirtualizationOverheadModel(virtualizationOverheadModel); } /** @@ -78,11 +86,20 @@ public final class GpuModel { * @param coreSpeed The speed of a single core */ public GpuModel(int id, int coreCount, double coreSpeed) { - this(id, coreCount, coreSpeed, 0, 0, "unkown", "unkown", "unkown"); + this(id, coreCount, coreSpeed, 0, 0, "unkown", "unkown", "unkown", VirtualizationOverheadModelEnum.NONE); } public GpuModel(int id, int coreCount, double coreSpeed, double memoryBandwidth, long memorySize) { - this(id, coreCount, coreSpeed, memoryBandwidth, memorySize, "unkown", "unkown", "unkown"); + this( + id, + coreCount, + coreSpeed, + memoryBandwidth, + memorySize, + "unkown", + "unkown", + "unkown", + VirtualizationOverheadModelEnum.NONE); } /** @@ -148,6 +165,14 @@ public final class GpuModel { return arch; } + /** + * Return the virtualization overhead model of this GPU. + * @return The virtualization overhead model of this GPU. + */ + public VirtualizationOverheadModel getVirtualizationOverheadModel() { + return this.virtualizationOverheadModel; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/ConstantVirtualizationOverhead.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/ConstantVirtualizationOverhead.java new file mode 100644 index 00000000..e30133a5 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/ConstantVirtualizationOverhead.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 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.virtualization.OverheadModels; + +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModel; + +/** + * A VirtualizationOverheadModel that applies a constant percentage overhead to the current GPU demand. + * This model is useful for scenarios where a fixed overhead is expected regardless of the number of consumers. + */ +public class ConstantVirtualizationOverhead implements VirtualizationOverheadModel { + + private double percentageOverhead = 0.0; + + public double getPercentageOverhead() { + return percentageOverhead; + } + + /** + * Creates a new instance of ConstantVirtualizationOverhead with the specified percentage overhead. + * + * @param percentageOverhead The percentage overhead to apply to the current GPU demand. + * If set to -1.0, a default value of 0.05 (5%) is used. + */ + public ConstantVirtualizationOverhead(double percentageOverhead) { + + this.percentageOverhead = (percentageOverhead == -1.0) ? 0.05 : percentageOverhead; + } + + @Override + public double getSupply(double currentGpuDemand, int consumerCount) { + return currentGpuDemand * (1 - percentageOverhead); + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/NoVirtualizationOverHead.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/NoVirtualizationOverHead.java new file mode 100644 index 00000000..114962ef --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/NoVirtualizationOverHead.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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.virtualization.OverheadModels; + +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModel; + +/** + * A VirtualizationOverheadModel that does not introduce any overhead. + * It simply returns the current GPU demand as the supply. + */ +public class NoVirtualizationOverHead implements VirtualizationOverheadModel { + @Override + public double getSupply(double currentGpuDemand, int consumerCount) { + return currentGpuDemand; // No overhead, so supply is equal to demand + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/ShareBasedVirtualizationOverhead.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/ShareBasedVirtualizationOverhead.java new file mode 100644 index 00000000..e1562c38 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/OverheadModels/ShareBasedVirtualizationOverhead.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 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.virtualization.OverheadModels; + +import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModel; + +/** + * A VirtualizationOverheadModel that divides the current GPU demand by the number of consumers. + * This model assumes that the supply is shared among all consumers, effectively reducing the + * supply available to each consumer based on the number of consumers. + */ +public class ShareBasedVirtualizationOverhead implements VirtualizationOverheadModel { + @Override + public double getSupply(double currentGpuDemand, int consumerCount) { + // Supply is divided by the number of consumers to account for sharing + return currentGpuDemand / (consumerCount == 0 ? 1 : consumerCount); + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/VirtualizationOverheadModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/VirtualizationOverheadModel.java new file mode 100644 index 00000000..149780f8 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/VirtualizationOverheadModel.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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.virtualization; + +/** + * An interface for modeling the overhead introduced by virtualization in a compute environment. + * This model is used to determine the effective supply of resources available to consumers based + * on the current demand and the number of consumers. + */ +public interface VirtualizationOverheadModel { + + public double getSupply(double currentGpuDemand, int consumerCount); +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/VirtualizationOverheadModelFactory.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/VirtualizationOverheadModelFactory.java new file mode 100644 index 00000000..8eee2b01 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/virtualization/VirtualizationOverheadModelFactory.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 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.virtualization; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.opendc.simulator.compute.virtualization.OverheadModels.ConstantVirtualizationOverhead; +import org.opendc.simulator.compute.virtualization.OverheadModels.NoVirtualizationOverHead; +import org.opendc.simulator.compute.virtualization.OverheadModels.ShareBasedVirtualizationOverhead; + +/** + * A factory class for creating instances of VirtualizationOverheadModel based on the specified type. + * This factory supports different virtualization overhead models, including no overhead, constant overhead, + * and share-based overhead. + */ +public class VirtualizationOverheadModelFactory { + + public enum VirtualizationOverheadModelEnum { + NONE, + // General virtualization models -> Passthrough vs Full/Para virtualization + CONSTANT, + // Hardware assisted virtualization models + SHARE_BASED; + + private final Map<String, Object> properties = new HashMap<>(); + + public void setProperty(String key, Object value) { + properties.put(key, value); + } + + public Object getProperty(String key) { + return properties.get(key); + } + + public <T> T getProperty(String key, Class<T> type) { + return type.cast(properties.get(key)); + } + + public Set<String> getPropertyNames() { + return properties.keySet(); + } + } + + /** + * Factory method to create a VirtualizationOverheadModel based on the specified type. + * + * @param virtualizationOverheadModelType The type of virtualization overhead model to create. + * @return An instance of the specified VirtualizationOverheadModel. + */ + public static VirtualizationOverheadModel getVirtualizationOverheadModel( + VirtualizationOverheadModelEnum virtualizationOverheadModelType) { + return switch (virtualizationOverheadModelType) { + case NONE -> new NoVirtualizationOverHead(); + case CONSTANT -> { + double percentageOverhead = -1.0; // Default value if not set + if (virtualizationOverheadModelType.getPropertyNames().contains("percentageOverhead")) { + percentageOverhead = + virtualizationOverheadModelType.getProperty("percentageOverhead", Double.class); + } + yield new ConstantVirtualizationOverhead(percentageOverhead); + } + case SHARE_BASED -> new ShareBasedVirtualizationOverhead(); + default -> throw new IllegalArgumentException( + "Unknown virtualization overhead model type: " + virtualizationOverheadModelType); + }; + } +} diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowDistributor.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowDistributor.java index cae3e8a1..c388293b 100644 --- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowDistributor.java +++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowDistributor.java @@ -102,7 +102,6 @@ public abstract class FlowDistributor extends FlowNode implements FlowSupplier, protected abstract void updateOutgoingDemand(); - // TODO: This should probably be moved to the distribution strategy protected abstract void updateOutgoingSupplies(); public abstract double[] distributeSupply( @@ -120,6 +119,7 @@ public abstract class FlowDistributor extends FlowNode implements FlowSupplier, this.incomingDemands.add(0.0); this.outgoingSupplies.add(0.0); this.consumerResourceType = consumerEdge.getConsumerResourceType(); + this.outgoingDemandUpdateNeeded = true; } @Override @@ -233,7 +233,7 @@ public abstract class FlowDistributor extends FlowNode implements FlowSupplier, @Override public void pushOutgoingDemand(FlowEdge supplierEdge, double newDemand) { - supplierEdge.pushDemand(newDemand, false, this.getSupplierResourceType()); + supplierEdge.pushDemand(newDemand, false, this.getSupplierResourceType(), this.consumerEdges.size()); } @Override diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowEdge.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowEdge.java index db2a2944..1e65998b 100644 --- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowEdge.java +++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowEdge.java @@ -177,6 +177,16 @@ public class FlowEdge { this.supplierIndex = supplierIndex; } + public void pushDemand(double newDemand, boolean forceThrough, ResourceType resourceType, int consumerCount) { + // or store last resource type in the edge + if ((newDemand == this.demand) && !forceThrough) { + return; + } + + this.demand = newDemand; + this.supplier.handleIncomingDemand(this, newDemand, resourceType, consumerCount); + } + public void pushDemand(double newDemand, boolean forceThrough, ResourceType resourceType) { // or store last resource type in the edge if ((newDemand == this.demand) && !forceThrough) { diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowSupplier.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowSupplier.java index eb665b8c..2f5f80ef 100644 --- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowSupplier.java +++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowSupplier.java @@ -32,6 +32,12 @@ public interface FlowSupplier { handleIncomingDemand(consumerEdge, newDemand); } + default void handleIncomingDemand( + FlowEdge consumerEdge, double newDemand, ResourceType resourceType, int consumerCount) { + handleIncomingDemand(consumerEdge, newDemand); + } + ; + void pushOutgoingSupply(FlowEdge consumerEdge, double newSupply); default void pushOutgoingSupply(FlowEdge consumerEdge, double newSupply, ResourceType resourceType) { |
