diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-09-23 12:49:32 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-23 12:49:32 +0200 |
| commit | 2d2a3854d355bd4b074ef651f291d34081e70d96 (patch) | |
| tree | e99c4bf7e5647341c1e269797f7f46099753436f /opendc-compute/opendc-compute-simulator | |
| parent | 8d1d091f093e6ac32dba1e6a4f74490b280fcc4b (diff) | |
| parent | 3d5eb562227dcad5a8a60f31b96e6d68f7774fb2 (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')
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(), |
