diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-09-01 14:38:34 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-10-21 22:13:04 +0200 |
| commit | 44215bd668c5fa3efe2f57fc577824478b00af57 (patch) | |
| tree | b933228e5e5748716351dc9ce031b4840f254428 /opendc-simulator/opendc-simulator-compute/src/test | |
| parent | c1f67a872e2d7ce63ac96f8ca80cbe8b25c62e3b (diff) | |
refactor(sim/compute): Re-implement using flow2
This change re-implements the OpenDC compute simulator framework using
the new flow2 framework for modelling multi-edge flow networks. The
re-implementation is written in Java and focusses on performance and
clean API surface.
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src/test')
13 files changed, 312 insertions, 532 deletions
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 1eddf82c..f0aae15b 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 @@ -26,6 +26,7 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.cancel import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch +import kotlinx.coroutines.yield import org.junit.jupiter.api.Assertions.assertAll import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach @@ -38,17 +39,16 @@ import org.opendc.simulator.compute.model.NetworkAdapter import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.model.StorageDevice -import org.opendc.simulator.compute.power.ConstantPowerModel -import org.opendc.simulator.compute.power.LinearPowerModel -import org.opendc.simulator.compute.power.SimplePowerDriver +import org.opendc.simulator.compute.power.CpuPowerModels import org.opendc.simulator.compute.workload.SimFlopsWorkload +import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimWorkload -import org.opendc.simulator.compute.workload.SimWorkloadLifecycle -import org.opendc.simulator.flow.FlowEngine -import org.opendc.simulator.flow.source.FixedFlowSource +import org.opendc.simulator.flow2.FlowEngine +import org.opendc.simulator.flow2.source.SimpleFlowSource import org.opendc.simulator.kotlin.runSimulation import org.opendc.simulator.network.SimNetworkSink import org.opendc.simulator.power.SimPowerSource +import java.util.concurrent.ThreadLocalRandom /** * Test suite for the [SimBareMetalMachine] class. @@ -61,41 +61,69 @@ class SimMachineTest { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) machineModel = MachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, - net = listOf(NetworkAdapter("Mellanox", "ConnectX-5", 25000.0)), - storage = listOf(StorageDevice("Samsung", "EVO", 1000.0, 250.0, 250.0)) + /*cpus*/ List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, + /*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + /*net*/ listOf(NetworkAdapter("Mellanox", "ConnectX-5", 25000.0)), + /*storage*/ listOf(StorageDevice("Samsung", "EVO", 1000.0, 250.0, 250.0)) ) } @Test fun testFlopsWorkload() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) - machine.runWorkload(SimFlopsWorkload(2_000, utilization = 1.0)) + machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) // Two cores execute 1000 MFlOps per second (1000 ms) assertEquals(1000, clock.millis()) } @Test + fun testTraceWorkload() = runSimulation { + val random = ThreadLocalRandom.current() + val builder = SimTrace.builder() + repeat(1000000) { + val timestamp = it.toLong() * 1000 + val deadline = timestamp + 1000 + builder.add(deadline, random.nextDouble(0.0, 4500.0), 1) + } + val trace = builder.build() + + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + machine.runWorkload(trace.createWorkload(0)) + + // Two cores execute 1000 MFlOps per second (1000 ms) + assertEquals(1000000000, clock.millis()) + } + + @Test fun testDualSocketMachine() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + val cpuNode = machineModel.cpus[0].node val machineModel = MachineModel( - cpus = List(cpuNode.coreCount * 2) { ProcessingUnit(cpuNode, it % 2, 1000.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + /*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( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val machine = SimBareMetalMachine.create( + graph, + machineModel ) - machine.runWorkload(SimFlopsWorkload(2_000, utilization = 1.0)) + machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) // Two sockets with two cores execute 2000 MFlOps per second (500 ms) assertEquals(500, clock.millis()) @@ -103,42 +131,47 @@ class SimMachineTest { @Test fun testPower() = runSimulation { - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine( - engine, + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + val machine = SimBareMetalMachine.create( + graph, machineModel, - SimplePowerDriver(LinearPowerModel(100.0, 50.0)) + SimPsuFactories.simple(CpuPowerModels.linear(100.0, 50.0)) ) - val source = SimPowerSource(engine, capacity = 1000.0) + val source = SimPowerSource(graph, /*capacity*/ 1000.0f) source.connect(machine.psu) coroutineScope { - launch { machine.runWorkload(SimFlopsWorkload(2_000, utilization = 1.0)) } + launch { machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) } + + yield() assertAll( - { assertEquals(100.0, machine.psu.powerDraw) }, - { assertEquals(100.0, source.powerDraw) } + { assertEquals(100.0, machine.psu.powerUsage) }, + { assertEquals(100.0f, source.powerDraw) } ) } } @Test fun testCapacityClamp() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) machine.runWorkload(object : SimWorkload { override fun onStart(ctx: SimMachineContext) { val cpu = ctx.cpus[0] - cpu.capacity = cpu.model.frequency + 1000.0 - assertEquals(cpu.model.frequency, cpu.capacity) - cpu.capacity = -1.0 - assertEquals(0.0, cpu.capacity) + cpu.frequency = (cpu.model.frequency + 1000.0) + assertEquals(cpu.model.frequency, cpu.frequency) + cpu.frequency = -1.0 + assertEquals(0.0, cpu.frequency) - ctx.close() + ctx.shutdown() } override fun onStop(ctx: SimMachineContext) {} @@ -147,16 +180,18 @@ class SimMachineTest { @Test fun testMemory() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) machine.runWorkload(object : SimWorkload { override fun onStart(ctx: SimMachineContext) { assertEquals(32_000 * 4.0, ctx.memory.capacity) - ctx.close() + ctx.shutdown() } override fun onStop(ctx: SimMachineContext) {} @@ -165,104 +200,111 @@ class SimMachineTest { @Test fun testMemoryUsage() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) machine.runWorkload(object : SimWorkload { override fun onStart(ctx: SimMachineContext) { - val lifecycle = SimWorkloadLifecycle(ctx) - ctx.memory.startConsumer(lifecycle.waitFor(FixedFlowSource(ctx.memory.capacity, utilization = 0.8))) + val source = SimpleFlowSource(ctx.graph, ctx.memory.capacity.toFloat(), 1.0f) { ctx.shutdown() } + ctx.graph.connect(source.output, ctx.memory.input) } override fun onStop(ctx: SimMachineContext) {} }) - assertEquals(1250, clock.millis()) + assertEquals(1000, clock.millis()) } @Test fun testNetUsage() = runSimulation { - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine( - engine, - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) val adapter = (machine.peripherals[0] as SimNetworkAdapter) - adapter.connect(SimNetworkSink(engine, adapter.bandwidth)) + adapter.connect(SimNetworkSink(graph, adapter.bandwidth.toFloat())) machine.runWorkload(object : SimWorkload { override fun onStart(ctx: SimMachineContext) { - val lifecycle = SimWorkloadLifecycle(ctx) - val iface = ctx.net[0] - iface.tx.startConsumer(lifecycle.waitFor(FixedFlowSource(iface.bandwidth, utilization = 0.8))) + val iface = ctx.networkInterfaces[0] + val source = SimpleFlowSource(ctx.graph, 800.0f, 0.8f) { ctx.shutdown(); it.close(); } + ctx.graph.connect(source.output, iface.tx) } override fun onStop(ctx: SimMachineContext) {} }) - assertEquals(1250, clock.millis()) + assertEquals(40, clock.millis()) } @Test fun testDiskReadUsage() = runSimulation { - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine( - engine, - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) machine.runWorkload(object : SimWorkload { override fun onStart(ctx: SimMachineContext) { - val lifecycle = SimWorkloadLifecycle(ctx) - val disk = ctx.storage[0] - disk.read.startConsumer(lifecycle.waitFor(FixedFlowSource(disk.read.capacity, utilization = 0.8))) + val disk = ctx.storageInterfaces[0] + val source = SimpleFlowSource(ctx.graph, 800.0f, 0.8f) { ctx.shutdown() } + ctx.graph.connect(source.output, disk.read) } override fun onStop(ctx: SimMachineContext) {} }) - assertEquals(1250, clock.millis()) + assertEquals(4000, clock.millis()) } @Test fun testDiskWriteUsage() = runSimulation { - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine( - engine, - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) machine.runWorkload(object : SimWorkload { override fun onStart(ctx: SimMachineContext) { - val lifecycle = SimWorkloadLifecycle(ctx) - val disk = ctx.storage[0] - disk.write.startConsumer(lifecycle.waitFor(FixedFlowSource(disk.write.capacity, utilization = 0.8))) + val disk = ctx.storageInterfaces[0] + val source = SimpleFlowSource(ctx.graph, 800.0f, 0.8f) { ctx.shutdown() } + ctx.graph.connect(source.output, disk.write) } override fun onStop(ctx: SimMachineContext) {} }) - assertEquals(1250, clock.millis()) + assertEquals(4000, clock.millis()) } @Test fun testCancellation() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) try { coroutineScope { - launch { machine.runWorkload(SimFlopsWorkload(2_000, utilization = 1.0)) } + launch { machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) } cancel() } } catch (_: CancellationException) { @@ -274,19 +316,21 @@ class SimMachineTest { @Test fun testConcurrentRuns() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) coroutineScope { launch { - machine.runWorkload(SimFlopsWorkload(2_000, utilization = 1.0)) + machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) } assertThrows<IllegalStateException> { - machine.runWorkload(SimFlopsWorkload(2_000, utilization = 1.0)) + machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) } } } diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt deleted file mode 100644 index 0a6cb29f..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/device/SimPsuTest.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.simulator.compute.device - -import io.mockk.every -import io.mockk.mockk -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.compute.power.PowerDriver -import org.opendc.simulator.flow.FlowEngine -import org.opendc.simulator.kotlin.runSimulation -import org.opendc.simulator.power.SimPowerSource - -/** - * Test suite for [SimPsu] - */ -internal class SimPsuTest { - - @Test - fun testInvalidInput() { - assertThrows<IllegalArgumentException> { SimPsu(1.0, emptyMap()) } - } - - @Test - fun testDoubleConnect() { - val psu = SimPsu(1.0, mapOf(0.0 to 1.0)) - val cpuLogic = mockk<PowerDriver.Logic>() - psu.connect(cpuLogic) - assertThrows<IllegalStateException> { psu.connect(mockk()) } - } - - @Test - fun testPsuIdle() = runSimulation { - val ratedOutputPower = 240.0 - val energyEfficiency = mapOf(0.0 to 1.0) - - val engine = FlowEngine(coroutineContext, clock) - val source = SimPowerSource(engine, capacity = ratedOutputPower) - - val cpuLogic = mockk<PowerDriver.Logic>() - every { cpuLogic.computePower() } returns 0.0 - - val psu = SimPsu(ratedOutputPower, energyEfficiency) - psu.connect(cpuLogic) - source.connect(psu) - - assertEquals(0.0, source.powerDraw, 0.01) - } - - @Test - fun testPsuPowerLoss() = runSimulation { - val ratedOutputPower = 240.0 - // Efficiency of 80 Plus Titanium PSU - val energyEfficiency = sortedMapOf( - 0.3 to 0.9, - 0.7 to 0.92, - 1.0 to 0.94 - ) - - val engine = FlowEngine(coroutineContext, clock) - val source = SimPowerSource(engine, capacity = ratedOutputPower) - - val cpuLogic = mockk<PowerDriver.Logic>() - every { cpuLogic.computePower() } returnsMany listOf(50.0, 100.0, 150.0, 200.0) - - val psu = SimPsu(ratedOutputPower, energyEfficiency) - psu.connect(cpuLogic) - source.connect(psu) - - assertEquals(55.55, source.powerDraw, 0.01) - - psu.update() - assertEquals(108.695, source.powerDraw, 0.01) - - psu.update() - assertEquals(163.043, source.powerDraw, 0.01) - - psu.update() - assertEquals(212.765, source.powerDraw, 0.01) - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt index 6b498119..79669d40 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt @@ -31,20 +31,17 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertAll import org.junit.jupiter.api.assertDoesNotThrow import org.opendc.simulator.compute.SimBareMetalMachine -import org.opendc.simulator.compute.kernel.cpufreq.PerformanceScalingGovernor +import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernors import org.opendc.simulator.compute.kernel.interference.VmInterferenceModel import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit -import org.opendc.simulator.compute.power.ConstantPowerModel -import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.runWorkload import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceFragment -import org.opendc.simulator.compute.workload.SimTraceWorkload -import org.opendc.simulator.flow.FlowEngine -import org.opendc.simulator.flow.mux.FlowMultiplexerFactory +import org.opendc.simulator.flow2.FlowEngine +import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory import org.opendc.simulator.kotlin.runSimulation import java.util.SplittableRandom @@ -58,8 +55,8 @@ internal class SimFairShareHypervisorTest { fun setUp() { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) model = MachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + /*cpus*/ List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + /*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) } @@ -70,23 +67,20 @@ internal class SimFairShareHypervisorTest { fun testOvercommittedSingle() = runSimulation { val duration = 5 * 60L val workloadA = - SimTraceWorkload( - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 28.0, 1), - SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1), - SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), - SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) - ) - ) - - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, model, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1), PerformanceScalingGovernor()) + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 28.0, 1), + SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), + SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) + ).createWorkload(0) - launch { - machine.runWorkload(hypervisor) - println("Hypervisor finished") - } + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, model) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(0L), ScalingGovernors.performance()) + + launch { machine.runWorkload(hypervisor) } yield() val vm = hypervisor.newMachine(model) @@ -110,31 +104,27 @@ internal class SimFairShareHypervisorTest { fun testOvercommittedDual() = runSimulation { val duration = 5 * 60L val workloadA = - SimTraceWorkload( - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 28.0, 1), - SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1), - SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), - SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) - ) - ) + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 28.0, 1), + SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), + SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) + ).createWorkload(0) val workloadB = - SimTraceWorkload( - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 28.0, 1), - SimTraceFragment(duration * 1000, duration * 1000, 3100.0, 1), - SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), - SimTraceFragment(duration * 3000, duration * 1000, 73.0, 1) - ) - ) - - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, model, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1), null) + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 28.0, 1), + SimTraceFragment(duration * 1000, duration * 1000, 3100.0, 1), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), + SimTraceFragment(duration * 3000, duration * 1000, 73.0, 1) + ).createWorkload(0) - launch { - machine.runWorkload(hypervisor) - } + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, model) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(0L), ScalingGovernors.performance()) + + launch { machine.runWorkload(hypervisor) } yield() coroutineScope { @@ -163,18 +153,18 @@ internal class SimFairShareHypervisorTest { fun testMultipleCPUs() = runSimulation { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) val model = MachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + /*cpus*/ List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + /*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, model, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1), null) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, model) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(0L), ScalingGovernors.performance()) assertDoesNotThrow { - launch { - machine.runWorkload(hypervisor) - } + launch { machine.runWorkload(hypervisor) } } machine.cancel() @@ -184,39 +174,37 @@ internal class SimFairShareHypervisorTest { fun testInterference() = runSimulation { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) val model = MachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + /*cpus*/ List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + /*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) val interferenceModel = VmInterferenceModel.builder() - .addGroup(targetLoad = 0.0, score = 0.9, members = setOf("a", "b")) - .addGroup(targetLoad = 0.0, score = 0.6, members = setOf("a", "c")) - .addGroup(targetLoad = 0.1, score = 0.8, members = setOf("a", "n")) + .addGroup(setOf("a", "b"), 0.0, 0.9) + .addGroup(setOf("a", "c"), 0.0, 0.6) + .addGroup(setOf("a", "n"), 0.1, 0.8) .build() - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, model, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1), null) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, model) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(0L)) val duration = 5 * 60L val workloadA = - SimTraceWorkload( - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 0.0, 1), - SimTraceFragment(duration * 1000, duration * 1000, 28.0, 1), - SimTraceFragment(duration * 2000, duration * 1000, 3500.0, 1), - SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) - ) - ) + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 0.0, 1), + SimTraceFragment(duration * 1000, duration * 1000, 28.0, 1), + SimTraceFragment(duration * 2000, duration * 1000, 3500.0, 1), + SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) + ).createWorkload(0) val workloadB = - SimTraceWorkload( - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 0.0, 1), - SimTraceFragment(duration * 1000, duration * 1000, 28.0, 1), - SimTraceFragment(duration * 2000, duration * 1000, 3100.0, 1), - SimTraceFragment(duration * 3000, duration * 1000, 73.0, 1) - ) - ) + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 0.0, 1), + SimTraceFragment(duration * 1000, duration * 1000, 28.0, 1), + SimTraceFragment(duration * 2000, duration * 1000, 3100.0, 1), + SimTraceFragment(duration * 3000, duration * 1000, 73.0, 1) + ).createWorkload(0) launch { machine.runWorkload(hypervisor) diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt index 57fe3766..ba5a5c68 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt @@ -37,16 +37,13 @@ import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit -import org.opendc.simulator.compute.power.ConstantPowerModel -import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.runWorkload import org.opendc.simulator.compute.workload.SimFlopsWorkload import org.opendc.simulator.compute.workload.SimRuntimeWorkload import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceFragment -import org.opendc.simulator.compute.workload.SimTraceWorkload -import org.opendc.simulator.flow.FlowEngine -import org.opendc.simulator.flow.mux.FlowMultiplexerFactory +import org.opendc.simulator.flow2.FlowEngine +import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory import org.opendc.simulator.kotlin.runSimulation import java.util.SplittableRandom @@ -60,8 +57,8 @@ internal class SimSpaceSharedHypervisorTest { fun setUp() { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) machineModel = MachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + /*cpus*/ List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + /*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) } @@ -72,18 +69,18 @@ internal class SimSpaceSharedHypervisorTest { fun testTrace() = runSimulation { val duration = 5 * 60L val workloadA = - SimTraceWorkload( - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 28.0, 1), - SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1), - SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), - SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) - ) - ) - - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(1), null) + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 28.0, 1), + SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1), + SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1) + ).createWorkload(0) + + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L)) launch { machine.runWorkload(hypervisor) } val vm = hypervisor.newMachine(machineModel) @@ -102,10 +99,12 @@ internal class SimSpaceSharedHypervisorTest { @Test fun testRuntimeWorkload() = runSimulation { val duration = 5 * 60L * 1000 - val workload = SimRuntimeWorkload(duration) - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(1), null) + val workload = SimRuntimeWorkload(duration, 1.0) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L)) launch { machine.runWorkload(hypervisor) } yield() @@ -125,9 +124,11 @@ internal class SimSpaceSharedHypervisorTest { fun testFlopsWorkload() = runSimulation { val duration = 5 * 60L * 1000 val workload = SimFlopsWorkload((duration * 3.2).toLong(), 1.0) - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(1), null) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L)) launch { machine.runWorkload(hypervisor) } yield() @@ -144,21 +145,23 @@ internal class SimSpaceSharedHypervisorTest { @Test fun testTwoWorkloads() = runSimulation { val duration = 5 * 60L * 1000 - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(1), null) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L)) launch { machine.runWorkload(hypervisor) } yield() val vm = hypervisor.newMachine(machineModel) - vm.runWorkload(SimRuntimeWorkload(duration)) + vm.runWorkload(SimRuntimeWorkload(duration, 1.0)) hypervisor.removeMachine(vm) yield() val vm2 = hypervisor.newMachine(machineModel) - vm2.runWorkload(SimRuntimeWorkload(duration)) + vm2.runWorkload(SimRuntimeWorkload(duration, 1.0)) hypervisor.removeMachine(vm2) machine.cancel() @@ -171,14 +174,18 @@ internal class SimSpaceSharedHypervisorTest { */ @Test fun testConcurrentWorkloadFails() = runSimulation { - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(1), null) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L)) launch { machine.runWorkload(hypervisor) } yield() - hypervisor.newMachine(machineModel) + val vm = hypervisor.newMachine(machineModel) + launch { vm.runWorkload(SimFlopsWorkload(10_000, 1.0)) } + yield() assertAll( { assertFalse(hypervisor.canFit(machineModel)) }, @@ -186,6 +193,7 @@ internal class SimSpaceSharedHypervisorTest { ) machine.cancel() + vm.cancel() } /** @@ -193,9 +201,11 @@ internal class SimSpaceSharedHypervisorTest { */ @Test fun testConcurrentWorkloadSucceeds() = runSimulation { - val engine = FlowEngine(coroutineContext, clock) - val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(1), null) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L)) launch { machine.runWorkload(hypervisor) } yield() diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt index ef354569..6b182f4c 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt @@ -25,11 +25,10 @@ package org.opendc.simulator.compute.kernel.cpufreq import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test /** - * Test suite for the [ConservativeScalingGovernor] + * Test suite for the conservative [ScalingGovernor]. */ internal class ConservativeScalingGovernorTest { @Test @@ -38,7 +37,7 @@ internal class ConservativeScalingGovernorTest { val minSpeed = cpuCapacity / 2 val defaultThreshold = 0.8 val defaultStepSize = 0.05 * cpuCapacity - val governor = ConservativeScalingGovernor() + val governor = ScalingGovernors.conservative(defaultThreshold) val policy = mockk<ScalingPolicy>(relaxUnitFun = true) every { policy.max } returns cpuCapacity @@ -48,10 +47,8 @@ internal class ConservativeScalingGovernorTest { every { policy.target } answers { target } every { policy.target = any() } propertyType Double::class answers { target = value } - val logic = governor.createLogic(policy) + val logic = governor.newGovernor(policy) logic.onStart() - assertEquals(defaultThreshold, governor.threshold) - logic.onLimit(0.5) /* Upwards scaling */ @@ -71,7 +68,7 @@ internal class ConservativeScalingGovernorTest { val minSpeed = firstPState val threshold = 0.5 val stepSize = 0.02 * cpuCapacity - val governor = ConservativeScalingGovernor(threshold, stepSize) + val governor = ScalingGovernors.conservative(threshold, stepSize) val policy = mockk<ScalingPolicy>(relaxUnitFun = true) every { policy.max } returns cpuCapacity @@ -81,9 +78,8 @@ internal class ConservativeScalingGovernorTest { every { policy.target } answers { target } every { policy.target = any() } propertyType Double::class answers { target = value } - val logic = governor.createLogic(policy) + val logic = governor.newGovernor(policy) logic.onStart() - assertEquals(threshold, governor.threshold) logic.onLimit(0.5) /* Upwards scaling */ diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt index ca759e39..d6a7090b 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt @@ -25,11 +25,10 @@ package org.opendc.simulator.compute.kernel.cpufreq import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test /** - * Test suite for the [OnDemandScalingGovernor] + * Test suite for the on-demand [ScalingGovernor]. */ internal class OnDemandScalingGovernorTest { @Test @@ -37,15 +36,14 @@ internal class OnDemandScalingGovernorTest { val cpuCapacity = 4100.0 val minSpeed = cpuCapacity / 2 val defaultThreshold = 0.8 - val governor = OnDemandScalingGovernor() + val governor = ScalingGovernors.ondemand(defaultThreshold) val policy = mockk<ScalingPolicy>(relaxUnitFun = true) every { policy.min } returns minSpeed every { policy.max } returns cpuCapacity - val logic = governor.createLogic(policy) + val logic = governor.newGovernor(policy) logic.onStart() - assertEquals(defaultThreshold, governor.threshold) verify(exactly = 1) { policy.target = minSpeed } logic.onLimit(0.5) @@ -60,16 +58,15 @@ internal class OnDemandScalingGovernorTest { val firstPState = 1000.0 val cpuCapacity = 4100.0 val threshold = 0.5 - val governor = OnDemandScalingGovernor(threshold) + val governor = ScalingGovernors.ondemand(threshold) val policy = mockk<ScalingPolicy>(relaxUnitFun = true) every { policy.max } returns cpuCapacity every { policy.min } returns firstPState - val logic = governor.createLogic(policy) + val logic = governor.newGovernor(policy) logic.onStart() - assertEquals(threshold, governor.threshold) verify(exactly = 1) { policy.target = firstPState } logic.onLimit(0.1) diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt index a4bb24f2..f03f41fe 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt @@ -34,7 +34,7 @@ internal class PerformanceScalingGovernorTest { @Test fun testSetStartLimit() { val policy = spyk<ScalingPolicy>() - val logic = PerformanceScalingGovernor().createLogic(policy) + val logic = ScalingGovernors.performance().newGovernor(policy) every { policy.max } returns 4100.0 diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt index 662d55fb..4cee8199 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt @@ -36,7 +36,7 @@ internal class PowerSaveScalingGovernorTest { val cpuCapacity = 4100.0 val minSpeed = cpuCapacity / 2 val policy = mockk<ScalingPolicy>(relaxUnitFun = true) - val logic = PowerSaveScalingGovernor().createLogic(policy) + val logic = ScalingGovernors.powerSave().newGovernor(policy) every { policy.max } returns cpuCapacity every { policy.min } returns minSpeed @@ -55,7 +55,7 @@ internal class PowerSaveScalingGovernorTest { val cpuCapacity = 4100.0 val firstPState = 1000.0 val policy = mockk<ScalingPolicy>(relaxUnitFun = true) - val logic = PowerSaveScalingGovernor().createLogic(policy) + val logic = ScalingGovernors.powerSave().newGovernor(policy) every { policy.max } returns cpuCapacity every { policy.min } returns firstPState 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 deleted file mode 100644 index 3c0a55a6..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PStatePowerDriverTest.kt +++ /dev/null @@ -1,123 +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.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<SimBareMetalMachine>() - - 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<SimBareMetalMachine>() - val cpu = mockk<SimProcessingUnit>(relaxUnitFun = true) - - every { cpu.capacity } returns 3200.0 - every { cpu.rate } 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<SimBareMetalMachine>() - val cpu = mockk<SimProcessingUnit>(relaxUnitFun = true) - val cpus = listOf(cpu, cpu) - - every { cpus[0].capacity } returns 1000.0 - every { cpus[0].rate } returns 1200.0 - - every { cpus[1].capacity } returns 3500.0 - every { cpus[1].rate } 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<SimBareMetalMachine>() - val cpu = mockk<SimProcessingUnit>(relaxUnitFun = true) - - 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.rate } returns 1400.0 - every { cpu.capacity } returns 1400.0 - assertEquals(150.0, logic.computePower()) - - every { cpu.rate } returns 1400.0 - every { cpu.capacity } returns 4000.0 - assertEquals(235.0, logic.computePower()) - } -} 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 67532d5b..9a6263c5 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 @@ -38,7 +38,7 @@ internal class PowerModelTest { @ParameterizedTest @MethodSource("MachinePowerModelArgs") fun `compute power consumption given CPU loads`( - powerModel: PowerModel, + powerModel: CpuPowerModel, expectedPowerConsumption: Double ) { val computedPowerConsumption = powerModel.computePower(cpuUtil) @@ -48,10 +48,10 @@ internal class PowerModelTest { @ParameterizedTest @MethodSource("MachinePowerModelArgs") fun `ignore idle power when computing power consumptions`( - powerModel: PowerModel, + powerModel: CpuPowerModel, expectedPowerConsumption: Double ) { - val zeroPowerModel = ZeroIdlePowerDecorator(powerModel) + val zeroPowerModel = CpuPowerModels.zeroIdle(powerModel) assertAll( { assertEquals(expectedPowerConsumption, zeroPowerModel.computePower(cpuUtil), epsilon) }, @@ -61,8 +61,9 @@ internal class PowerModelTest { @Test fun `compute power draw by the SPEC benchmark model`() { - val ibm = listOf(58.4, 98.0, 109.0, 118.0, 128.0, 140.0, 153.0, 170.0, 189.0, 205.0, 222.0) - val powerModel = InterpolationPowerModel(ibm) + val powerModel = CpuPowerModels.interpolate( + 58.4, 98.0, 109.0, 118.0, 128.0, 140.0, 153.0, 170.0, 189.0, 205.0, 222.0 + ) assertAll( { assertEquals(58.4, powerModel.computePower(0.0)) }, @@ -80,14 +81,14 @@ internal class PowerModelTest { private companion object { @JvmStatic fun MachinePowerModelArgs(): Stream<Arguments> = Stream.of( - Arguments.of(ConstantPowerModel(0.0), 0.0), - 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), - Arguments.of(MsePowerModel(350.0, 200.0, 1.4), 340.571), - Arguments.of(AsymptoticPowerModel(350.0, 200.0, 0.3, false), 338.765), - Arguments.of(AsymptoticPowerModel(350.0, 200.0, 0.3, true), 323.072) + Arguments.of(CpuPowerModels.constant(0.0), 0.0), + Arguments.of(CpuPowerModels.linear(350.0, 200.0), 335.0), + Arguments.of(CpuPowerModels.square(350.0, 200.0), 321.5), + Arguments.of(CpuPowerModels.cubic(350.0, 200.0), 309.35), + Arguments.of(CpuPowerModels.sqrt(350.0, 200.0), 342.302), + Arguments.of(CpuPowerModels.mse(350.0, 200.0, 1.4), 340.571), + Arguments.of(CpuPowerModels.asymptotic(350.0, 200.0, 0.3, false), 338.765), + Arguments.of(CpuPowerModels.asymptotic(350.0, 200.0, 0.3, true), 323.072) ) } } diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt index b3e57453..edbc0571 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt @@ -32,7 +32,7 @@ class SimFlopsWorkloadTest { @Test fun testFlopsNonNegative() { assertThrows<IllegalArgumentException>("FLOPs must be non-negative") { - SimFlopsWorkload(-1) + SimFlopsWorkload(-1, 1.0) } } diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt index 83e1f81c..e3b6e6c5 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt @@ -31,10 +31,8 @@ import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.ProcessingNode import org.opendc.simulator.compute.model.ProcessingUnit -import org.opendc.simulator.compute.power.ConstantPowerModel -import org.opendc.simulator.compute.power.SimplePowerDriver import org.opendc.simulator.compute.runWorkload -import org.opendc.simulator.flow.FlowEngine +import org.opendc.simulator.flow2.FlowEngine import org.opendc.simulator.kotlin.runSimulation /** @@ -48,28 +46,28 @@ class SimTraceWorkloadTest { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) machineModel = MachineModel( - cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, - memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } + /*cpus*/ List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, + /*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } ) } @Test fun testSmoke() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) - val workload = SimTraceWorkload( + val workload = SimTrace.ofFragments( SimTraceFragment(0, 1000, 2 * 28.0, 2), SimTraceFragment(1000, 1000, 2 * 3100.0, 2), SimTraceFragment(2000, 1000, 0.0, 2), SimTraceFragment(3000, 1000, 2 * 73.0, 2) - ), - offset = 0 - ) + ).createWorkload(0) machine.runWorkload(workload) @@ -78,21 +76,21 @@ class SimTraceWorkloadTest { @Test fun testOffset() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) - val workload = SimTraceWorkload( + val workload = SimTrace.ofFragments( SimTraceFragment(0, 1000, 2 * 28.0, 2), SimTraceFragment(1000, 1000, 2 * 3100.0, 2), SimTraceFragment(2000, 1000, 0.0, 2), SimTraceFragment(3000, 1000, 2 * 73.0, 2) - ), - offset = 1000 - ) + ).createWorkload(1000) machine.runWorkload(workload) @@ -101,21 +99,21 @@ class SimTraceWorkloadTest { @Test fun testSkipFragment() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) - val workload = SimTraceWorkload( + val workload = SimTrace.ofFragments( SimTraceFragment(0, 1000, 2 * 28.0, 2), SimTraceFragment(1000, 1000, 2 * 3100.0, 2), SimTraceFragment(2000, 1000, 0.0, 2), SimTraceFragment(3000, 1000, 2 * 73.0, 2) - ), - offset = 0 - ) + ).createWorkload(0) delay(1000L) machine.runWorkload(workload) @@ -125,21 +123,21 @@ class SimTraceWorkloadTest { @Test fun testZeroCores() = runSimulation { - val machine = SimBareMetalMachine( - FlowEngine(coroutineContext, clock), - machineModel, - SimplePowerDriver(ConstantPowerModel(0.0)) + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel ) - val workload = SimTraceWorkload( + val workload = SimTrace.ofFragments( SimTraceFragment(0, 1000, 2 * 28.0, 2), SimTraceFragment(1000, 1000, 2 * 3100.0, 2), SimTraceFragment(2000, 1000, 0.0, 0), SimTraceFragment(3000, 1000, 2 * 73.0, 2) - ), - offset = 0 - ) + ).createWorkload(0) machine.runWorkload(workload) diff --git a/opendc-simulator/opendc-simulator-compute/src/test/resources/spec_machines.yml b/opendc-simulator/opendc-simulator-compute/src/test/resources/spec_machines.yml deleted file mode 100644 index d51cba80..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/resources/spec_machines.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# The power model of an IBM server x3550 (2 x [Xeon X5675 3067 MHz, 6 cores], 16GB).<br/> -# <a href="http://www.spec.org/power_ssj2008/results/res2011q2/power_ssj2008-20110406-00368.html"> -# http://www.spec.org/power_ssj2008/results/res2011q2/power_ssj2008-20110406-00368.html</a> -IBMx3550M3_XeonX5675: [58.4, 98.0, 109.0, 118.0, 128.0, 140.0, 153.0, 170.0, 189.0, 205.0, 222.0] - # The power model of an IBM server x3550 (2 x [Xeon X5670 2933 MHz, 6 cores], 12GB).<br/> - # <a href="http://www.spec.org/power_ssj2008/results/res2010q2/power_ssj2008-20100315-00239.html"> - # http://www.spec.org/power_ssj2008/results/res2010q2/power_ssj2008-20100315-00239.html</a> -IBMx3550M3_XeonX5670: [66.0, 107.0, 120.0, 131.0, 143.0, 156.0, 173.0, 191.0, 211.0, 229.0, 247.0] - # the power model of an IBM server x3250 (1 x [Xeon X3480 3067 MHz, 4 cores], 8GB).<br/> - # <a href="http://www.spec.org/power_ssj2008/results/res2010q4/power_ssj2008-20101001-00297.html"> - # http://www.spec.org/power_ssj2008/results/res2010q4/power_ssj2008-20101001-00297.html</a> -IBMx3250M3_XeonX3480: [42.3, 46.7, 49.7, 55.4, 61.8, 69.3, 76.1, 87.0, 96.1, 106.0, 113.0] - # The power model of an IBM server x3250 (1 x [Xeon X3470 2933 MHz, 4 cores], 8GB).<br/> - # <a href="http://www.spec.org/power_ssj2008/results/res2009q4/power_ssj2008-20091104-00213.html"> - # http://www.spec.org/power_ssj2008/results/res2009q4/power_ssj2008-20091104-00213.html</a> -IBMx3250M3_XeonX3470: [41.6, 46.7, 52.3, 57.9, 65.4, 73.0, 80.7, 89.5, 99.6, 105.0, 113.0] - # The power model of an HP ProLiant ML110 G5 (1 x [Xeon 3075 2660 MHz, 2 cores], 4GB).<br/> - # <a href="http://www.spec.org/power_ssj2008/results/res2011q1/power_ssj2008-20110124-00339.html"> - # http://www.spec.org/power_ssj2008/results/res2011q1/power_ssj2008-20110124-00339.html</a> -HPProLiantMl110G5_Xeon3075: [93.7, 97.0, 101.0, 105.0, 110.0, 116.0, 121.0, 125.0, 129.0, 133.0, 135.0] - # The power model of an HP ProLiant ML110 G4 (1 x [Xeon 3040 1860 MHz, 2 cores], 4GB).<br/> - # <a href="http://www.spec.org/power_ssj2008/results/res2011q1/power_ssj2008-20110127-00342.html"> - # http://www.spec.org/power_ssj2008/results/res2011q1/power_ssj2008-20110127-00342.html</a> -HPProLiantMl110G4_Xeon3040: [86.0, 89.4, 92.6, 96.0, 99.5, 102.0, 106.0, 108.0, 112.0, 114.0, 117.0] - # The power model of an HP ProLiant ML110 G3 (1 x [Pentium D930 3000 MHz, 2 cores], 4GB).<br/> - # <a href="http://www.spec.org/power_ssj2008/results/res2011q1/power_ssj2008-20110127-00342.html"> - # http://www.spec.org/power_ssj2008/results/res2011q1/power_ssj2008-20110127-00342.html</a> -HPProLiantMl110G3_PentiumD930: [105.0, 112.0, 118.0, 125.0, 131.0, 137.0, 147.0, 153.0, 157.0, 164.0, 169.0] |
