summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-compute/src/test
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-10-28 16:46:47 +0200
committerGitHub <noreply@github.com>2022-10-28 16:46:47 +0200
commitb96acc687f59b698fbc4d4c984d77b008cd4051b (patch)
treeff4d99454259b92ec4484433bb716acd6319faa1 /opendc-simulator/opendc-simulator-compute/src/test
parentc4cfb6f6e0507f335fd88935857f20e88c34abd0 (diff)
parent8bf940eb7b59b5e5e326cfc06d51bdb54393f33b (diff)
Support custom start-up and clean-up time for VMs (#112)
This pull request implements customizable startup and clean-up time for virtual machine. We achieve this by implementing `SimWorkload` chaining and modelling start-up and clean-up time using `SimWorkload` as well. Implements #33 ## Implementation Notes :hammer_and_pick: * Store method parameters in class files * Add completion parameter to startWorkload * Provide workload constructors in SimWorkloads * Add support for resetting machine context * Add support for chaining workloads * Use workload chaining for boot delay * Model host boot time * Do not suspend on guest start * Use static logger field ## Breaking API Changes :warning: * `SimMachine#startWorkload` now has a third parameter `completion` which is invoked when the workload finishes executing (either due to failure or success). * `SimFlopsWorkload` and `SimRuntimeWorkload` can be instantiated via `SimWorkloads`.
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src/test')
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt14
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt13
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt176
3 files changed, 189 insertions, 14 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 f0aae15b..266839bd 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
@@ -40,9 +40,9 @@ 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.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.SimWorkloads
import org.opendc.simulator.flow2.FlowEngine
import org.opendc.simulator.flow2.source.SimpleFlowSource
import org.opendc.simulator.kotlin.runSimulation
@@ -78,7 +78,7 @@ class SimMachineTest {
machineModel
)
- machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0))
+ machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0))
// Two cores execute 1000 MFlOps per second (1000 ms)
assertEquals(1000, clock.millis())
@@ -123,7 +123,7 @@ class SimMachineTest {
machineModel
)
- machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0))
+ machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0))
// Two sockets with two cores execute 2000 MFlOps per second (500 ms)
assertEquals(500, clock.millis())
@@ -142,7 +142,7 @@ class SimMachineTest {
source.connect(machine.psu)
coroutineScope {
- launch { machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) }
+ launch { machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0)) }
yield()
assertAll(
@@ -304,7 +304,7 @@ class SimMachineTest {
try {
coroutineScope {
- launch { machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0)) }
+ launch { machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0)) }
cancel()
}
} catch (_: CancellationException) {
@@ -326,11 +326,11 @@ class SimMachineTest {
coroutineScope {
launch {
- machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0))
+ machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0))
}
assertThrows<IllegalStateException> {
- machine.runWorkload(SimFlopsWorkload(2_000, /*utilization*/ 1.0))
+ machine.runWorkload(SimWorkloads.flops(2_000, /*utilization*/ 1.0))
}
}
}
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 ba5a5c68..d11b91ee 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
@@ -38,10 +38,9 @@ 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.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.SimWorkloads
import org.opendc.simulator.flow2.FlowEngine
import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory
import org.opendc.simulator.kotlin.runSimulation
@@ -99,7 +98,7 @@ internal class SimSpaceSharedHypervisorTest {
@Test
fun testRuntimeWorkload() = runSimulation {
val duration = 5 * 60L * 1000
- val workload = SimRuntimeWorkload(duration, 1.0)
+ val workload = SimWorkloads.runtime(duration, 1.0)
val engine = FlowEngine.create(coroutineContext, clock)
val graph = engine.newGraph()
@@ -123,7 +122,7 @@ internal class SimSpaceSharedHypervisorTest {
@Test
fun testFlopsWorkload() = runSimulation {
val duration = 5 * 60L * 1000
- val workload = SimFlopsWorkload((duration * 3.2).toLong(), 1.0)
+ val workload = SimWorkloads.flops((duration * 3.2).toLong(), 1.0)
val engine = FlowEngine.create(coroutineContext, clock)
val graph = engine.newGraph()
@@ -155,13 +154,13 @@ internal class SimSpaceSharedHypervisorTest {
yield()
val vm = hypervisor.newMachine(machineModel)
- vm.runWorkload(SimRuntimeWorkload(duration, 1.0))
+ vm.runWorkload(SimWorkloads.runtime(duration, 1.0))
hypervisor.removeMachine(vm)
yield()
val vm2 = hypervisor.newMachine(machineModel)
- vm2.runWorkload(SimRuntimeWorkload(duration, 1.0))
+ vm2.runWorkload(SimWorkloads.runtime(duration, 1.0))
hypervisor.removeMachine(vm2)
machine.cancel()
@@ -184,7 +183,7 @@ internal class SimSpaceSharedHypervisorTest {
yield()
val vm = hypervisor.newMachine(machineModel)
- launch { vm.runWorkload(SimFlopsWorkload(10_000, 1.0)) }
+ launch { vm.runWorkload(SimWorkloads.runtime(10_000, 1.0)) }
yield()
assertAll(
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
new file mode 100644
index 00000000..6bf05f65
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt
@@ -0,0 +1,176 @@
+/*
+ * 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 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.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.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() {
+ 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) }
+ )
+ }
+
+ @Test
+ fun testMultipleWorkloads() = runSimulation {
+ val engine = FlowEngine.create(coroutineContext, clock)
+ val graph = engine.newGraph()
+
+ val machine = SimBareMetalMachine.create(
+ graph,
+ machineModel
+ )
+
+ val workload =
+ SimWorkloads.chain(
+ SimRuntimeWorkload(1000, 1.0),
+ SimRuntimeWorkload(1000, 1.0)
+ )
+
+ machine.runWorkload(workload)
+
+ assertEquals(2000, clock.millis())
+ }
+
+ @Test
+ fun testStartFailure() = runSimulation {
+ val engine = FlowEngine.create(coroutineContext, clock)
+ val graph = engine.newGraph()
+
+ val machine = SimBareMetalMachine.create(
+ graph,
+ machineModel
+ )
+
+ val workloadA = mockk<SimWorkload>()
+ every { workloadA.onStart(any()) } throws IllegalStateException("Staged")
+ every { workloadA.onStop(any()) } returns Unit
+
+ val workload =
+ SimWorkloads.chain(
+ workloadA,
+ SimRuntimeWorkload(1000, 1.0)
+ )
+
+ machine.runWorkload(workload)
+
+ assertEquals(0, clock.millis())
+ }
+
+ @Test
+ fun testStartFailureSecond() = runSimulation {
+ val engine = FlowEngine.create(coroutineContext, clock)
+ val graph = engine.newGraph()
+
+ val machine = SimBareMetalMachine.create(
+ graph,
+ machineModel
+ )
+
+ val workloadA = mockk<SimWorkload>()
+ every { workloadA.onStart(any()) } throws IllegalStateException("Staged")
+ every { workloadA.onStop(any()) } returns Unit
+
+ val workload =
+ SimWorkloads.chain(
+ SimRuntimeWorkload(1000, 1.0),
+ workloadA,
+ SimRuntimeWorkload(1000, 1.0)
+ )
+
+ machine.runWorkload(workload)
+
+ assertEquals(1000, clock.millis())
+ }
+
+ @Test
+ fun testStopFailure() = runSimulation {
+ val engine = FlowEngine.create(coroutineContext, clock)
+ val graph = engine.newGraph()
+
+ val machine = SimBareMetalMachine.create(
+ graph,
+ machineModel
+ )
+
+ val workloadA = spyk<SimWorkload>(SimRuntimeWorkload(1000, 1.0))
+ every { workloadA.onStop(any()) } throws IllegalStateException("Staged")
+
+ val workload =
+ SimWorkloads.chain(
+ workloadA,
+ SimRuntimeWorkload(1000, 1.0)
+ )
+
+ machine.runWorkload(workload)
+
+ assertEquals(1000, clock.millis())
+ }
+
+ @Test
+ fun testStopFailureSecond() = runSimulation {
+ val engine = FlowEngine.create(coroutineContext, clock)
+ val graph = engine.newGraph()
+
+ val machine = SimBareMetalMachine.create(
+ graph,
+ machineModel
+ )
+
+ val workloadA = spyk<SimWorkload>(SimRuntimeWorkload(1000, 1.0))
+ every { workloadA.onStop(any()) } throws IllegalStateException("Staged")
+
+ val workload =
+ SimWorkloads.chain(
+ SimRuntimeWorkload(1000, 1.0),
+ workloadA,
+ SimRuntimeWorkload(1000, 1.0)
+ )
+
+ machine.runWorkload(workload)
+
+ assertEquals(2000, clock.millis())
+ }
+}