diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2020-10-04 17:17:23 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2020-10-04 17:23:34 +0200 |
| commit | 47f803afc14a50c467d2f5f7ff406824428223f7 (patch) | |
| tree | afb4109773039d908578bafd2f80edf70ef21e63 | |
| parent | 136c1b9ddc7bd9331d3552d681e9190fc6198271 (diff) | |
Reimplement performance interference in opendc-simulator-compute
This change reimplements the performance interference model originally
implemented for the SimpleVirtDriver class, for SimHypervisor.
11 files changed, 83 insertions, 64 deletions
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimVirtDriver.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimVirtDriver.kt index 6e0df93f..357ad714 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimVirtDriver.kt +++ b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimVirtDriver.kt @@ -35,6 +35,8 @@ 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.interference.IMAGE_PERF_INTERFERENCE_MODEL +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import org.opendc.simulator.compute.workload.SimWorkload import org.opendc.utils.flow.EventFlow import java.time.Clock @@ -124,15 +126,31 @@ public class SimVirtDriver( events ) availableMemory -= requiredMemory - vms.add(VirtualMachine(server, events, hypervisor.createMachine(ctx.machine))) + val vm = VirtualMachine(server, events, hypervisor.createMachine(ctx.machine)) + vms.add(vm) + vmStarted(vm) eventFlow.emit(HypervisorEvent.VmsUpdated(this, vms.size, availableMemory)) return server } + private fun vmStarted(vm: VirtualMachine) { + vms.forEach { it -> + vm.performanceInterferenceModel?.onStart(it.server.image.name) + } + } + + private fun vmStopped(vm: VirtualMachine) { + vms.forEach { it -> + vm.performanceInterferenceModel?.onStop(it.server.image.name) + } + } + /** * A virtual machine instance that the driver manages. */ private inner class VirtualMachine(server: Server, val events: EventFlow<ServerEvent>, machine: SimMachine) { + val performanceInterferenceModel: PerformanceInterferenceModel? = server.image.tags[IMAGE_PERF_INTERFERENCE_MODEL] as? PerformanceInterferenceModel? + val job = coroutineScope.launch { val workload = object : SimWorkload { override suspend fun run(ctx: SimExecutionContext) { @@ -176,6 +194,7 @@ public class SimVirtDriver( server = server.copy(state = serverState) availableMemory += server.flavor.memorySize vms.remove(this) + vmStopped(this) eventFlow.emit(HypervisorEvent.VmsUpdated(this@SimVirtDriver, vms.size, availableMemory)) events.close() } diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt index 7b6c4880..3ff21558 100644 --- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt @@ -34,7 +34,6 @@ import kotlinx.coroutines.launch import mu.KotlinLogging import org.opendc.compute.core.Flavor import org.opendc.compute.core.ServerEvent -import org.opendc.compute.core.workload.PerformanceInterferenceModel import org.opendc.compute.core.workload.VmWorkload import org.opendc.compute.metal.NODE_CLUSTER import org.opendc.compute.metal.driver.BareMetalDriver @@ -51,6 +50,7 @@ import org.opendc.experiments.sc20.experiment.monitor.ExperimentMonitor import org.opendc.experiments.sc20.trace.Sc20StreamingParquetTraceReader import org.opendc.format.environment.EnvironmentReader import org.opendc.format.trace.TraceReader +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import java.io.File import java.time.Clock import kotlin.math.ln diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt index 39b00a61..6ee53aec 100644 --- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt @@ -23,13 +23,13 @@ package org.opendc.experiments.sc20.trace import org.opendc.compute.core.image.SimWorkloadImage -import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import org.opendc.compute.core.workload.PerformanceInterferenceModel import org.opendc.compute.core.workload.VmWorkload import org.opendc.experiments.sc20.experiment.model.CompositeWorkload import org.opendc.experiments.sc20.experiment.model.Workload import org.opendc.format.trace.TraceEntry import org.opendc.format.trace.TraceReader +import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import java.util.TreeSet /** diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt index 2ec01606..0afdc5fd 100644 --- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt @@ -32,12 +32,12 @@ import org.apache.parquet.filter2.predicate.Statistics import org.apache.parquet.filter2.predicate.UserDefinedPredicate import org.apache.parquet.io.api.Binary import org.opendc.compute.core.image.SimWorkloadImage -import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import org.opendc.compute.core.workload.PerformanceInterferenceModel import org.opendc.compute.core.workload.VmWorkload import org.opendc.core.User import org.opendc.format.trace.TraceEntry import org.opendc.format.trace.TraceReader +import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import org.opendc.simulator.compute.workload.SimTraceWorkload import java.io.File import java.io.Serializable diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt index 7f60cd90..f30e64cf 100644 --- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt @@ -22,7 +22,7 @@ package org.opendc.format.trace -import org.opendc.compute.core.workload.PerformanceInterferenceModel +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import java.io.Closeable import kotlin.random.Random diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt index f98a5a6d..6292a9cc 100644 --- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt @@ -23,12 +23,12 @@ package org.opendc.format.trace.bitbrains import org.opendc.compute.core.image.SimWorkloadImage -import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import org.opendc.compute.core.workload.PerformanceInterferenceModel import org.opendc.compute.core.workload.VmWorkload import org.opendc.core.User import org.opendc.format.trace.TraceEntry import org.opendc.format.trace.TraceReader +import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import org.opendc.simulator.compute.workload.SimTraceWorkload import java.io.BufferedReader import java.io.File diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt index fd8cdfce..4267737d 100644 --- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt @@ -25,9 +25,8 @@ package org.opendc.format.trace.sc20 import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue -import org.opendc.compute.core.workload.PerformanceInterferenceModel -import org.opendc.compute.core.workload.PerformanceInterferenceModelItem import org.opendc.format.trace.PerformanceInterferenceModelReader +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import java.io.InputStream import java.util.* import kotlin.random.Random @@ -43,13 +42,13 @@ public class Sc20PerformanceInterferenceReader(input: InputStream, mapper: Objec /** * The computed value from the file. */ - private val items: Map<String, TreeSet<PerformanceInterferenceModelItem>> + private val items: Map<String, TreeSet<PerformanceInterferenceModel.Item>> init { val entries: List<PerformanceInterferenceEntry> = mapper.readValue(input) - val res = mutableMapOf<String, TreeSet<PerformanceInterferenceModelItem>>() + val res = mutableMapOf<String, TreeSet<PerformanceInterferenceModel.Item>>() for (entry in entries) { - val item = PerformanceInterferenceModelItem(TreeSet(entry.vms), entry.minServerLoad, entry.performanceScore) + val item = PerformanceInterferenceModel.Item(TreeSet(entry.vms), entry.minServerLoad, entry.performanceScore) for (workload in entry.vms) { res.computeIfAbsent(workload) { TreeSet() }.add(item) } diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt index 560ad846..558003a7 100644 --- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt @@ -23,12 +23,12 @@ package org.opendc.format.trace.sc20 import org.opendc.compute.core.image.SimWorkloadImage -import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import org.opendc.compute.core.workload.PerformanceInterferenceModel import org.opendc.compute.core.workload.VmWorkload import org.opendc.core.User import org.opendc.format.trace.TraceEntry import org.opendc.format.trace.TraceReader +import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import org.opendc.simulator.compute.workload.SimTraceWorkload import java.io.BufferedReader import java.io.File diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt index 55eda70f..6087227b 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.intrinsics.startCoroutineCancellable import kotlinx.coroutines.selects.SelectClause0 import kotlinx.coroutines.selects.SelectInstance import kotlinx.coroutines.selects.select +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.workload.SimWorkload import java.time.Clock @@ -69,15 +70,16 @@ public class SimHypervisor( * * @param model The machine to create. */ - public fun createMachine(model: SimMachineModel): SimMachine { - val vmCtx = VmExecutionContext(model) + public fun createMachine(model: SimMachineModel, performanceInterferenceModel: PerformanceInterferenceModel? = null): SimMachine { + val vm = VmSession(model, performanceInterferenceModel) + val vmCtx = VmExecutionContext(vm) return object : SimMachine { override val model: SimMachineModel get() = vmCtx.machine override val usage: StateFlow<Double> - get() = vmCtx.session.usage + get() = vm.usage /** * The current active workload. @@ -187,6 +189,7 @@ public class SimHypervisor( val totalAllocatedUsage = maxUsage - availableUsage var totalAllocatedBurst = 0L availableUsage = totalAllocatedUsage + val serverLoad = totalAllocatedUsage / maxUsage // Divide the requests over the available capacity of the pCPUs fairly for (i in pCPUs) { @@ -232,7 +235,7 @@ public class SimHypervisor( val vm = vmIterator.next() // Apply performance interference model - val performanceScore = 1.0 // TODO Performance interference + val performanceScore = vm.performanceInterferenceModel?.apply(serverLoad) ?: 1.0 var hasFinished = false for (vcpu in vm.vcpus) { @@ -330,6 +333,7 @@ public class SimHypervisor( @OptIn(InternalCoroutinesApi::class) private data class VmSession( val model: SimMachineModel, + val performanceInterferenceModel: PerformanceInterferenceModel? = null, var triggerMode: SimExecutionContext.TriggerMode = SimExecutionContext.TriggerMode.FIRST, var merge: (SimExecutionContext.Slice, SimExecutionContext.Slice) -> SimExecutionContext.Slice = { _, r -> r }, var select: () -> Unit = {} @@ -491,12 +495,10 @@ public class SimHypervisor( * The execution context in which a VM runs. * */ - private inner class VmExecutionContext(override val machine: SimMachineModel) : - SimExecutionContext, - DisposableHandle { - private var finalized: Boolean = false - private var initialized: Boolean = false - val session: VmSession = VmSession(machine) + private inner class VmExecutionContext(val session: VmSession) : + SimExecutionContext, DisposableHandle { + override val machine: SimMachineModel + get() = session.model override val clock: Clock get() = this@SimHypervisor.clock diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/PerformanceInterferenceModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt index 51f62197..4c409887 100644 --- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/PerformanceInterferenceModel.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt @@ -20,7 +20,7 @@ * SOFTWARE. */ -package org.opendc.compute.core.workload +package org.opendc.simulator.compute.interference import java.util.* import kotlin.random.Random @@ -33,13 +33,13 @@ public const val IMAGE_PERF_INTERFERENCE_MODEL: String = "image:performance-inte /** * Performance Interference Model describing the variability incurred by different sets of workloads if colocated. * - * @param items The [PerformanceInterferenceModelItem]s that make up this model. + * @param items The [PerformanceInterferenceModel.Item]s that make up this model. */ public class PerformanceInterferenceModel( - public val items: SortedSet<PerformanceInterferenceModelItem>, + public val items: SortedSet<Item>, private val random: Random = Random(0) ) { - private var intersectingItems: List<PerformanceInterferenceModelItem> = emptyList() + private var intersectingItems: List<Item> = emptyList() private val colocatedWorkloads = TreeMap<String, Int>() /** @@ -76,7 +76,7 @@ public class PerformanceInterferenceModel( } } - private fun doesMatch(item: PerformanceInterferenceModelItem): Boolean { + private fun doesMatch(item: Item): Boolean { var count = 0 for ( name in item.workloadNames.subSet( @@ -90,45 +90,45 @@ public class PerformanceInterferenceModel( } return false } -} -/** - * Model describing how a specific set of workloads causes performance variability for each workload. - * - * @param workloadNames The names of the workloads that together cause performance variability for each workload in the set. - * @param minServerLoad The minimum total server load at which this interference is activated and noticeable. - * @param performanceScore The performance score that should be applied to each workload's performance. 1 means no - * influence, <1 means that performance degrades, and >1 means that performance improves. - */ -public data class PerformanceInterferenceModelItem( - public val workloadNames: SortedSet<String>, - public val minServerLoad: Double, - public val performanceScore: Double -) : Comparable<PerformanceInterferenceModelItem> { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false + /** + * Model describing how a specific set of workloads causes performance variability for each workload. + * + * @param workloadNames The names of the workloads that together cause performance variability for each workload in the set. + * @param minServerLoad The minimum total server load at which this interference is activated and noticeable. + * @param performanceScore The performance score that should be applied to each workload's performance. 1 means no + * influence, <1 means that performance degrades, and >1 means that performance improves. + */ + public data class Item( + public val workloadNames: SortedSet<String>, + public val minServerLoad: Double, + public val performanceScore: Double + ) : Comparable<Item> { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false - other as PerformanceInterferenceModelItem + other as Item - if (workloadNames != other.workloadNames) return false + if (workloadNames != other.workloadNames) return false - return true - } + return true + } - override fun hashCode(): Int = workloadNames.hashCode() + override fun hashCode(): Int = workloadNames.hashCode() - override fun compareTo(other: PerformanceInterferenceModelItem): Int { - var cmp = performanceScore.compareTo(other.performanceScore) - if (cmp != 0) { - return cmp - } + override fun compareTo(other: Item): Int { + var cmp = performanceScore.compareTo(other.performanceScore) + if (cmp != 0) { + return cmp + } - cmp = minServerLoad.compareTo(other.minServerLoad) - if (cmp != 0) { - return cmp - } + cmp = minServerLoad.compareTo(other.minServerLoad) + if (cmp != 0) { + return cmp + } - return hashCode().compareTo(other.hashCode()) + return hashCode().compareTo(other.hashCode()) + } } } diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt index b9cd1b06..78bd2940 100644 --- a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt @@ -36,7 +36,6 @@ import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.workload.SimTraceWorkload import org.opendc.simulator.utils.DelayControllerClockAdapter import java.time.Clock -import java.util.* /** * Test suite for the [SimHypervisor] class. |
