diff options
Diffstat (limited to 'simulator/opendc-compute/opendc-compute-simulator/src')
8 files changed, 175 insertions, 124 deletions
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt index 97f550ba..7a978a53 100644 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt @@ -41,6 +41,7 @@ import org.opendc.core.services.ServiceRegistry import org.opendc.simulator.compute.SimBareMetalMachine import org.opendc.simulator.compute.SimExecutionContext import org.opendc.simulator.compute.SimMachineModel +import org.opendc.simulator.compute.workload.SimResourceCommand import org.opendc.simulator.compute.workload.SimWorkload import org.opendc.simulator.failures.FailureDomain import org.opendc.utils.flow.EventFlow @@ -139,15 +140,31 @@ public class SimBareMetalDriver( events ) + val delegate = (node.image as SimWorkloadImage).workload // Wrap the workload to pass in a ComputeSimExecutionContext val workload = object : SimWorkload { - override suspend fun run(ctx: SimExecutionContext) { - val wrappedCtx = object : ComputeSimExecutionContext, SimExecutionContext by ctx { + lateinit var wrappedCtx: ComputeSimExecutionContext + + override fun onStart(ctx: SimExecutionContext) { + wrappedCtx = object : ComputeSimExecutionContext, SimExecutionContext by ctx { override val server: Server get() = nodeState.value.server!! + + override fun toString(): String = "WrappedSimExecutionContext" } - (node.image as SimWorkloadImage).workload.run(wrappedCtx) + + delegate.onStart(wrappedCtx) + } + + override fun onStart(ctx: SimExecutionContext, cpu: Int): SimResourceCommand { + return delegate.onStart(wrappedCtx, cpu) + } + + override fun onNext(ctx: SimExecutionContext, cpu: Int, remainingWork: Double): SimResourceCommand { + return delegate.onNext(wrappedCtx, cpu, remainingWork) } + + override fun toString(): String = "SimWorkloadWrapper(delegate=$delegate)" } job = coroutineScope.launch { diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt index 09eec1ef..d7a8a8b2 100644 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt @@ -32,30 +32,29 @@ import org.opendc.compute.core.virt.HypervisorEvent import org.opendc.compute.core.virt.driver.InsufficientMemoryOnServerException import org.opendc.compute.core.virt.driver.VirtDriver import org.opendc.core.services.ServiceRegistry -import org.opendc.simulator.compute.SimExecutionContext -import org.opendc.simulator.compute.SimHypervisor -import org.opendc.simulator.compute.SimMachine +import org.opendc.simulator.compute.* import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL import org.opendc.simulator.compute.interference.PerformanceInterferenceModel +import org.opendc.simulator.compute.model.MemoryUnit +import org.opendc.simulator.compute.workload.SimResourceCommand import org.opendc.simulator.compute.workload.SimWorkload import org.opendc.utils.flow.EventFlow -import java.time.Clock import java.util.* /** * A [VirtDriver] that is simulates virtual machines on a physical machine using [SimHypervisor]. */ -public class SimVirtDriver( - private val coroutineScope: CoroutineScope, - clock: Clock, - private val ctx: SimExecutionContext -) : VirtDriver { +public class SimVirtDriver(private val coroutineScope: CoroutineScope, hypervisor: SimHypervisorProvider) : VirtDriver, SimWorkload { + /** + * The execution context in which the [VirtDriver] runs. + */ + private lateinit var ctx: ComputeSimExecutionContext /** * The server hosting this hypervisor. */ public val server: Server - get() = (ctx as ComputeSimExecutionContext).server + get() = ctx.server /** * The [EventFlow] to emit the events. @@ -67,35 +66,33 @@ public class SimVirtDriver( /** * Current total memory use of the images on this hypervisor. */ - private var availableMemory: Long = ctx.machine.memory.map { it.size }.sum() + private var availableMemory: Long = 0 /** * The hypervisor to run multiple workloads. */ - private val hypervisor = SimHypervisor( - coroutineScope, - clock, + private val hypervisor = hypervisor.create( object : SimHypervisor.Listener { override fun onSliceFinish( hypervisor: SimHypervisor, - requestedBurst: Long, - grantedBurst: Long, - overcommissionedBurst: Long, - interferedBurst: Long, + requestedWork: Long, + grantedWork: Long, + overcommittedWork: Long, + interferedWork: Long, cpuUsage: Double, cpuDemand: Double ) { eventFlow.emit( HypervisorEvent.SliceFinished( this@SimVirtDriver, - requestedBurst, - grantedBurst, - overcommissionedBurst, - interferedBurst, + requestedWork, + grantedWork, + overcommittedWork, + interferedWork, cpuUsage, cpuDemand, vms.size, - (ctx as ComputeSimExecutionContext).server + ctx.server ) ) } @@ -107,6 +104,14 @@ public class SimVirtDriver( */ private val vms = HashSet<VirtualMachine>() + override fun canFit(flavor: Flavor): Boolean { + val sufficientMemory = availableMemory > flavor.memorySize + val enoughCpus = ctx.machine.cpus.size >= flavor.cpuCount + val canFit = hypervisor.canFit(flavor.toMachineModel()) + + return sufficientMemory && enoughCpus && canFit + } + override suspend fun spawn(name: String, image: Image, flavor: Flavor): Server { val requiredMemory = flavor.memorySize if (availableMemory - requiredMemory < 0) { @@ -126,13 +131,26 @@ public class SimVirtDriver( events ) availableMemory -= requiredMemory - val vm = VirtualMachine(server, events, hypervisor.createMachine(ctx.machine)) + + val vm = VirtualMachine(server, events, hypervisor.createMachine(flavor.toMachineModel())) vms.add(vm) vmStarted(vm) eventFlow.emit(HypervisorEvent.VmsUpdated(this, vms.size, availableMemory)) return server } + /** + * Convert flavor to machine model. + */ + private fun Flavor.toMachineModel(): SimMachineModel { + val originalCpu = ctx.machine.cpus[0] + val processingNode = originalCpu.node.copy(coreCount = cpuCount) + val processingUnits = (0 until cpuCount).map { originalCpu.copy(id = it, node = processingNode) } + val memoryUnits = listOf(MemoryUnit("Generic", "Generic", 3200.0, memorySize)) + + return SimMachineModel(processingUnits, memoryUnits) + } + private fun vmStarted(vm: VirtualMachine) { vms.forEach { it -> vm.performanceInterferenceModel?.onStart(it.server.image.name) @@ -148,18 +166,35 @@ public class SimVirtDriver( /** * A virtual machine instance that the driver manages. */ - private inner class VirtualMachine(server: Server, val events: EventFlow<ServerEvent>, machine: SimMachine) { + private inner class VirtualMachine(server: Server, val events: EventFlow<ServerEvent>, val machine: SimMachine) { val performanceInterferenceModel: PerformanceInterferenceModel? = server.image.tags[IMAGE_PERF_INTERFERENCE_MODEL] as? PerformanceInterferenceModel? val job = coroutineScope.launch { + val delegate = (server.image as SimWorkloadImage).workload + // Wrap the workload to pass in a ComputeSimExecutionContext val workload = object : SimWorkload { - override suspend fun run(ctx: SimExecutionContext) { - val wrappedCtx = object : ComputeSimExecutionContext, SimExecutionContext by ctx { + lateinit var wrappedCtx: ComputeSimExecutionContext + + override fun onStart(ctx: SimExecutionContext) { + wrappedCtx = object : ComputeSimExecutionContext, SimExecutionContext by ctx { override val server: Server - get() = this@VirtualMachine.server + get() = server + + override fun toString(): String = "WrappedSimExecutionContext" } - (server.image as SimWorkloadImage).workload.run(wrappedCtx) + + delegate.onStart(wrappedCtx) + } + + override fun onStart(ctx: SimExecutionContext, cpu: Int): SimResourceCommand { + return delegate.onStart(wrappedCtx, cpu) + } + + override fun onNext(ctx: SimExecutionContext, cpu: Int, remainingWork: Double): SimResourceCommand { + return delegate.onNext(wrappedCtx, cpu, remainingWork) } + + override fun toString(): String = "SimWorkloadWrapper(delegate=$delegate)" } delay(1) // TODO Introduce boot time @@ -169,6 +204,8 @@ public class SimVirtDriver( exit(null) } catch (cause: Throwable) { exit(cause) + } finally { + machine.close() } } @@ -200,7 +237,17 @@ public class SimVirtDriver( } } - public suspend fun run() { - hypervisor.run(ctx) + override fun onStart(ctx: SimExecutionContext) { + this.ctx = ctx as ComputeSimExecutionContext + this.availableMemory = ctx.machine.memory.map { it.size }.sum() + this.hypervisor.onStart(ctx) + } + + override fun onStart(ctx: SimExecutionContext, cpu: Int): SimResourceCommand { + return hypervisor.onStart(ctx, cpu) + } + + override fun onNext(ctx: SimExecutionContext, cpu: Int, remainingWork: Double): SimResourceCommand { + return hypervisor.onNext(ctx, cpu, remainingWork) } } diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt deleted file mode 100644 index 58b9408a..00000000 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt +++ /dev/null @@ -1,38 +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.compute.simulator - -import kotlinx.coroutines.coroutineScope -import org.opendc.simulator.compute.SimExecutionContext -import org.opendc.simulator.compute.workload.SimWorkload - -public class SimVirtDriverWorkload : SimWorkload { - public lateinit var driver: SimVirtDriver - - override suspend fun run(ctx: SimExecutionContext) { - coroutineScope { - driver = SimVirtDriver(this, ctx.clock, ctx) - driver.run() - } - } -} diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt index e83370d7..defea888 100644 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt @@ -38,7 +38,11 @@ import org.opendc.compute.core.virt.driver.InsufficientMemoryOnServerException import org.opendc.compute.core.virt.driver.VirtDriver import org.opendc.compute.core.virt.service.VirtProvisioningEvent import org.opendc.compute.core.virt.service.VirtProvisioningService +import org.opendc.compute.core.virt.service.events.* import org.opendc.compute.simulator.allocation.AllocationPolicy +import org.opendc.simulator.compute.SimHypervisorProvider +import org.opendc.trace.core.EventTracer +import org.opendc.utils.TimerScheduler import org.opendc.utils.flow.EventFlow import java.time.Clock import java.util.* @@ -51,7 +55,10 @@ public class SimVirtProvisioningService( private val coroutineScope: CoroutineScope, private val clock: Clock, private val provisioningService: ProvisioningService, - public val allocationPolicy: AllocationPolicy + public val allocationPolicy: AllocationPolicy, + private val tracer: EventTracer, + private val hypervisor: SimHypervisorProvider, + private val schedulingQuantum: Long = 300000, // 5 minutes in milliseconds ) : VirtProvisioningService { /** * The logger instance to use. @@ -71,7 +78,7 @@ public class SimVirtProvisioningService( /** * The incoming images to be processed by the provisioner. */ - private val incomingImages: MutableSet<ImageView> = mutableSetOf() + private val incomingImages: Deque<ImageView> = ArrayDeque() /** * The active images in the system. @@ -99,11 +106,16 @@ public class SimVirtProvisioningService( override val events: Flow<VirtProvisioningEvent> = eventFlow + /** + * The [TimerScheduler] to use for scheduling the scheduler cycles. + */ + private var scheduler: TimerScheduler<Unit> = TimerScheduler(coroutineScope, clock) + init { coroutineScope.launch { val provisionedNodes = provisioningService.nodes() provisionedNodes.forEach { node -> - val workload = SimVirtDriverWorkload() + val workload = SimVirtDriver(coroutineScope, hypervisor) val hypervisorImage = SimWorkloadImage(UUID.randomUUID(), "vmm", emptyMap(), workload) launch { var init = false @@ -121,7 +133,7 @@ public class SimVirtProvisioningService( }.launchIn(this) delay(1) - onHypervisorAvailable(server, workload.driver) + onHypervisorAvailable(server, workload) } } } @@ -131,11 +143,15 @@ public class SimVirtProvisioningService( return availableHypervisors.map { it.driver }.toSet() } + override val hostCount: Int = hypervisors.size + override suspend fun deploy( name: String, image: Image, flavor: Flavor ): Server { + tracer.commit(VmSubmissionEvent(name, image, flavor)) + eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( this@SimVirtProvisioningService, @@ -161,36 +177,34 @@ public class SimVirtProvisioningService( provisionedNodes.forEach { node -> provisioningService.stop(node) } } - private var call: Job? = null - private fun requestCycle() { - if (call != null) { + // Bail out in case we have already requested a new cycle. + if (scheduler.isTimerActive(Unit)) { return } - val quantum = 300000 // 5 minutes in milliseconds // We assume that the provisioner runs at a fixed slot every time quantum (e.g t=0, t=60, t=120). // This is important because the slices of the VMs need to be aligned. // We calculate here the delay until the next scheduling slot. - val delay = quantum - (clock.millis() % quantum) + val delay = schedulingQuantum - (clock.millis() % schedulingQuantum) - val call = coroutineScope.launch { - delay(delay) - this@SimVirtProvisioningService.call = null - schedule() + scheduler.startSingleTimer(Unit, delay) { + coroutineScope.launch { schedule() } } - this.call = call } private suspend fun schedule() { - val imagesToBeScheduled = incomingImages.toSet() - - for (imageInstance in imagesToBeScheduled) { - val requiredMemory = imageInstance.image.tags["required-memory"] as Long + while (incomingImages.isNotEmpty()) { + val imageInstance = incomingImages.peekFirst() + val requiredMemory = imageInstance.flavor.memorySize val selectedHv = allocationLogic.select(availableHypervisors, imageInstance) - if (selectedHv == null) { + if (selectedHv == null || !selectedHv.driver.canFit(imageInstance.flavor)) { + logger.trace { "Image ${imageInstance.image} selected for scheduling but no capacity available for it." } + if (requiredMemory > maxMemory || imageInstance.flavor.cpuCount > maxCores) { + tracer.commit(VmSubmissionInvalidEvent(imageInstance.name)) + eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( this@SimVirtProvisioningService, @@ -199,12 +213,13 @@ public class SimVirtProvisioningService( submittedVms, runningVms, finishedVms, - queuedVms, + --queuedVms, ++unscheduledVms ) ) - incomingImages -= imageInstance + // Remove the incoming image + incomingImages.poll() logger.warn("Failed to spawn ${imageInstance.image}: does not fit [${clock.millis()}]") continue @@ -215,7 +230,7 @@ public class SimVirtProvisioningService( try { logger.info { "[${clock.millis()}] Spawning ${imageInstance.image} on ${selectedHv.server.uid} ${selectedHv.server.name} ${selectedHv.server.flavor}" } - incomingImages -= imageInstance + incomingImages.poll() // Speculatively update the hypervisor view information to prevent other images in the queue from // deciding on stale values. @@ -231,6 +246,8 @@ public class SimVirtProvisioningService( imageInstance.server = server imageInstance.continuation.resume(server) + tracer.commit(VmScheduledEvent(imageInstance.name)) + eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( this@SimVirtProvisioningService, @@ -252,6 +269,8 @@ public class SimVirtProvisioningService( if (event.server.state == ServerState.SHUTOFF) { logger.info { "[${clock.millis()}] Server ${event.server.uid} ${event.server.name} ${event.server.flavor} finished." } + tracer.commit(VmStoppedEvent(event.server.name)) + eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( this@SimVirtProvisioningService, @@ -310,6 +329,8 @@ public class SimVirtProvisioningService( hypervisors[server] = hv } + tracer.commit(HypervisorAvailableEvent(server.uid)) + eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( this@SimVirtProvisioningService, @@ -333,6 +354,8 @@ public class SimVirtProvisioningService( val hv = hypervisors[server] ?: return availableHypervisors -= hv + tracer.commit(HypervisorUnavailableEvent(hv.uid)) + eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( this@SimVirtProvisioningService, @@ -359,6 +382,8 @@ public class SimVirtProvisioningService( hv.driver = hypervisor availableHypervisors += hv + tracer.commit(HypervisorAvailableEvent(hv.uid)) + eventFlow.emit( VirtProvisioningEvent.MetricsAvailable( this@SimVirtProvisioningService, diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt index 8defe8b7..4470eab9 100644 --- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt @@ -40,7 +40,7 @@ public interface ComparableAllocationPolicyLogic : AllocationPolicy.Logic { ): HypervisorView? { return hypervisors.asSequence() .filter { hv -> - val fitsMemory = hv.availableMemory >= (image.image.tags["required-memory"] as Long) + val fitsMemory = hv.availableMemory >= (image.flavor.memorySize) val fitsCpu = hv.server.flavor.cpuCount >= image.flavor.cpuCount fitsMemory && fitsCpu } diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt index 0f1bd444..fb8a5f47 100644 --- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt @@ -64,7 +64,7 @@ internal class SimBareMetalDriverTest { testScope.launch { val driver = SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel) - val image = SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(4_000, 2, utilization = 1.0)) + val image = SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(4_000, utilization = 1.0)) // Batch driver commands withContext(coroutineContext) { @@ -84,6 +84,6 @@ internal class SimBareMetalDriverTest { testScope.advanceUntilIdle() assertEquals(ServerState.SHUTOFF, finalState) - assertEquals(1001, finalTime) + assertEquals(501, finalTime) } } diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt index def78ce7..a33a4e5f 100644 --- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt @@ -64,7 +64,7 @@ internal class SimProvisioningServiceTest { val clock = DelayControllerClockAdapter(testScope) testScope.launch { - val image = SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(1000, 2)) + val image = SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(1000)) val driver = SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel) val provisioner = SimpleProvisioningService() diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt index a0c61f29..1831eae0 100644 --- a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt @@ -34,6 +34,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertAll import org.opendc.compute.core.Flavor import org.opendc.compute.core.virt.HypervisorEvent +import org.opendc.simulator.compute.SimFairShareHypervisorProvider import org.opendc.simulator.compute.SimMachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.ProcessingNode @@ -66,17 +67,17 @@ internal class SimVirtDriverTest { } /** - * Test overcommissioning of a hypervisor. + * Test overcommitting of resources by the hypervisor. */ @Test - fun overcommission() { - var requestedBurst = 0L - var grantedBurst = 0L - var overcommissionedBurst = 0L + fun testOvercommitted() { + var requestedWork = 0L + var grantedWork = 0L + var overcommittedWork = 0L scope.launch { - val virtDriverWorkload = SimVirtDriverWorkload() - val vmm = SimWorkloadImage(UUID.randomUUID(), "vmm", emptyMap(), virtDriverWorkload) + val virtDriver = SimVirtDriver(this, SimFairShareHypervisorProvider()) + val vmm = SimWorkloadImage(UUID.randomUUID(), "vmm", emptyMap(), virtDriver) val duration = 5 * 60L val vmImageA = SimWorkloadImage( UUID.randomUUID(), @@ -84,10 +85,10 @@ internal class SimVirtDriverTest { emptyMap(), SimTraceWorkload( sequenceOf( - SimTraceWorkload.Fragment(0, 28L * duration, duration * 1000, 28.0, 2), - SimTraceWorkload.Fragment(0, 3500L * duration, duration * 1000, 3500.0, 2), - SimTraceWorkload.Fragment(0, 0, duration * 1000, 0.0, 2), - SimTraceWorkload.Fragment(0, 183L * duration, duration * 1000, 183.0, 2) + SimTraceWorkload.Fragment(duration * 1000, 28.0, 2), + SimTraceWorkload.Fragment(duration * 1000, 3500.0, 2), + SimTraceWorkload.Fragment(duration * 1000, 0.0, 2), + SimTraceWorkload.Fragment(duration * 1000, 183.0, 2) ), ) ) @@ -97,10 +98,10 @@ internal class SimVirtDriverTest { emptyMap(), SimTraceWorkload( sequenceOf( - SimTraceWorkload.Fragment(0, 28L * duration, duration * 1000, 28.0, 2), - SimTraceWorkload.Fragment(0, 3100L * duration, duration * 1000, 3100.0, 2), - SimTraceWorkload.Fragment(0, 0, duration * 1000, 0.0, 2), - SimTraceWorkload.Fragment(0, 73L * duration, duration * 1000, 73.0, 2) + SimTraceWorkload.Fragment(duration * 1000, 28.0, 2), + SimTraceWorkload.Fragment(duration * 1000, 3100.0, 2), + SimTraceWorkload.Fragment(duration * 1000, 0.0, 2), + SimTraceWorkload.Fragment(duration * 1000, 73.0, 2) ) ), ) @@ -115,31 +116,30 @@ internal class SimVirtDriverTest { delay(5) val flavor = Flavor(2, 0) - val vmDriver = virtDriverWorkload.driver - vmDriver.events + virtDriver.events .onEach { event -> when (event) { is HypervisorEvent.SliceFinished -> { - requestedBurst += event.requestedBurst - grantedBurst += event.grantedBurst - overcommissionedBurst += event.overcommissionedBurst + requestedWork += event.requestedBurst + grantedWork += event.grantedBurst + overcommittedWork += event.overcommissionedBurst } } } .launchIn(this) - vmDriver.spawn("a", vmImageA, flavor) - vmDriver.spawn("b", vmImageB, flavor) + virtDriver.spawn("a", vmImageA, flavor) + virtDriver.spawn("b", vmImageB, flavor) } scope.advanceUntilIdle() assertAll( { assertEquals(emptyList<Throwable>(), scope.uncaughtExceptions, "No errors") }, - { assertEquals(2073600, requestedBurst, "Requested Burst does not match") }, - { assertEquals(2013600, grantedBurst, "Granted Burst does not match") }, - { assertEquals(60000, overcommissionedBurst, "Overcommissioned Burst does not match") }, - { assertEquals(1200007, scope.currentTime) } + { assertEquals(4197600, requestedWork, "Requested work does not match") }, + { assertEquals(3057600, grantedWork, "Granted work does not match") }, + { assertEquals(1140000, overcommittedWork, "Overcommitted work does not match") }, + { assertEquals(1200006, scope.currentTime) } ) } } |
