summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-compute/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src/main/kotlin')
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimAbstractHypervisor.kt84
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisor.kt2
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt25
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceKey.kt28
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt13
5 files changed, 120 insertions, 32 deletions
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 8e925bdf..9495095e 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
@@ -30,7 +30,7 @@ import org.opendc.simulator.compute.model.MachineModel
import org.opendc.simulator.compute.model.ProcessingUnit
import org.opendc.simulator.compute.workload.SimWorkload
import org.opendc.simulator.flow.*
-import org.opendc.simulator.flow.interference.InterferenceKey
+import org.opendc.simulator.compute.kernel.interference.VmInterferenceKey
import org.opendc.simulator.flow.mux.FlowMultiplexer
import kotlin.math.roundToLong
@@ -144,6 +144,10 @@ public abstract class SimAbstractHypervisor(
if (delta > 0) {
_counters.record()
+
+ for (vm in _vms) {
+ vm._counters.record()
+ }
}
val load = cpuDemand / cpuCapacity
@@ -171,19 +175,19 @@ public abstract class SimAbstractHypervisor(
/**
* The interference key of this virtual machine.
*/
- private val interferenceKey: InterferenceKey? = interferenceId?.let { interferenceDomain?.createKey(it) }
+ private val interferenceKey: VmInterferenceKey? = interferenceId?.let { interferenceDomain?.createKey(it) }
/**
* The vCPUs of the machine.
*/
- override val cpus = model.cpus.map { cpu -> VCpu(mux, mux.newInput(cpu.frequency, interferenceKey), cpu) }
+ override val cpus = model.cpus.map { cpu -> VCpu(mux, mux.newInput(cpu.frequency), cpu) }
/**
* The resource counters associated with the hypervisor.
*/
override val counters: SimHypervisorCounters
get() = _counters
- private val _counters = VmCountersImpl(cpus)
+ @JvmField val _counters = VmCountersImpl(cpus, interferenceDomain, interferenceKey)
/**
* The CPU capacity of the hypervisor in MHz.
@@ -317,8 +321,8 @@ public abstract class SimAbstractHypervisor(
override val cpuLostTime: Long
get() = _cpuTime[3]
- private val _cpuTime = LongArray(4)
- private val _previous = DoubleArray(4)
+ val _cpuTime = LongArray(4)
+ private val _previous = DoubleArray(3)
/**
* Record the CPU time of the hypervisor.
@@ -331,22 +335,18 @@ public abstract class SimAbstractHypervisor(
val demand = counters.demand
val actual = counters.actual
val remaining = counters.remaining
- val interference = counters.interference
val demandDelta = demand - previous[0]
val actualDelta = actual - previous[1]
val remainingDelta = remaining - previous[2]
- val interferenceDelta = interference - previous[3]
previous[0] = demand
previous[1] = actual
previous[2] = remaining
- previous[3] = interference
cpuTime[0] += (actualDelta * d).roundToLong()
cpuTime[1] += (remainingDelta * d).roundToLong()
cpuTime[2] += ((demandDelta - actualDelta) * d).roundToLong()
- cpuTime[3] += (interferenceDelta * d).roundToLong()
}
override fun flush() {
@@ -358,17 +358,71 @@ public abstract class SimAbstractHypervisor(
/**
* A [SimHypervisorCounters] implementation for a virtual machine.
*/
- private class VmCountersImpl(private val cpus: List<VCpu>) : SimHypervisorCounters {
+ private inner class VmCountersImpl(
+ private val cpus: List<VCpu>,
+ private val interferenceDomain: VmInterferenceDomain?,
+ private val key: VmInterferenceKey?
+ ) : SimHypervisorCounters {
private val d = cpus.size / cpus.sumOf { it.model.frequency } * 1000
override val cpuActiveTime: Long
- get() = (cpus.sumOf { it.counters.actual } * d).roundToLong()
+ get() = _cpuTime[0]
override val cpuIdleTime: Long
- get() = (cpus.sumOf { it.counters.remaining } * d).roundToLong()
+ get() = _cpuTime[1]
override val cpuStealTime: Long
- get() = (cpus.sumOf { it.counters.demand - it.counters.actual } * d).roundToLong()
+ get() = _cpuTime[2]
override val cpuLostTime: Long
- get() = (cpus.sumOf { it.counters.interference } * d).roundToLong()
+ get() = _cpuTime[3]
+
+ private val _cpuTime = LongArray(4)
+ private val _previous = DoubleArray(3)
+
+ /**
+ * Record the CPU time of the hypervisor.
+ */
+ fun record() {
+ val cpuTime = _cpuTime
+ val previous = _previous
+
+ var demand = 0.0
+ var actual = 0.0
+ var remaining = 0.0
+
+ for (cpu in cpus) {
+ val counters = cpu.counters
+
+ actual += counters.actual
+ demand += counters.demand
+ remaining += counters.remaining
+ }
+
+ val demandDelta = demand - previous[0]
+ val actualDelta = actual - previous[1]
+ val remainingDelta = remaining - previous[2]
+
+ previous[0] = demand
+ previous[1] = actual
+ previous[2] = remaining
+
+ val d = d
+ cpuTime[0] += (actualDelta * d).roundToLong()
+ cpuTime[1] += (remainingDelta * d).roundToLong()
+ cpuTime[2] += ((demandDelta - actualDelta) * d).roundToLong()
+
+ // Compute the performance penalty due to flow interference
+ val interferenceDomain = interferenceDomain
+ if (interferenceDomain != null) {
+ val mux = mux
+ val load = mux.rate / mux.capacity.coerceAtLeast(1.0)
+ val penalty = 1 - interferenceDomain.apply(key, load)
+ val interference = (actualDelta * d * penalty).roundToLong()
+
+ if (interference > 0) {
+ cpuTime[3] += interference
+ _counters._cpuTime[3] += interference
+ }
+ }
+ }
override fun flush() {
for (cpu in cpus) {
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 36f76650..f6a700b9 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
@@ -50,7 +50,7 @@ public class SimFairShareHypervisor(
/**
* The multiplexer that distributes the computing capacity.
*/
- override val mux: FlowMultiplexer = MaxMinFlowMultiplexer(engine, this, interferenceDomain)
+ override val mux: FlowMultiplexer = MaxMinFlowMultiplexer(engine, this)
override fun canFit(model: MachineModel): Boolean = true
}
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 09b03306..5220fa2d 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
@@ -22,38 +22,45 @@
package org.opendc.simulator.compute.kernel.interference
-import org.opendc.simulator.flow.interference.InterferenceDomain
-import org.opendc.simulator.flow.interference.InterferenceKey
-
/**
* The interference domain of a hypervisor.
*/
-public interface VmInterferenceDomain : InterferenceDomain {
+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 [InterferenceKey] for the specified [id].
+ * Construct an [VmInterferenceKey] for 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): InterferenceKey?
+ public fun createKey(id: String): VmInterferenceKey?
/**
* Remove the specified [key] from this domain.
*/
- public fun removeKey(key: InterferenceKey)
+ 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: InterferenceKey)
+ 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.
*/
- public fun leave(key: InterferenceKey)
+ public fun leave(key: VmInterferenceKey)
}
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/VmInterferenceKey.kt
new file mode 100644
index 00000000..8d720ea9
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceKey.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 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.simulator.compute.kernel.interference
+
+/**
+ * A key that uniquely identifies a participant of an interference domain.
+ */
+public interface VmInterferenceKey
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 977292be..7cc545c8 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
@@ -22,7 +22,6 @@
package org.opendc.simulator.compute.kernel.interference
-import org.opendc.simulator.flow.interference.InterferenceKey
import java.util.*
/**
@@ -215,12 +214,12 @@ public class VmInterferenceModel private constructor(
*/
private val activeKeys = ArrayList<InterferenceKeyImpl>()
- override fun createKey(id: String): InterferenceKey? {
+ override fun createKey(id: String): VmInterferenceKey? {
val intId = idMapping[id] ?: return null
return keys.computeIfAbsent(intId) { InterferenceKeyImpl(intId) }
}
- override fun removeKey(key: InterferenceKey) {
+ override fun removeKey(key: VmInterferenceKey) {
if (key !is InterferenceKeyImpl) {
return
}
@@ -232,7 +231,7 @@ public class VmInterferenceModel private constructor(
keys.remove(key.id)
}
- override fun join(key: InterferenceKey) {
+ override fun join(key: VmInterferenceKey) {
if (key !is InterferenceKeyImpl) {
return
}
@@ -246,14 +245,14 @@ public class VmInterferenceModel private constructor(
}
}
- override fun leave(key: InterferenceKey) {
+ override fun leave(key: VmInterferenceKey) {
if (key is InterferenceKeyImpl && key.release()) {
activeKeys.remove(key)
computeActiveGroups(key.id)
}
}
- override fun apply(key: InterferenceKey?, load: Double): Double {
+ override fun apply(key: VmInterferenceKey?, load: Double): Double {
if (key == null || key !is InterferenceKeyImpl) {
return 1.0
}
@@ -367,7 +366,7 @@ public class VmInterferenceModel private constructor(
*
* @param id The identifier of the member.
*/
- private class InterferenceKeyImpl(@JvmField val id: Int) : InterferenceKey, Comparable<InterferenceKeyImpl> {
+ private class InterferenceKeyImpl(@JvmField val id: Int) : VmInterferenceKey, Comparable<InterferenceKeyImpl> {
/**
* The active groups to which the key belongs.
*/