diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-09-05 20:23:45 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-09-21 11:31:15 +0200 |
| commit | 35ec0060fb73149e687655851a682f12486f0086 (patch) | |
| tree | 8e6a4f5e14b00584d4054e3a21dc27ddda745b44 | |
| parent | 2ec5e8f1e44239916779655d4d68a9c6dae8e894 (diff) | |
refactor(sim/compute): Move interference logic into VmInterferenceMember
This change updates the design of the VM interference model, where we
move more of the logic into the `VmInterferenceMember` interface. This
removes the dependency on the `VmInterferenceModel` for the hypervisor
interface.
12 files changed, 144 insertions, 206 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 908353f0..628f324b 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 @@ -92,7 +92,7 @@ public class SimHost( * The hypervisor to run multiple workloads. */ private val hypervisor: SimHypervisor = hypervisorProvider - .create(engine, scalingGovernor = scalingGovernor, interferenceDomain = interferenceDomain) + .create(engine, scalingGovernor = scalingGovernor) /** * The virtual machines running on the hypervisor. @@ -144,7 +144,7 @@ public class SimHost( val guest = guests.computeIfAbsent(server) { key -> require(canFit(key)) { "Server does not fit" } - val interferenceKey = interferenceDomain?.createKey(key.name) + val interferenceKey = interferenceDomain?.getMember(key.name) val machine = hypervisor.newMachine(key.flavor.toMachineModel(), interferenceKey) val newGuest = Guest( scope.coroutineContext, diff --git a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt index fbcc99c3..02b48fa7 100644 --- a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt +++ b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt @@ -107,7 +107,7 @@ class SimMachineBenchmarks { val machine = SimBareMetalMachine( engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) - val hypervisor = SimFairShareHypervisor(engine, null, null) + val hypervisor = SimFairShareHypervisor(engine, null) launch { machine.runWorkload(hypervisor) } @@ -129,7 +129,7 @@ class SimMachineBenchmarks { val machine = SimBareMetalMachine( engine, machineModel, SimplePowerDriver(ConstantPowerModel(0.0)) ) - val hypervisor = SimFairShareHypervisor(engine, null, null) + val hypervisor = SimFairShareHypervisor(engine, null) launch { machine.runWorkload(hypervisor) } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt index b3898004..98dab28f 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt @@ -25,8 +25,7 @@ package org.opendc.simulator.compute.kernel import org.opendc.simulator.compute.* import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor import org.opendc.simulator.compute.kernel.cpufreq.ScalingPolicy -import org.opendc.simulator.compute.kernel.interference.VmInterferenceDomain -import org.opendc.simulator.compute.kernel.interference.VmInterferenceKey +import org.opendc.simulator.compute.kernel.interference.VmInterferenceMember import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.workload.SimWorkload @@ -42,8 +41,7 @@ import kotlin.math.roundToLong */ public abstract class SimAbstractHypervisor( protected val engine: FlowEngine, - private val scalingGovernor: ScalingGovernor?, - protected val interferenceDomain: VmInterferenceDomain? = null + private val scalingGovernor: ScalingGovernor? ) : SimHypervisor, FlowConvergenceListener { /** * The machine on which the hypervisor runs. @@ -93,7 +91,7 @@ public abstract class SimAbstractHypervisor( private val governors = mutableListOf<ScalingGovernor.Logic>() /* SimHypervisor */ - override fun newMachine(model: MachineModel, interferenceKey: VmInterferenceKey?): SimVirtualMachine { + override fun newMachine(model: MachineModel, interferenceKey: VmInterferenceMember?): SimVirtualMachine { require(canFit(model)) { "Machine does not fit" } val vm = VirtualMachine(model, interferenceKey) _vms.add(vm) @@ -163,7 +161,7 @@ public abstract class SimAbstractHypervisor( */ private inner class VirtualMachine( model: MachineModel, - private val interferenceKey: VmInterferenceKey? = null + private val interferenceKey: VmInterferenceMember? = null ) : SimAbstractMachine(engine, model), SimVirtualMachine, AutoCloseable { /** * A flag to indicate that the machine is closed. @@ -180,7 +178,7 @@ public abstract class SimAbstractHypervisor( */ override val counters: SimHypervisorCounters get() = _counters - @JvmField val _counters = VmCountersImpl(cpus, interferenceDomain, interferenceKey) + @JvmField val _counters = VmCountersImpl(cpus, interferenceKey) /** * The CPU capacity of the hypervisor in MHz. @@ -206,17 +204,18 @@ public abstract class SimAbstractHypervisor( return super.startWorkload( object : SimWorkload { override fun onStart(ctx: SimMachineContext) { + val interferenceKey = interferenceKey try { - joinInterferenceDomain() + interferenceKey?.activate() workload.onStart(ctx) } catch (cause: Throwable) { - leaveInterferenceDomain() + interferenceKey?.deactivate() throw cause } } override fun onStop(ctx: SimMachineContext) { - leaveInterferenceDomain() + interferenceKey?.deactivate() workload.onStop(ctx) } }, @@ -236,26 +235,6 @@ public abstract class SimAbstractHypervisor( cpu.close() } } - - /** - * Join the interference domain of the hypervisor. - */ - private fun joinInterferenceDomain() { - val interferenceKey = interferenceKey - if (interferenceKey != null) { - interferenceDomain?.join(interferenceKey) - } - } - - /** - * Leave the interference domain of the hypervisor. - */ - private fun leaveInterferenceDomain() { - val interferenceKey = interferenceKey - if (interferenceKey != null) { - interferenceDomain?.leave(interferenceKey) - } - } } /** @@ -353,8 +332,7 @@ public abstract class SimAbstractHypervisor( */ private inner class VmCountersImpl( private val cpus: List<VCpu>, - private val interferenceDomain: VmInterferenceDomain?, - private val key: VmInterferenceKey? + private val key: VmInterferenceMember? ) : SimHypervisorCounters { private val d = cpus.size / cpus.sumOf { it.model.frequency } * 1000 @@ -403,11 +381,11 @@ public abstract class SimAbstractHypervisor( cpuTime[2] += ((demandDelta - actualDelta) * d).roundToLong() // Compute the performance penalty due to flow interference - val interferenceDomain = interferenceDomain - if (interferenceDomain != null) { + val key = key + if (key != null) { val mux = mux val load = mux.rate / mux.capacity.coerceAtLeast(1.0) - val penalty = 1 - interferenceDomain.apply(key, load) + val penalty = 1 - key.apply(load) val interference = (actualDelta * d * penalty).roundToLong() if (interference > 0) { diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt index a12c5517..66453835 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt @@ -24,7 +24,6 @@ package org.opendc.simulator.compute.kernel import org.opendc.simulator.compute.SimMachine 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.workload.SimWorkload import org.opendc.simulator.flow.FlowEngine @@ -36,15 +35,12 @@ import org.opendc.simulator.flow.mux.MaxMinFlowMultiplexer * concurrently using weighted fair sharing. * * @param engine The [FlowEngine] to manage the machine's resources. - * @param listener The listener for the convergence of the system. * @param scalingGovernor The CPU frequency scaling governor to use for the hypervisor. - * @param interferenceDomain The resource interference domain to which the hypervisor belongs. */ public class SimFairShareHypervisor( engine: FlowEngine, - scalingGovernor: ScalingGovernor?, - interferenceDomain: VmInterferenceDomain?, -) : SimAbstractHypervisor(engine, scalingGovernor, interferenceDomain) { + scalingGovernor: ScalingGovernor? +) : SimAbstractHypervisor(engine, scalingGovernor) { /** * The multiplexer that distributes the computing capacity. */ diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt index 204b4860..ad8177d3 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorProvider.kt @@ -23,7 +23,6 @@ package org.opendc.simulator.compute.kernel import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor -import org.opendc.simulator.compute.kernel.interference.VmInterferenceDomain import org.opendc.simulator.flow.FlowEngine /** @@ -35,6 +34,5 @@ public class SimFairShareHypervisorProvider : SimHypervisorProvider { override fun create( engine: FlowEngine, scalingGovernor: ScalingGovernor?, - interferenceDomain: VmInterferenceDomain?, - ): SimHypervisor = SimFairShareHypervisor(engine, scalingGovernor, interferenceDomain) + ): SimHypervisor = SimFairShareHypervisor(engine, scalingGovernor) } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt index 229e569c..f53d0c5d 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt @@ -23,7 +23,7 @@ package org.opendc.simulator.compute.kernel import org.opendc.simulator.compute.SimMachine -import org.opendc.simulator.compute.kernel.interference.VmInterferenceKey +import org.opendc.simulator.compute.kernel.interference.VmInterferenceMember import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.workload.SimWorkload @@ -68,7 +68,7 @@ public interface SimHypervisor : SimWorkload { * @param model The machine to create. * @param interferenceKey The key of the machine in the interference model. */ - public fun newMachine(model: MachineModel, interferenceKey: VmInterferenceKey? = null): SimVirtualMachine + public fun newMachine(model: MachineModel, interferenceKey: VmInterferenceMember? = null): SimVirtualMachine /** * Remove the specified [machine] from the hypervisor. diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt index b7e8760a..6ee523fd 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorProvider.kt @@ -23,7 +23,6 @@ package org.opendc.simulator.compute.kernel import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor -import org.opendc.simulator.compute.kernel.interference.VmInterferenceDomain import org.opendc.simulator.flow.FlowEngine /** @@ -41,9 +40,5 @@ public interface SimHypervisorProvider { /** * Create a new [SimHypervisor] instance. */ - public fun create( - engine: FlowEngine, - scalingGovernor: ScalingGovernor? = null, - interferenceDomain: VmInterferenceDomain? = null, - ): SimHypervisor + public fun create(engine: FlowEngine, scalingGovernor: ScalingGovernor? = null): SimHypervisor } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt index 96b73e69..f7456797 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorProvider.kt @@ -23,7 +23,6 @@ package org.opendc.simulator.compute.kernel import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor -import org.opendc.simulator.compute.kernel.interference.VmInterferenceDomain import org.opendc.simulator.flow.FlowEngine /** @@ -35,6 +34,5 @@ public class SimSpaceSharedHypervisorProvider : SimHypervisorProvider { override fun create( engine: FlowEngine, scalingGovernor: ScalingGovernor?, - interferenceDomain: VmInterferenceDomain?, ): SimHypervisor = SimSpaceSharedHypervisor(engine, scalingGovernor) } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt index 5220fa2d..3b355f1e 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt @@ -27,40 +27,11 @@ package org.opendc.simulator.compute.kernel.interference */ public interface VmInterferenceDomain { /** - * Compute the performance score of a participant in this interference domain. - * - * @param key The participant to obtain the score of or `null` if the participant has no key. - * @param load The overall load on the interference domain. - * @return A score representing the performance score to be applied to the resource consumer, with 1 - * meaning no influence, <1 means that performance degrades, and >1 means that performance improves. - */ - public fun apply(key: VmInterferenceKey?, load: Double): Double - - /** - * Construct an [VmInterferenceKey] for the specified [id]. + * Return the [VmInterferenceMember] associated with the specified [id]. * * @param id The identifier of the virtual machine. - * @return A key identifying the virtual machine as part of the interference domain. `null` if the virtual machine - * does not participate in the domain. - */ - public fun createKey(id: String): VmInterferenceKey? - - /** - * Remove the specified [key] from this domain. - */ - public fun removeKey(key: VmInterferenceKey) - - /** - * Mark the specified [key] as active in this interference domain. - * - * @param key The key to join the interference domain with. - */ - public fun join(key: VmInterferenceKey) - - /** - * Mark the specified [key] as inactive in this interference domain. - * - * @param key The key of the virtual machine that wants to leave the domain. + * @return A [VmInterferenceMember] representing the virtual machine as part of the interference domain. `null` if + * the virtual machine does not participate in the domain. */ - public fun leave(key: VmInterferenceKey) + public fun getMember(id: String): VmInterferenceMember? } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceKey.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.kt index 8d720ea9..2f3dd74b 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceKey.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.kt @@ -23,6 +23,25 @@ package org.opendc.simulator.compute.kernel.interference /** - * A key that uniquely identifies a participant of an interference domain. + * A participant of an interference domain. */ -public interface VmInterferenceKey +public interface VmInterferenceMember { + /** + * Mark this member as active in this interference domain. + */ + public fun activate() + + /** + * Mark this member as inactive in this interference domain. + */ + public fun deactivate() + + /** + * Compute the performance score of the member in this interference domain. + * + * @param load The overall load on the interference domain. + * @return A score representing the performance score to be applied to the member, with 1 + * meaning no influence, <1 means that performance degrades, and >1 means that performance improves. + */ + public fun apply(load: Double): Double +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt index 7cc545c8..bfda3121 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt @@ -35,11 +35,11 @@ import java.util.* * @param seed The seed to use for randomly selecting the virtual machines that are affected. */ public class VmInterferenceModel private constructor( - private val targets: DoubleArray, - private val scores: DoubleArray, private val idMapping: Map<String, Int>, private val members: Array<IntArray>, private val membership: Array<IntArray>, + private val targets: DoubleArray, + private val scores: DoubleArray, private val size: Int, seed: Long, ) { @@ -51,13 +51,13 @@ public class VmInterferenceModel private constructor( /** * Construct a new [VmInterferenceDomain]. */ - public fun newDomain(): VmInterferenceDomain = InterferenceDomainImpl(targets, scores, idMapping, members, membership, random) + public fun newDomain(): VmInterferenceDomain = InterferenceDomainImpl(idMapping, members, membership, targets, scores, random) /** * Create a copy of this model with a different seed. */ public fun withSeed(seed: Long): VmInterferenceModel { - return VmInterferenceModel(targets, scores, idMapping, members, membership, size, seed) + return VmInterferenceModel(idMapping, members, membership, targets, scores, size, seed) } public companion object { @@ -171,11 +171,11 @@ public class VmInterferenceModel private constructor( @Suppress("UNCHECKED_CAST") return VmInterferenceModel( - newTargets, - newScores, idMapping, newMembers as Array<IntArray>, membership.map { it.value.toIntArray() }.toTypedArray(), + newTargets, + newScores, size, seed ) @@ -197,127 +197,62 @@ public class VmInterferenceModel private constructor( * Internal implementation of [VmInterferenceDomain]. */ private class InterferenceDomainImpl( - private val targets: DoubleArray, - private val scores: DoubleArray, private val idMapping: Map<String, Int>, private val members: Array<IntArray>, private val membership: Array<IntArray>, + private val targets: DoubleArray, + private val scores: DoubleArray, private val random: SplittableRandom ) : VmInterferenceDomain { /** * Keys registered with this domain. */ - private val keys = HashMap<Int, InterferenceKeyImpl>() + private val keys = HashMap<Int, InterferenceMemberImpl>() /** * The set of keys active in this domain. */ - private val activeKeys = ArrayList<InterferenceKeyImpl>() - - override fun createKey(id: String): VmInterferenceKey? { - val intId = idMapping[id] ?: return null - return keys.computeIfAbsent(intId) { InterferenceKeyImpl(intId) } - } - - override fun removeKey(key: VmInterferenceKey) { - if (key !is InterferenceKeyImpl) { - return - } + private val activeKeys = ArrayList<InterferenceMemberImpl>() - if (activeKeys.remove(key)) { - computeActiveGroups(key.id) - } + /** + * Queue of participants that will be removed or added to the active groups. + */ + private val participants = ArrayDeque<InterferenceMemberImpl>() - keys.remove(key.id) + override fun getMember(id: String): VmInterferenceMember? { + val intId = idMapping[id] ?: return null + return keys.computeIfAbsent(intId) { InterferenceMemberImpl(it, this, members, targets, scores, random) } } - override fun join(key: VmInterferenceKey) { - if (key !is InterferenceKeyImpl) { - return - } + override fun toString(): String = "VmInterferenceDomain" - if (key.acquire()) { - val pos = activeKeys.binarySearch(key) - if (pos < 0) { - activeKeys.add(-pos - 1, key) - } - computeActiveGroups(key.id) + fun join(key: InterferenceMemberImpl) { + val activeKeys = activeKeys + val pos = activeKeys.binarySearch(key) + if (pos < 0) { + activeKeys.add(-pos - 1, key) } - } - override fun leave(key: VmInterferenceKey) { - if (key is InterferenceKeyImpl && key.release()) { - activeKeys.remove(key) - computeActiveGroups(key.id) - } + computeActiveGroups(activeKeys, key.id) } - override fun apply(key: VmInterferenceKey?, load: Double): Double { - if (key == null || key !is InterferenceKeyImpl) { - return 1.0 - } - - val groups = key.groups - val groupSize = groups.size - - if (groupSize == 0) { - return 1.0 - } - - val targets = targets - val scores = scores - var low = 0 - var high = groups.size - 1 - - var group = -1 - var score = 1.0 - - // Perform binary search over the groups based on target load - while (low <= high) { - val mid = low + high ushr 1 - val midGroup = groups[mid] - val target = targets[midGroup] - - if (target < load) { - low = mid + 1 - group = midGroup - score = scores[midGroup] - } else if (target > load) { - high = mid - 1 - } else { - group = midGroup - score = scores[midGroup] - break - } - } - - return if (group >= 0 && random.nextInt(members[group].size) == 0) { - score - } else { - 1.0 - } + fun leave(key: InterferenceMemberImpl) { + val activeKeys = activeKeys + activeKeys.remove(key) + computeActiveGroups(activeKeys, key.id) } - override fun toString(): String = "VmInterferenceDomain" - - /** - * Queue of participants that will be removed or added to the active groups. - */ - private val _participants = ArrayDeque<InterferenceKeyImpl>() - /** - * (Re-)Compute the active groups. + * (Re-)compute the active groups. */ - private fun computeActiveGroups(id: Int) { - val activeKeys = activeKeys - val groups = membership[id] - + private fun computeActiveGroups(activeKeys: ArrayList<InterferenceMemberImpl>, id: Int) { if (activeKeys.isEmpty()) { return } + val groups = membership[id] val members = members - val participants = _participants + val participants = participants for (group in groups) { val groupMembers = members[group] @@ -366,7 +301,14 @@ public class VmInterferenceModel private constructor( * * @param id The identifier of the member. */ - private class InterferenceKeyImpl(@JvmField val id: Int) : VmInterferenceKey, Comparable<InterferenceKeyImpl> { + private class InterferenceMemberImpl( + @JvmField val id: Int, + private val domain: InterferenceDomainImpl, + private val members: Array<IntArray>, + private val targets: DoubleArray, + private val scores: DoubleArray, + private val random: SplittableRandom + ) : VmInterferenceMember, Comparable<InterferenceMemberImpl> { /** * The active groups to which the key belongs. */ @@ -377,16 +319,57 @@ public class VmInterferenceModel private constructor( */ private var refCount: Int = 0 - /** - * Join the domain. - */ - fun acquire(): Boolean = refCount++ <= 0 + override fun activate() { + if (refCount++ <= 0) { + domain.join(this) + } + } - /** - * Leave the domain. - */ - fun release(): Boolean = --refCount <= 0 + override fun deactivate() { + if (--refCount <= 0) { + domain.leave(this) + } + } + + override fun apply(load: Double): Double { + val groups = groups + val groupSize = groups.size + + if (groupSize == 0) { + return 1.0 + } + + val targets = targets + val scores = scores + var low = 0 + var high = groups.size - 1 + + var group = -1 + + // Perform binary search over the groups based on target load + while (low <= high) { + val mid = low + high ushr 1 + val midGroup = groups[mid] + val target = targets[midGroup] + + if (target < load) { + low = mid + 1 + group = midGroup + } else if (target > load) { + high = mid - 1 + } else { + group = midGroup + break + } + } + + return if (group >= 0 && random.nextInt(members[group].size) == 0) { + scores[group] + } else { + 1.0 + } + } - override fun compareTo(other: InterferenceKeyImpl): Int = id.compareTo(other.id) + override fun compareTo(other: InterferenceMemberImpl): Int = id.compareTo(other.id) } } diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt index ab2a6d76..15d32002 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt @@ -77,7 +77,7 @@ internal class SimFairShareHypervisorTest { val platform = FlowEngine(coroutineContext, clock) val machine = SimBareMetalMachine(platform, model, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimFairShareHypervisor(platform, PerformanceScalingGovernor(), null) + val hypervisor = SimFairShareHypervisor(platform, PerformanceScalingGovernor()) launch { machine.runWorkload(hypervisor) @@ -128,7 +128,7 @@ internal class SimFairShareHypervisorTest { val machine = SimBareMetalMachine( platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) ) - val hypervisor = SimFairShareHypervisor(platform, null, null) + val hypervisor = SimFairShareHypervisor(platform, null) launch { machine.runWorkload(hypervisor) @@ -167,7 +167,7 @@ internal class SimFairShareHypervisorTest { val platform = FlowEngine(coroutineContext, clock) val machine = SimBareMetalMachine(platform, model, SimplePowerDriver(ConstantPowerModel(0.0))) - val hypervisor = SimFairShareHypervisor(platform, null, null) + val hypervisor = SimFairShareHypervisor(platform, null) assertDoesNotThrow { launch { @@ -197,7 +197,7 @@ internal class SimFairShareHypervisorTest { val machine = SimBareMetalMachine( platform, model, SimplePowerDriver(ConstantPowerModel(0.0)) ) - val hypervisor = SimFairShareHypervisor(platform, null, interferenceDomain) + val hypervisor = SimFairShareHypervisor(platform, null) val duration = 5 * 60L val workloadA = @@ -225,11 +225,11 @@ internal class SimFairShareHypervisorTest { coroutineScope { launch { - val vm = hypervisor.newMachine(model, interferenceDomain.createKey("a")) + val vm = hypervisor.newMachine(model, interferenceDomain.getMember("a")) vm.runWorkload(workloadA) hypervisor.removeMachine(vm) } - val vm = hypervisor.newMachine(model, interferenceDomain.createKey("b")) + val vm = hypervisor.newMachine(model, interferenceDomain.getMember("b")) vm.runWorkload(workloadB) hypervisor.removeMachine(vm) } |
