summaryrefslogtreecommitdiff
path: root/opendc-compute/opendc-compute-simulator
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-09-23 12:49:32 +0200
committerGitHub <noreply@github.com>2022-09-23 12:49:32 +0200
commit2d2a3854d355bd4b074ef651f291d34081e70d96 (patch)
treee99c4bf7e5647341c1e269797f7f46099753436f /opendc-compute/opendc-compute-simulator
parent8d1d091f093e6ac32dba1e6a4f74490b280fcc4b (diff)
parent3d5eb562227dcad5a8a60f31b96e6d68f7774fb2 (diff)
merge: Do not require interference model during topology construction (#102)
This pull request refactors the existing workload interference model in order to remove a dependency on it during the topology construction. With this change, interference domains (e.g., a single host) can be constructed independently of the interference profiles of virtual machines. ## Implementation Notes :hammer_and_pick: * Move VM interference model into compute simulator * Remove convergence listener parameter * Remove FlowEngine from SimMachineContext * Remove timestamp parameter from SimTrace * Pass interference key via parameter * Move interference logic into VmInterferenceMember * Prevent boxing in interference algorithm * Extract Random dependency from interference model * Add separate error host state * Simplify constructor of SimHost * Make interference domain independent of profile ## External Dependencies :four_leaf_clover: * N/A ## Breaking API Changes :warning: * The interface of `VmInterferenceModel` is changed. Users do not need to provide a seed for the model anymore. * A `VmInterferenceModel` should be passed via the metadata parameter of `startWorkload` to enable workload interference.
Diffstat (limited to 'opendc-compute/opendc-compute-simulator')
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt87
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt2
-rw-r--r--opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt22
3 files changed, 36 insertions, 75 deletions
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
index c28239b4..c04573b5 100644
--- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
@@ -35,17 +35,10 @@ import org.opendc.compute.simulator.internal.Guest
import org.opendc.compute.simulator.internal.GuestListener
import org.opendc.simulator.compute.*
import org.opendc.simulator.compute.kernel.SimHypervisor
-import org.opendc.simulator.compute.kernel.SimHypervisorProvider
-import org.opendc.simulator.compute.kernel.cpufreq.PerformanceScalingGovernor
-import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor
-import org.opendc.simulator.compute.kernel.interference.VmInterferenceDomain
import org.opendc.simulator.compute.model.MachineModel
import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.power.ConstantPowerModel
-import org.opendc.simulator.compute.power.PowerDriver
-import org.opendc.simulator.compute.power.SimplePowerDriver
import org.opendc.simulator.compute.workload.SimWorkload
-import org.opendc.simulator.flow.FlowEngine
+import java.time.Clock
import java.time.Duration
import java.time.Instant
import java.util.*
@@ -57,44 +50,20 @@ import kotlin.coroutines.CoroutineContext
public class SimHost(
override val uid: UUID,
override val name: String,
- model: MachineModel,
override val meta: Map<String, Any>,
- context: CoroutineContext,
- engine: FlowEngine,
- hypervisorProvider: SimHypervisorProvider,
- scalingGovernor: ScalingGovernor = PerformanceScalingGovernor(),
- powerDriver: PowerDriver = SimplePowerDriver(ConstantPowerModel(0.0)),
+ private val context: CoroutineContext,
+ private val clock: Clock,
+ private val machine: SimBareMetalMachine,
+ private val hypervisor: SimHypervisor,
private val mapper: SimWorkloadMapper = SimMetaWorkloadMapper(),
- interferenceDomain: VmInterferenceDomain? = null,
private val optimize: Boolean = false
) : Host, AutoCloseable {
/**
- * The [CoroutineScope] of the host bounded by the lifecycle of the host.
- */
- private val scope: CoroutineScope = CoroutineScope(context + Job())
-
- /**
- * The clock instance used by the host.
- */
- private val clock = engine.clock
-
- /**
* The event listeners registered with this host.
*/
private val listeners = mutableListOf<HostListener>()
/**
- * The machine to run on.
- */
- public val machine: SimBareMetalMachine = SimBareMetalMachine(engine, model.optimize(), powerDriver)
-
- /**
- * The hypervisor to run multiple workloads.
- */
- private val hypervisor: SimHypervisor = hypervisorProvider
- .create(engine, scalingGovernor = scalingGovernor, interferenceDomain = interferenceDomain)
-
- /**
* The virtual machines running on the hypervisor.
*/
private val guests = HashMap<Server, Guest>()
@@ -113,7 +82,11 @@ public class SimHost(
field = value
}
- override val model: HostModel = HostModel(model.cpus.sumOf { it.frequency }, model.cpus.size, model.memory.sumOf { it.size })
+ override val model: HostModel = HostModel(
+ machine.model.cpus.sumOf { it.frequency },
+ machine.model.cpus.size,
+ machine.model.memory.sumOf { it.size }
+ )
/**
* The [GuestListener] that listens for guest events.
@@ -144,9 +117,9 @@ public class SimHost(
val guest = guests.computeIfAbsent(server) { key ->
require(canFit(key)) { "Server does not fit" }
- val machine = hypervisor.newMachine(key.flavor.toMachineModel(), key.name)
+ val machine = hypervisor.newMachine(key.flavor.toMachineModel())
val newGuest = Guest(
- scope.coroutineContext,
+ context,
clock,
this,
hypervisor,
@@ -193,8 +166,7 @@ public class SimHost(
}
override fun close() {
- reset()
- scope.cancel()
+ reset(HostState.DOWN)
machine.cancel()
}
@@ -269,7 +241,7 @@ public class SimHost(
override fun toString(): String = "SimHost[uid=$uid,name=$name,model=$model]"
public suspend fun fail() {
- reset()
+ reset(HostState.ERROR)
for (guest in _guests) {
guest.fail()
@@ -308,7 +280,7 @@ public class SimHost(
_state = HostState.UP
hypervisor.onStart(ctx)
} catch (cause: Throwable) {
- _state = HostState.DOWN
+ _state = HostState.ERROR
_ctx = null
throw cause
}
@@ -318,7 +290,6 @@ public class SimHost(
try {
hypervisor.onStop(ctx)
} finally {
- _state = HostState.DOWN
_ctx = null
}
}
@@ -328,12 +299,12 @@ public class SimHost(
/**
* Reset the machine.
*/
- private fun reset() {
+ private fun reset(state: HostState) {
updateUptime()
// Stop the hypervisor
_ctx?.close()
- _state = HostState.DOWN
+ _state = state
}
/**
@@ -346,26 +317,8 @@ public class SimHost(
val processingUnits = (0 until cpuCount).map { originalCpu.copy(id = it, node = processingNode, frequency = cpuCapacity) }
val memoryUnits = listOf(MemoryUnit("Generic", "Generic", 3200.0, memorySize))
- return MachineModel(processingUnits, memoryUnits).optimize()
- }
-
- /**
- * Optimize the [MachineModel] for simulation.
- */
- private fun MachineModel.optimize(): MachineModel {
- if (!optimize) {
- return this
- }
-
- val originalCpu = cpus[0]
- val freq = cpus.sumOf { it.frequency }
- val processingNode = originalCpu.node.copy(coreCount = 1)
- val processingUnits = listOf(originalCpu.copy(frequency = freq, node = processingNode))
-
- val memorySize = memory.sumOf { it.size }
- val memoryUnits = listOf(MemoryUnit("Generic", "Generic", 3200.0, memorySize))
-
- return MachineModel(processingUnits, memoryUnits)
+ val model = MachineModel(processingUnits, memoryUnits)
+ return if (optimize) model.optimize() else model
}
private var _lastReport = clock.millis()
@@ -384,7 +337,7 @@ public class SimHost(
if (_state == HostState.UP) {
_uptime += duration
- } else if (_state == HostState.DOWN && scope.isActive) {
+ } else if (_state == HostState.ERROR) {
// Only increment downtime if the machine is in a failure state
_downtime += duration
}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt
index ea3c6549..cc084526 100644
--- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt
@@ -217,7 +217,7 @@ internal class Guest(
*/
private suspend fun runMachine(workload: SimWorkload) {
delay(1) // TODO Introduce model for boot time
- machine.runWorkload(workload, mapOf("driver" to host, "server" to server))
+ machine.runWorkload(workload, mapOf("driver" to host, "server" to server) + server.meta)
}
/**
diff --git a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt
index 5ba4a667..a7993291 100644
--- a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt
+++ b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt
@@ -30,16 +30,20 @@ import org.junit.jupiter.api.assertAll
import org.opendc.compute.api.*
import org.opendc.compute.service.driver.Host
import org.opendc.compute.service.driver.HostListener
-import org.opendc.simulator.compute.kernel.SimFairShareHypervisorProvider
+import org.opendc.simulator.compute.SimBareMetalMachine
+import org.opendc.simulator.compute.kernel.SimHypervisor
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.workload.SimTrace
import org.opendc.simulator.compute.workload.SimTraceFragment
import org.opendc.simulator.compute.workload.SimTraceWorkload
import org.opendc.simulator.core.runBlockingSimulation
import org.opendc.simulator.flow.FlowEngine
+import org.opendc.simulator.flow.mux.FlowMultiplexerFactory
import java.time.Instant
import java.util.*
import kotlin.coroutines.resume
@@ -67,14 +71,16 @@ internal class SimHostTest {
fun testOvercommitted() = runBlockingSimulation {
val duration = 5 * 60L
val engine = FlowEngine(coroutineContext, clock)
+ val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)))
+ val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1), null)
val host = SimHost(
uid = UUID.randomUUID(),
name = "test",
- model = machineModel,
meta = emptyMap(),
coroutineContext,
- engine,
- SimFairShareHypervisorProvider()
+ clock,
+ machine,
+ hypervisor
)
val vmImageA = MockImage(
UUID.randomUUID(),
@@ -149,14 +155,16 @@ internal class SimHostTest {
fun testFailure() = runBlockingSimulation {
val duration = 5 * 60L
val engine = FlowEngine(coroutineContext, clock)
+ val machine = SimBareMetalMachine(engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)))
+ val hypervisor = SimHypervisor(engine, FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1), null)
val host = SimHost(
uid = UUID.randomUUID(),
name = "test",
- model = machineModel,
meta = emptyMap(),
coroutineContext,
- engine,
- SimFairShareHypervisorProvider()
+ clock,
+ machine,
+ hypervisor
)
val image = MockImage(
UUID.randomUUID(),