From 5a365dbc068f2a8cdfa9813c39cc84bb30e15637 Mon Sep 17 00:00:00 2001 From: Dante Niewenhuis Date: Fri, 25 Oct 2024 13:32:41 +0200 Subject: Rewrote the FlowEngine (#256) * Removed unused components. Updated tests. Improved checkpointing model Improved model, started with SimPowerSource implemented FailureModels and Checkpointing First working version midway commit first update All simulation are now run with a single CPU and single MemoryUnit. multi CPUs are combined into one. This is for performance and explainability. * fixed merge conflicts * Updated M3SA paths. * Fixed small typo --- .../org/opendc/simulator/compute/SimMachineTest.kt | 883 +++++++++------------ .../compute/kernel/SimFairShareHypervisorTest.kt | 269 ------- .../compute/kernel/SimSpaceSharedHypervisorTest.kt | 234 ------ .../cpufreq/ConservativeScalingGovernorTest.kt | 94 --- .../kernel/cpufreq/OnDemandScalingGovernorTest.kt | 78 -- .../cpufreq/PerformanceScalingGovernorTest.kt | 50 -- .../kernel/cpufreq/PowerSaveScalingGovernorTest.kt | 72 -- .../simulator/compute/power/PowerModelTest.kt | 180 ----- .../compute/workload/SimChainWorkloadTest.kt | 310 -------- .../compute/workload/SimFlopsWorkloadTest.kt | 59 -- .../compute/workload/SimTraceWorkloadTest.kt | 160 ---- 11 files changed, 364 insertions(+), 2025 deletions(-) delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt delete mode 100644 opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt (limited to 'opendc-simulator/opendc-simulator-compute/src/test') 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 be6d289c..2b6a922e 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 @@ -22,33 +22,17 @@ package org.opendc.simulator.compute -import io.mockk.every -import io.mockk.mockk -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 import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.compute.device.SimNetworkAdapter -import org.opendc.simulator.compute.model.Cpu -import org.opendc.simulator.compute.model.MachineModel -import org.opendc.simulator.compute.model.MemoryUnit -import org.opendc.simulator.compute.model.NetworkAdapter -import org.opendc.simulator.compute.model.StorageDevice -import org.opendc.simulator.compute.power.CpuPowerModels -import org.opendc.simulator.compute.workload.SimTrace -import org.opendc.simulator.compute.workload.SimWorkload -import org.opendc.simulator.compute.workload.SimWorkloads -import org.opendc.simulator.flow2.FlowEngine -import org.opendc.simulator.flow2.source.SimpleFlowSource +import org.opendc.simulator.compute.cpu.CpuPowerModels +import org.opendc.simulator.compute.machine.SimMachine +import org.opendc.simulator.compute.models.CpuModel +import org.opendc.simulator.compute.models.MachineModel +import org.opendc.simulator.compute.models.MemoryUnit +import org.opendc.simulator.compute.workload.TraceWorkload +import org.opendc.simulator.engine.FlowEngine import org.opendc.simulator.kotlin.runSimulation -import org.opendc.simulator.network.SimNetworkSink -import org.opendc.simulator.power.SimPowerSource import java.util.concurrent.ThreadLocalRandom /** @@ -61,529 +45,390 @@ class SimMachineTest { fun setUp() { machineModel = MachineModel( - Cpu( + CpuModel( 0, 2, - 1000.0, + 1000.0f, "Intel", "Xeon", "amd64", ), MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - listOf(NetworkAdapter("Mellanox", "ConnectX-5", 25000.0)), - listOf(StorageDevice("Samsung", "EVO", 1000.0, 250.0, 250.0)), ) } // @Test - fun testFlopsWorkload() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) - - // Two cores execute 1000 MFlOps per second (1000 ms) - assertEquals(1000, timeSource.millis()) - } +// fun testFlopsWorkload() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// ) +// +// machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) +// +// // Two cores execute 1000 MFlOps per second (1000 ms) +// assertEquals(1000, timeSource.millis()) +// } @Test fun testTraceWorkload() = runSimulation { val random = ThreadLocalRandom.current() - val builder = SimTrace.builder() - repeat(1000000) { -// val timestamp = it.toLong() * 1000 -// val deadline = timestamp + 1000 + val builder = TraceWorkload.builder() + repeat(100) { builder.add(1000, random.nextDouble(0.0, 4500.0), 1) } - val trace = builder.build() - - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) + val traceWorkload = builder.build() - machine.runWorkload(trace.createWorkload(0)) - - // Two cores execute 1000 MFlOps per second (1000 ms) - assertEquals(1000000000, timeSource.millis()) - } - -// @Test - fun testDualSocketMachine() = - runSimulation { val engine = FlowEngine.create(dispatcher) val graph = engine.newGraph() - - val cpuNode = machineModel.cpu - val machineModel = - MachineModel( - List(cpuNode.coreCount * 2) { - Cpu( - it, - cpuNode.coreCount, - 1000.0, - ) - }, - MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - ) - val machine = - SimBareMetalMachine.create( + val simMachine = + SimMachine( graph, machineModel, - ) - - machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) - - // Two sockets with two cores execute 2000 MFlOps per second (500 ms) - assertEquals(500, timeSource.millis()) - } - - @Test - fun testPower() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - SimPsuFactories.simple(CpuPowerModels.linear(100.0, 50.0)), - ) - val source = SimPowerSource(graph, 1000.0f) - source.connect(machine.psu) - - coroutineScope { - launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) } - - yield() - assertAll( - { assertEquals(100.0, machine.psu.powerDraw) }, - { assertEquals(100.0f, source.powerDraw) }, - ) - } - } - - @Test - fun testCapacityClamp() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - machine.runWorkload( - object : SimWorkload { - override fun onStart(ctx: SimMachineContext) { - val cpu = ctx.cpu - - cpu.frequency = (cpu.cpuModel.totalCapacity + 1000.0) - assertEquals(cpu.cpuModel.totalCapacity, cpu.frequency) - cpu.frequency = -1.0 - assertEquals(0.0, cpu.frequency) - - ctx.shutdown() - } - - override fun setOffset(now: Long) {} - - override fun onStop(ctx: SimMachineContext) {} - - override fun makeSnapshot(now: Long) { - } - - override fun getSnapshot(): SimWorkload = this - - override fun createCheckpointModel() {} - - override fun getCheckpointInterval(): Long { - return -1 - } - - override fun getCheckpointDuration(): Long { - return -1 - } - - override fun getCheckpointIntervalScaling(): Double { - return -1.0 - } - }, - ) - } - - @Test - fun testMemory() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - 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.shutdown() - } - - override fun setOffset(now: Long) {} - - override fun onStop(ctx: SimMachineContext) {} - - override fun makeSnapshot(now: Long) {} - - override fun getSnapshot(): SimWorkload = this - - override fun createCheckpointModel() {} - - override fun getCheckpointInterval(): Long { - return -1 - } - - override fun getCheckpointDuration(): Long { - return -1 - } - - override fun getCheckpointIntervalScaling(): Double { - return -1.0 - } - }, - ) - } - - @Test - fun testMemoryUsage() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - machine.runWorkload( - object : SimWorkload { - override fun onStart(ctx: SimMachineContext) { - val source = SimpleFlowSource(ctx.graph, ctx.memory.capacity.toFloat(), 1.0f) { ctx.shutdown() } - ctx.graph.connect(source.output, ctx.memory.input) - } - - override fun setOffset(now: Long) {} - - override fun onStop(ctx: SimMachineContext) {} - - override fun makeSnapshot(now: Long) { - } - - override fun getSnapshot(): SimWorkload = this - - override fun createCheckpointModel() {} - - override fun getCheckpointInterval(): Long { - return -1 - } - - override fun getCheckpointDuration(): Long { - return -1 - } - - override fun getCheckpointIntervalScaling(): Double { - return -1.0 - } - }, - ) - - assertEquals(1000, timeSource.millis()) - } - - @Test - fun testNetUsage() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val adapter = (machine.peripherals[0] as SimNetworkAdapter) - adapter.connect(SimNetworkSink(graph, adapter.bandwidth.toFloat())) - - machine.runWorkload( - object : SimWorkload { - override fun onStart(ctx: SimMachineContext) { - 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 setOffset(now: Long) {} - - override fun onStop(ctx: SimMachineContext) {} - - override fun makeSnapshot(now: Long) { - } - - override fun getSnapshot(): SimWorkload = this - - override fun createCheckpointModel() {} - - override fun getCheckpointInterval(): Long { - return -1 - } - - override fun getCheckpointDuration(): Long { - return -1 - } - - override fun getCheckpointIntervalScaling(): Double { - return -1.0 - } - }, - ) - - assertEquals(40, timeSource.millis()) - } - - @Test - fun testDiskReadUsage() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - machine.runWorkload( - object : SimWorkload { - override fun onStart(ctx: SimMachineContext) { - 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 setOffset(now: Long) {} - - override fun onStop(ctx: SimMachineContext) {} - - override fun makeSnapshot(now: Long) {} - - override fun getSnapshot(): SimWorkload = this - - override fun createCheckpointModel() {} - - override fun getCheckpointInterval(): Long { - return -1 - } - - override fun getCheckpointDuration(): Long { - return -1 - } - - override fun getCheckpointIntervalScaling(): Double { - return -1.0 - } - }, - ) - - assertEquals(4000, timeSource.millis()) - } - - @Test - fun testDiskWriteUsage() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - machine.runWorkload( - object : SimWorkload { - override fun onStart(ctx: SimMachineContext) { - 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 setOffset(now: Long) {} - - override fun onStop(ctx: SimMachineContext) {} - - override fun makeSnapshot(now: Long) {} - - override fun getSnapshot(): SimWorkload = this - - override fun createCheckpointModel() {} - - override fun getCheckpointInterval(): Long { - return -1 - } - - override fun getCheckpointDuration(): Long { - return -1 - } - - override fun getCheckpointIntervalScaling(): Double { - return -1.0 - } - }, - ) - - assertEquals(4000, timeSource.millis()) - } - - @Test - fun testCancellation() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - try { - coroutineScope { - launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) } - cancel() - } - } catch (_: CancellationException) { - // Ignore - } - - assertEquals(0, timeSource.millis()) - } - - @Test - fun testConcurrentRuns() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - coroutineScope { - launch { - machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) + CpuPowerModels.constant(0.0), + ) { cause -> } - assertThrows { - machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) + val virtualMachine = + simMachine.startWorkload(traceWorkload) { cause -> + assertEquals(100000, timeSource.millis()) } - } - } - - @Test - fun testCatchStartFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workload = mockk() - every { workload.onStart(any()) } throws IllegalStateException() - - assertThrows { machine.runWorkload(workload) } - } - - @Test - fun testCatchStopFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workload = mockk() - every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown() } - every { workload.onStop(any()) } throws IllegalStateException() - - assertThrows { machine.runWorkload(workload) } - } - - @Test - fun testCatchShutdownFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workload = mockk() - every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } - assertThrows { machine.runWorkload(workload) } + // Two cores execute 1000 MFlOps per second (1000 ms) } - @Test - fun testCatchNestedFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workload = mockk() - every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } - every { workload.onStop(any()) } throws IllegalStateException() - - val exc = assertThrows { machine.runWorkload(workload) } - assertEquals(1, exc.cause!!.suppressedExceptions.size) - } +// @Test +// fun testDualSocketMachine() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val cpuNode = machineModel.cpu +// val machineModel = +// MachineModel( +// List(cpuNode.coreCount * 2) { +// CpuModel( +// it, +// cpuNode.coreCount, +// 1000.0, +// ) +// }, +// MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), +// ) +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) +// +// // Two sockets with two cores execute 2000 MFlOps per second (500 ms) +// assertEquals(500, timeSource.millis()) +// } +// +// // @Test +// // fun testPower() = +// // runSimulation { +// // val engine = FlowEngine.create(dispatcher) +// // val graph = engine.newGraph() +// // val machine = +// // SimBareMetalMachine.create( +// // graph, +// // machineModel, +// // CpuPowerModels.linear(100.0, 50.0), +// // ) +// // val source = SimPowerSource(graph, 1000.0f) +// // source.connect(machine.psu) +// // +// // coroutineScope { +// // launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) } +// // +// // yield() +// // assertAll( +// // { assertEquals(100.0, machine.psu.powerDraw) }, +// // { assertEquals(100.0f, source.powerDraw) }, +// // ) +// // } +// // } +// +// @Test +// fun testCapacityClamp() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// machine.runWorkload( +// object : SimWorkload { +// override fun onStart(ctx: SimMachineContext) { +// val cpu = ctx.cpu +// +// cpu.frequency = (cpu.cpuModel.totalCapacity + 1000.0) +// assertEquals(cpu.cpuModel.totalCapacity, cpu.frequency) +// cpu.frequency = -1.0 +// assertEquals(0.0, cpu.frequency) +// +// ctx.shutdown() +// } +// +// override fun setOffset(now: Long) {} +// +// override fun onStop(ctx: SimMachineContext) {} +// +// override fun makeSnapshot(now: Long) { +// } +// +// override fun getSnapshot(): SimWorkload = this +// +// override fun createCheckpointModel() {} +// +// override fun getCheckpointInterval(): Long { +// return -1 +// } +// +// override fun getCheckpointDuration(): Long { +// return -1 +// } +// +// override fun getCheckpointIntervalScaling(): Double { +// return -1.0 +// } +// }, +// ) +// } +// +// @Test +// fun testMemory() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// machine.runWorkload( +// object : SimWorkload { +// override fun onStart(ctx: SimMachineContext) { +// assertEquals(32_000 * 4.0, ctx.memory.capacity) +// ctx.shutdown() +// } +// +// override fun setOffset(now: Long) {} +// +// override fun onStop(ctx: SimMachineContext) {} +// +// override fun makeSnapshot(now: Long) {} +// +// override fun getSnapshot(): SimWorkload = this +// +// override fun createCheckpointModel() {} +// +// override fun getCheckpointInterval(): Long { +// return -1 +// } +// +// override fun getCheckpointDuration(): Long { +// return -1 +// } +// +// override fun getCheckpointIntervalScaling(): Double { +// return -1.0 +// } +// }, +// ) +// } +// +// @Test +// fun testMemoryUsage() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// machine.runWorkload( +// object : SimWorkload { +// override fun onStart(ctx: SimMachineContext) { +// val source = SimpleFlowSource(ctx.graph, ctx.memory.capacity.toFloat(), 1.0f) { ctx.shutdown() } +// ctx.graph.connect(source.output, ctx.memory.input) +// } +// +// override fun setOffset(now: Long) {} +// +// override fun onStop(ctx: SimMachineContext) {} +// +// override fun makeSnapshot(now: Long) { +// } +// +// override fun getSnapshot(): SimWorkload = this +// +// override fun createCheckpointModel() {} +// +// override fun getCheckpointInterval(): Long { +// return -1 +// } +// +// override fun getCheckpointDuration(): Long { +// return -1 +// } +// +// override fun getCheckpointIntervalScaling(): Double { +// return -1.0 +// } +// }, +// ) +// +// assertEquals(1000, timeSource.millis()) +// } +// +// @Test +// fun testCancellation() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// try { +// coroutineScope { +// launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) } +// cancel() +// } +// } catch (_: CancellationException) { +// // Ignore +// } +// +// assertEquals(0, timeSource.millis()) +// } +// +// @Test +// fun testConcurrentRuns() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// coroutineScope { +// launch { +// machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) +// } +// +// assertThrows { +// machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) +// } +// } +// } +// +// @Test +// fun testCatchStartFailure() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// val workload = mockk() +// every { workload.onStart(any()) } throws IllegalStateException() +// +// assertThrows { machine.runWorkload(workload) } +// } +// +// @Test +// fun testCatchStopFailure() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// val workload = mockk() +// every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown() } +// every { workload.onStop(any()) } throws IllegalStateException() +// +// assertThrows { machine.runWorkload(workload) } +// } +// +// @Test +// fun testCatchShutdownFailure() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// val workload = mockk() +// every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } +// +// assertThrows { machine.runWorkload(workload) } +// } +// +// @Test +// fun testCatchNestedFailure() = +// runSimulation { +// val engine = FlowEngine.create(dispatcher) +// val graph = engine.newGraph() +// +// val machine = +// SimBareMetalMachine.create( +// graph, +// machineModel, +// CpuPowerModels.constant(0.0) +// ) +// +// val workload = mockk() +// every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } +// every { workload.onStop(any()) } throws IllegalStateException() +// +// val exc = assertThrows { machine.runWorkload(workload) } +// assertEquals(1, exc.cause!!.suppressedExceptions.size) +// } } 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 deleted file mode 100644 index 6cebc46f..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt +++ /dev/null @@ -1,269 +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.kernel - -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.yield -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertAll -import org.junit.jupiter.api.assertDoesNotThrow -import org.opendc.simulator.compute.SimBareMetalMachine -import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernors -import org.opendc.simulator.compute.kernel.interference.VmInterferenceModel -import org.opendc.simulator.compute.model.Cpu -import org.opendc.simulator.compute.model.MachineModel -import org.opendc.simulator.compute.model.MemoryUnit -import org.opendc.simulator.compute.runWorkload -import org.opendc.simulator.compute.workload.SimTrace -import org.opendc.simulator.compute.workload.SimTraceFragment -import org.opendc.simulator.flow2.FlowEngine -import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory -import org.opendc.simulator.kotlin.runSimulation -import java.util.SplittableRandom - -/** - * Test suite for the [SimHypervisor] class. - */ -internal class SimFairShareHypervisorTest { - private lateinit var model: MachineModel - - @BeforeEach - fun setUp() { - model = - MachineModel( - Cpu( - 0, - 1, - 3200.0, - "Intel", - "Xeon", - "amd64", - ), - // memory - MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - ) - } - - /** - * Test overcommitting of resources via the hypervisor with a single VM. - */ - @Test - fun testOvercommittedSingle() = - runSimulation { - val duration = 5 * 60L - val workloadA = - 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(dispatcher) - 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) - vm.runWorkload(workloadA) - - yield() - machine.cancel() - - assertAll( - { assertEquals(319781, hypervisor.counters.cpuActiveTime, "Active time does not match") }, - { assertEquals(880219, hypervisor.counters.cpuIdleTime, "Idle time does not match") }, - { assertEquals(28125, hypervisor.counters.cpuStealTime, "Steal time does not match") }, - { assertEquals(1200000, timeSource.millis()) { "Current time is correct" } }, - ) - } - - /** - * Test overcommitting of resources via the hypervisor with two VMs. - */ - @Test - fun testOvercommittedDual() = - runSimulation { - val duration = 5 * 60L - val workloadA = - 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 = - 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) - - val engine = FlowEngine.create(dispatcher) - 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 { - launch { - val vm = hypervisor.newMachine(model) - vm.runWorkload(workloadA) - hypervisor.removeMachine(vm) - } - val vm = hypervisor.newMachine(model) - vm.runWorkload(workloadB) - hypervisor.removeMachine(vm) - } - yield() - machine.cancel() - yield() - - assertAll( - { assertEquals(329250, hypervisor.counters.cpuActiveTime, "Active time does not match") }, - { assertEquals(870750, hypervisor.counters.cpuIdleTime, "Idle time does not match") }, - { assertEquals(318750, hypervisor.counters.cpuStealTime, "Steal time does not match") }, - { assertEquals(1200000, timeSource.millis()) }, - ) - } - - @Test - fun testMultipleCPUs() = - runSimulation { - val model = - MachineModel( - Cpu( - 0, - 2, - 3200.0, - "Intel", - "Xeon", - "amd64", - ), - // memory - MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - ) - - val engine = FlowEngine.create(dispatcher) - 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) } - } - - machine.cancel() - } - - @Test - fun testInterference() = - runSimulation { - val model = - MachineModel( - Cpu( - 0, - 2, - 3200.0, - "Intel", - "Xeon", - "amd64", - ), - // memory - MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - ) - - val interferenceModel = - VmInterferenceModel.builder() - .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.create(dispatcher) - val graph = engine.newGraph() - - val machine = SimBareMetalMachine.create(graph, model) - val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(0L)) - - val duration = 5 * 60L - val workloadA = - 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 = - 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) - } - - coroutineScope { - launch { - val vm = hypervisor.newMachine(model) - vm.runWorkload(workloadA, meta = mapOf("interference-model" to interferenceModel.getProfile("a")!!)) - hypervisor.removeMachine(vm) - } - val vm = hypervisor.newMachine(model) - vm.runWorkload(workloadB, meta = mapOf("interference-model" to interferenceModel.getProfile("b")!!)) - hypervisor.removeMachine(vm) - } - - machine.cancel() - } -} 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 deleted file mode 100644 index b4ae372c..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt +++ /dev/null @@ -1,234 +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.kernel - -import kotlinx.coroutines.launch -import kotlinx.coroutines.yield -import org.junit.jupiter.api.Assertions.assertAll -import org.junit.jupiter.api.Assertions.assertDoesNotThrow -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.compute.SimBareMetalMachine -import org.opendc.simulator.compute.model.Cpu -import org.opendc.simulator.compute.model.MachineModel -import org.opendc.simulator.compute.model.MemoryUnit -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.SimWorkloads -import org.opendc.simulator.flow2.FlowEngine -import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory -import org.opendc.simulator.kotlin.runSimulation -import java.util.SplittableRandom - -/** - * A test suite for a space-shared [SimHypervisor]. - */ -internal class SimSpaceSharedHypervisorTest { - private lateinit var machineModel: MachineModel - - @BeforeEach - fun setUp() { - machineModel = - MachineModel( - Cpu( - 0, - 1, - 3200.0, - "Intel", - "Xeon", - "amd64", - ), - // memory - MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - ) - } - - /** - * Test a trace workload. - */ - @Test - fun testTrace() = - runSimulation { - val duration = 5 * 60L - val workloadA = - 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(dispatcher) - 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) - vm.runWorkload(workloadA) - yield() - - hypervisor.removeMachine(vm) - machine.cancel() - - assertEquals(5 * 60L * 4000, timeSource.millis()) { "Took enough time" } - } - - /** - * Test runtime workload on hypervisor. - */ - @Test - fun testRuntimeWorkload() = - runSimulation { - val duration = 5 * 60L * 1000 - val workload = SimWorkloads.runtime(duration, 1.0) - val engine = FlowEngine.create(dispatcher) - 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(workload) - hypervisor.removeMachine(vm) - - machine.cancel() - - assertEquals(duration, timeSource.millis()) { "Took enough time" } - } - - /** - * Test FLOPs workload on hypervisor. - */ - @Test - fun testFlopsWorkload() = - runSimulation { - val duration = 5 * 60L * 1000 - val workload = SimWorkloads.flops((duration * 3.2).toLong(), 1.0) - val engine = FlowEngine.create(dispatcher) - 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(workload) - machine.cancel() - - assertEquals(duration, timeSource.millis()) { "Took enough time" } - } - - /** - * Test two workloads running sequentially. - */ - @Test - fun testTwoWorkloads() = - runSimulation { - val duration = 5 * 60L * 1000 - val engine = FlowEngine.create(dispatcher) - 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(SimWorkloads.runtime(duration, 1.0)) - hypervisor.removeMachine(vm) - - yield() - - val vm2 = hypervisor.newMachine(machineModel) - vm2.runWorkload(SimWorkloads.runtime(duration, 1.0)) - hypervisor.removeMachine(vm2) - - machine.cancel() - - assertEquals(duration * 2, timeSource.millis()) { "Took enough time" } - } - - /** - * Test concurrent workloads on the machine. - */ - @Test - fun testConcurrentWorkloadFails() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - 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) - launch { vm.runWorkload(SimWorkloads.runtime(10_000, 1.0)) } - yield() - - assertAll( - { assertFalse(hypervisor.canFit(machineModel)) }, - { assertThrows { hypervisor.newMachine(machineModel) } }, - ) - - machine.cancel() - vm.cancel() - } - - /** - * Test concurrent workloads on the machine. - */ - @Test - fun testConcurrentWorkloadSucceeds() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = SimBareMetalMachine.create(graph, machineModel) - val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L)) - - launch { machine.runWorkload(hypervisor) } - yield() - - hypervisor.removeMachine(hypervisor.newMachine(machineModel)) - - assertAll( - { assertTrue(hypervisor.canFit(machineModel)) }, - { assertDoesNotThrow { hypervisor.newMachine(machineModel) } }, - ) - - machine.cancel() - } -} 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 deleted file mode 100644 index 4a930df6..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt +++ /dev/null @@ -1,94 +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.kernel.cpufreq - -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.junit.jupiter.api.Test - -/** - * Test suite for the conservative [ScalingGovernor]. - */ -internal class ConservativeScalingGovernorTest { - @Test - fun testSetStartLimitWithoutPStates() { - val cpuCapacity = 4100.0 - val minSpeed = cpuCapacity / 2 - val defaultThreshold = 0.8 - val defaultStepSize = 0.05 * cpuCapacity - val governor = ScalingGovernors.conservative(defaultThreshold) - - val policy = mockk(relaxUnitFun = true) - every { policy.max } returns cpuCapacity - every { policy.min } returns minSpeed - - var target = 0.0 - every { policy.target } answers { target } - every { policy.target = any() } propertyType Double::class answers { target = value } - - val logic = governor.newGovernor(policy) - logic.onStart() - logic.onLimit(0.5) - - // Upwards scaling - logic.onLimit(defaultThreshold + 0.2) - - // Downwards scaling - logic.onLimit(defaultThreshold + 0.1) - - verify(exactly = 2) { policy.target = minSpeed } - verify(exactly = 1) { policy.target = minSpeed + defaultStepSize } - } - - @Test - fun testSetStartLimitWithPStatesAndParams() { - val firstPState = 1000.0 - val cpuCapacity = 4100.0 - val minSpeed = firstPState - val threshold = 0.5 - val stepSize = 0.02 * cpuCapacity - val governor = ScalingGovernors.conservative(threshold, stepSize) - - val policy = mockk(relaxUnitFun = true) - every { policy.max } returns cpuCapacity - every { policy.min } returns firstPState - - var target = 0.0 - every { policy.target } answers { target } - every { policy.target = any() } propertyType Double::class answers { target = value } - - val logic = governor.newGovernor(policy) - logic.onStart() - logic.onLimit(0.5) - - // Upwards scaling - logic.onLimit(threshold + 0.2) - - // Downwards scaling - logic.onLimit(threshold + 0.1) - - verify(exactly = 2) { policy.target = minSpeed } - verify(exactly = 1) { policy.target = minSpeed + stepSize } - } -} 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 deleted file mode 100644 index d6a7090b..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt +++ /dev/null @@ -1,78 +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.kernel.cpufreq - -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.junit.jupiter.api.Test - -/** - * Test suite for the on-demand [ScalingGovernor]. - */ -internal class OnDemandScalingGovernorTest { - @Test - fun testSetStartLimitWithoutPStates() { - val cpuCapacity = 4100.0 - val minSpeed = cpuCapacity / 2 - val defaultThreshold = 0.8 - val governor = ScalingGovernors.ondemand(defaultThreshold) - - val policy = mockk(relaxUnitFun = true) - every { policy.min } returns minSpeed - every { policy.max } returns cpuCapacity - - val logic = governor.newGovernor(policy) - logic.onStart() - verify(exactly = 1) { policy.target = minSpeed } - - logic.onLimit(0.5) - verify(exactly = 1) { policy.target = minSpeed + 0.5 * (cpuCapacity - minSpeed) / 100 } - - logic.onLimit(defaultThreshold) - verify(exactly = 1) { policy.target = cpuCapacity } - } - - @Test - fun testSetStartLimitWithPStatesAndParams() { - val firstPState = 1000.0 - val cpuCapacity = 4100.0 - val threshold = 0.5 - val governor = ScalingGovernors.ondemand(threshold) - - val policy = mockk(relaxUnitFun = true) - every { policy.max } returns cpuCapacity - every { policy.min } returns firstPState - - val logic = governor.newGovernor(policy) - - logic.onStart() - verify(exactly = 1) { policy.target = firstPState } - - logic.onLimit(0.1) - verify(exactly = 1) { policy.target = firstPState + 0.1 * (cpuCapacity - firstPState) / 100 } - - logic.onLimit(threshold) - verify(exactly = 1) { policy.target = cpuCapacity } - } -} 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 deleted file mode 100644 index f03f41fe..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt +++ /dev/null @@ -1,50 +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.kernel.cpufreq - -import io.mockk.every -import io.mockk.spyk -import io.mockk.verify -import org.junit.jupiter.api.Test - -/** - * Test suite for the [PerformanceScalingGovernor] - */ -internal class PerformanceScalingGovernorTest { - @Test - fun testSetStartLimit() { - val policy = spyk() - val logic = ScalingGovernors.performance().newGovernor(policy) - - every { policy.max } returns 4100.0 - - logic.onStart() - verify(exactly = 1) { policy.target = 4100.0 } - - logic.onLimit(0.0) - verify(exactly = 1) { policy.target = 4100.0 } - - logic.onLimit(1.0) - verify(exactly = 1) { policy.target = 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 deleted file mode 100644 index 4cee8199..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt +++ /dev/null @@ -1,72 +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.kernel.cpufreq - -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.junit.jupiter.api.Test - -/** - * Test suite for the [PowerSaveScalingGovernor] - */ -internal class PowerSaveScalingGovernorTest { - @Test - fun testSetStartLimitWithoutPStates() { - val cpuCapacity = 4100.0 - val minSpeed = cpuCapacity / 2 - val policy = mockk(relaxUnitFun = true) - val logic = ScalingGovernors.powerSave().newGovernor(policy) - - every { policy.max } returns cpuCapacity - every { policy.min } returns minSpeed - - logic.onStart() - - logic.onLimit(0.0) - verify(exactly = 1) { policy.target = minSpeed } - - logic.onLimit(1.0) - verify(exactly = 1) { policy.target = minSpeed } - } - - @Test - fun testSetStartLimitWithPStates() { - val cpuCapacity = 4100.0 - val firstPState = 1000.0 - val policy = mockk(relaxUnitFun = true) - val logic = ScalingGovernors.powerSave().newGovernor(policy) - - every { policy.max } returns cpuCapacity - every { policy.min } returns firstPState - - logic.onStart() - verify(exactly = 1) { policy.target = firstPState } - - logic.onLimit(0.0) - verify(exactly = 1) { policy.target = firstPState } - - logic.onLimit(1.0) - verify(exactly = 1) { policy.target = firstPState } - } -} 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 deleted file mode 100644 index e3bea821..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt +++ /dev/null @@ -1,180 +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 org.junit.jupiter.api.Assertions.assertAll -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream -import kotlin.math.pow - -internal class PowerModelTest { - private val epsilon = 10.0.pow(-3) - private val cpuUtil = 0.9 - - @ParameterizedTest - @MethodSource("machinePowerModelArgs") - fun `compute power consumption given CPU loads`( - powerModel: CpuPowerModel, - expectedPowerConsumption: Double, - ) { - val computedPowerConsumption = powerModel.computePower(cpuUtil) - assertEquals(expectedPowerConsumption, computedPowerConsumption, epsilon) - } - - @ParameterizedTest - @MethodSource("machinePowerModelArgs") - fun `ignore idle power when computing power consumptions`( - powerModel: CpuPowerModel, - expectedPowerConsumption: Double, - ) { - val zeroPowerModel = CpuPowerModels.zeroIdle(powerModel) - - assertAll( - { assertEquals(expectedPowerConsumption, zeroPowerModel.computePower(cpuUtil), epsilon) }, - { assertEquals(0.0, zeroPowerModel.computePower(0.0)) }, - ) - } - - @Test - fun `compute power draw by the SPEC benchmark model`() { - 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)) }, - { assertEquals(58.4 + (98 - 58.4) / 5, powerModel.computePower(0.02)) }, - { assertEquals(98.0, powerModel.computePower(0.1)) }, - { assertEquals(140.0, powerModel.computePower(0.5)) }, - { assertEquals(189.0, powerModel.computePower(0.8)) }, - { assertEquals(189.0 + 0.7 * 10 * (205 - 189) / 10, powerModel.computePower(0.87)) }, - { assertEquals(205.0, powerModel.computePower(0.9)) }, - { assertEquals(222.0, powerModel.computePower(1.0)) }, - ) - } - - @Test - fun `test linear model`() { - val powerModel = CpuPowerModels.linear(400.0, 200.0) - - assertAll( - { assertEquals(200.0, powerModel.computePower(-0.1)) }, - { assertEquals(200.0, powerModel.computePower(0.0)) }, - { assertEquals(220.0, powerModel.computePower(0.1)) }, - { assertEquals(240.0, powerModel.computePower(0.2)) }, - { assertEquals(260.0, powerModel.computePower(0.3)) }, - { assertEquals(280.0, powerModel.computePower(0.4)) }, - { assertEquals(300.0, powerModel.computePower(0.5)) }, - { assertEquals(320.0, powerModel.computePower(0.6)) }, - { assertEquals(340.0, powerModel.computePower(0.7)) }, - { assertEquals(360.0, powerModel.computePower(0.8)) }, - { assertEquals(380.0, powerModel.computePower(0.9)) }, - { assertEquals(400.0, powerModel.computePower(1.0)) }, - { assertEquals(400.0, powerModel.computePower(1.1)) }, - ) - } - - @Test - fun `test sqrt model`() { - val powerModel = CpuPowerModels.sqrt(400.0, 200.0) - - assertAll( - { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) }, - { assertEquals(200.0, powerModel.computePower(0.0), 1.0) }, - { assertEquals(263.0, powerModel.computePower(0.1), 1.0) }, - { assertEquals(289.0, powerModel.computePower(0.2), 1.0) }, - { assertEquals(309.0, powerModel.computePower(0.3), 1.0) }, - { assertEquals(326.0, powerModel.computePower(0.4), 1.0) }, - { assertEquals(341.0, powerModel.computePower(0.5), 1.0) }, - { assertEquals(354.0, powerModel.computePower(0.6), 1.0) }, - { assertEquals(367.0, powerModel.computePower(0.7), 1.0) }, - { assertEquals(378.0, powerModel.computePower(0.8), 1.0) }, - { assertEquals(389.0, powerModel.computePower(0.9), 1.0) }, - { assertEquals(400.0, powerModel.computePower(1.0), 1.0) }, - { assertEquals(400.0, powerModel.computePower(1.1), 1.0) }, - ) - } - - @Test - fun `test square model`() { - val powerModel = CpuPowerModels.square(400.0, 200.0) - - assertAll( - { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) }, - { assertEquals(200.0, powerModel.computePower(0.0), 1.0) }, - { assertEquals(202.0, powerModel.computePower(0.1), 1.0) }, - { assertEquals(208.0, powerModel.computePower(0.2), 1.0) }, - { assertEquals(218.0, powerModel.computePower(0.3), 1.0) }, - { assertEquals(232.0, powerModel.computePower(0.4), 1.0) }, - { assertEquals(250.0, powerModel.computePower(0.5), 1.0) }, - { assertEquals(272.0, powerModel.computePower(0.6), 1.0) }, - { assertEquals(298.0, powerModel.computePower(0.7), 1.0) }, - { assertEquals(328.0, powerModel.computePower(0.8), 1.0) }, - { assertEquals(362.0, powerModel.computePower(0.9), 1.0) }, - { assertEquals(400.0, powerModel.computePower(1.0), 1.0) }, - { assertEquals(400.0, powerModel.computePower(1.1), 1.0) }, - ) - } - - @Test - fun `test cubic model`() { - val powerModel = CpuPowerModels.cubic(400.0, 200.0) - - assertAll( - { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) }, - { assertEquals(200.0, powerModel.computePower(0.0), 1.0) }, - { assertEquals(200.0, powerModel.computePower(0.1), 1.0) }, - { assertEquals(201.0, powerModel.computePower(0.2), 1.0) }, - { assertEquals(205.0, powerModel.computePower(0.3), 1.0) }, - { assertEquals(212.0, powerModel.computePower(0.4), 1.0) }, - { assertEquals(225.0, powerModel.computePower(0.5), 1.0) }, - { assertEquals(243.0, powerModel.computePower(0.6), 1.0) }, - { assertEquals(268.0, powerModel.computePower(0.7), 1.0) }, - { assertEquals(302.0, powerModel.computePower(0.8), 1.0) }, - { assertEquals(345.0, powerModel.computePower(0.9), 1.0) }, - { assertEquals(400.0, powerModel.computePower(1.0), 1.0) }, - { assertEquals(400.0, powerModel.computePower(1.1), 1.0) }, - ) - } - - @Suppress("unused") - private companion object { - @JvmStatic - fun machinePowerModelArgs(): Stream = - Stream.of( - 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/SimChainWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt deleted file mode 100644 index 582635fc..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (c) 2022 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.workload - -import io.mockk.every -import io.mockk.mockk -import io.mockk.spyk -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opendc.simulator.compute.SimBareMetalMachine -import org.opendc.simulator.compute.SimMachineContext -import org.opendc.simulator.compute.model.Cpu -import org.opendc.simulator.compute.model.MachineModel -import org.opendc.simulator.compute.model.MemoryUnit -import org.opendc.simulator.compute.runWorkload -import org.opendc.simulator.flow2.FlowEngine -import org.opendc.simulator.kotlin.runSimulation - -/** - * Test suite for the [SimChainWorkload] class. - */ -class SimChainWorkloadTest { - private lateinit var machineModel: MachineModel - - @BeforeEach - fun setUp() { - machineModel = - MachineModel( - Cpu( - 0, - 2, - 1000.0, - "Intel", - "Xeon", - "amd64", - ), - // memory - MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - ) - } - - @Test - fun testMultipleWorkloads() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workload = - SimWorkloads.chain( - SimWorkloads.runtime(1000, 1.0, 0L, 0L), - SimWorkloads.runtime(1000, 1.0, 0L, 0L), - ) - - machine.runWorkload(workload) - - assertEquals(2000, timeSource.millis()) - } - - @Test - fun testStartFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workloadA = mockk() - every { workloadA.onStart(any()) } throws IllegalStateException("Staged") - every { workloadA.onStop(any()) } returns Unit - - val workload = - SimWorkloads.chain( - workloadA, - SimWorkloads.runtime(1000, 1.0, 0L, 0L), - ) - - assertThrows { machine.runWorkload(workload) } - - assertEquals(0, timeSource.millis()) - } - -// @Test - fun testStartFailureSecond() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workloadA = mockk() - every { workloadA.onStart(any()) } throws IllegalStateException("Staged") - every { workloadA.onStop(any()) } returns Unit - - val workload = - SimWorkloads.chain( - SimWorkloads.runtime(1000, 1.0), - workloadA, - SimWorkloads.runtime(1000, 1.0), - ) - - assertThrows { machine.runWorkload(workload) } - - assertEquals(1000, timeSource.millis()) - } - - @Test - fun testStopFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workloadA = spyk(SimRuntimeWorkload(1000, 1.0)) - every { workloadA.onStop(any()) } throws IllegalStateException("Staged") - - val workload = - SimWorkloads.chain( - workloadA, - SimWorkloads.runtime(1000, 1.0), - ) - - assertThrows { machine.runWorkload(workload) } - - assertEquals(1000, timeSource.millis()) - } - - @Test - fun testStopFailureSecond() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workloadA = spyk(SimRuntimeWorkload(1000, 1.0)) - every { workloadA.onStop(any()) } throws IllegalStateException("Staged") - - val workload = - SimWorkloads.chain( - SimWorkloads.runtime(1000, 1.0), - workloadA, - SimWorkloads.runtime(1000, 1.0), - ) - - assertThrows { machine.runWorkload(workload) } - - assertEquals(2000, timeSource.millis()) - } - -// @Test - fun testStartAndStopFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workloadA = mockk() - every { workloadA.onStart(any()) } throws IllegalStateException() - every { workloadA.onStop(any()) } throws IllegalStateException() - - val workload = - SimWorkloads.chain( - SimRuntimeWorkload(1000, 1.0), - workloadA, - ) - - val exc = assertThrows { machine.runWorkload(workload) } - - assertEquals(2, exc.cause!!.suppressedExceptions.size) - assertEquals(1000, timeSource.millis()) - } - -// @Test - fun testShutdownAndStopFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workloadA = mockk() - every { workloadA.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } - every { workloadA.onStop(any()) } throws IllegalStateException() - - val workload = - SimWorkloads.chain( - SimRuntimeWorkload(1000, 1.0), - workloadA, - ) - - val exc = assertThrows { machine.runWorkload(workload) } - - assertEquals(1, exc.cause!!.suppressedExceptions.size) - assertEquals(1000, timeSource.millis()) - } - -// @Test - fun testShutdownAndStartFailure() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - val workloadA = mockk(relaxUnitFun = true) - every { workloadA.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } - - val workloadB = mockk(relaxUnitFun = true) - every { workloadB.onStart(any()) } throws IllegalStateException() - - val workload = - SimWorkloads.chain( - SimRuntimeWorkload(1000, 1.0), - workloadA, - workloadB, - ) - - val exc = assertThrows { machine.runWorkload(workload) } - assertEquals(1, exc.cause!!.suppressedExceptions.size) - assertEquals(1000, timeSource.millis()) - } - - @Test - fun testSnapshot() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = SimBareMetalMachine.create(graph, machineModel) - val workload = - SimWorkloads.chain( - SimWorkloads.runtime(1000, 1.0), - SimWorkloads.runtime(1000, 1.0), - ) - - val job = launch { machine.runWorkload(workload) } - delay(500L) - - workload.makeSnapshot(500L) - val snapshot = workload.getSnapshot() - - job.join() - - assertEquals(2000, timeSource.millis()) - - machine.runWorkload(snapshot) - - assertEquals(4000, timeSource.millis()) - } -} 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 deleted file mode 100644 index edbc0571..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020 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.workload - -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows - -/** - * Test suite for [SimFlopsWorkload] class. - */ -class SimFlopsWorkloadTest { - @Test - fun testFlopsNonNegative() { - assertThrows("FLOPs must be non-negative") { - SimFlopsWorkload(-1, 1.0) - } - } - - @Test - fun testUtilizationNonZero() { - assertThrows("Utilization cannot be zero") { - SimFlopsWorkload(1, 0.0) - } - } - - @Test - fun testUtilizationPositive() { - assertThrows("Utilization cannot be negative") { - SimFlopsWorkload(1, -1.0) - } - } - - @Test - fun testUtilizationNotLargerThanOne() { - assertThrows("Utilization cannot be larger than one") { - SimFlopsWorkload(1, 2.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 deleted file mode 100644 index a53f6c65..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt +++ /dev/null @@ -1,160 +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.workload - -import kotlinx.coroutines.delay -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.opendc.simulator.compute.SimBareMetalMachine -import org.opendc.simulator.compute.model.Cpu -import org.opendc.simulator.compute.model.MachineModel -import org.opendc.simulator.compute.model.MemoryUnit -import org.opendc.simulator.compute.runWorkload -import org.opendc.simulator.flow2.FlowEngine -import org.opendc.simulator.kotlin.runSimulation - -/** - * Test suite for the [SimTraceWorkloadTest] class. - */ -class SimTraceWorkloadTest { - private lateinit var machineModel: MachineModel - - @BeforeEach - fun setUp() { - machineModel = - MachineModel( - Cpu( - 0, - 2, - 1000.0, - "Intel", - "Xeon", - "amd64", - ), - // memory - MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), - ) - } - - @Test - fun testSmoke() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - 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), - ).createWorkload(0) - - machine.runWorkload(workload) - - assertEquals(4000, timeSource.millis()) - } - -// @Test // fixme: Fix delayed start and enable test - fun testOffset() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - 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), - ).createWorkload(1000) - - machine.runWorkload(workload) - - assertEquals(5000, timeSource.millis()) // fixme: should be 5000 but this is 4000 for now to make all tests succeed - } - - @Test - fun testSkipFragment() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - 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), - ).createWorkload(0) - - delay(1000L) - machine.runWorkload(workload) - - assertEquals(4000, timeSource.millis()) - } - - @Test - fun testZeroCores() = - runSimulation { - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = - SimBareMetalMachine.create( - graph, - machineModel, - ) - - 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), - ).createWorkload(0) - - machine.runWorkload(workload) - - assertEquals(4000, timeSource.millis()) - } -} -- cgit v1.2.3