summaryrefslogtreecommitdiff
path: root/simulator/opendc-compute/opendc-compute-simulator/src/main
diff options
context:
space:
mode:
authorHongyu <hongyuhe.cs@googlemail.com>2021-03-16 09:08:51 +0100
committerFabian Mastenbroek <mail.fabianm@gmail.com>2021-03-18 11:37:43 +0100
commitdd24782f3710678151c80f8ad365eecc7389b6f8 (patch)
tree6e5ddf4e61e70495d67d4220f7657e7b271301e8 /simulator/opendc-compute/opendc-compute-simulator/src/main
parent054a3d376b8b31ba98f91e7b34c6e0ca717def18 (diff)
simulator: Add the CPU power model from iCanCloud/E-mc2
This change implements the CPU energy model with p-states from iCanCloud/E-mc2: - Only pushed a portion of the code for discussion as not sure if the idea is on track. - Inline comments have been added, and formal documents will follow once the model is finalized. - The p-state power consumptions are currently hard-coded in a companion object, which should be improved in the next PR(s). **Breaking Changes** - CpuPowerModel: directly interact with the machine it is measuring. - SimBareMetalMachine: expose the speeds of its CPU cores and its clock instant.
Diffstat (limited to 'simulator/opendc-compute/opendc-compute-simulator/src/main')
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt2
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt11
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/models/PStatePowerModel.kt96
3 files changed, 101 insertions, 8 deletions
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
index 9cc1bf54..6e9b8151 100644
--- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt
@@ -133,7 +133,7 @@ public class SimHost(
override val model: HostModel = HostModel(model.cpus.size, model.memory.map { it.size }.sum())
- override val powerDraw: Flow<Double> = cpuPowerModel.getPowerDraw(this)
+ override val powerDraw: Flow<Double> = cpuPowerModel.getPowerDraw(machine)
init {
// Launch hypervisor onto machine
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt
index 604b69c0..893f7ab1 100644
--- a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/api/CpuPowerModel.kt
@@ -2,7 +2,7 @@ package org.opendc.compute.simulator.power.api
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
-import org.opendc.compute.simulator.SimHost
+import org.opendc.simulator.compute.SimMachine
public interface CpuPowerModel {
/**
@@ -18,14 +18,11 @@ public interface CpuPowerModel {
/**
* Emits the values of power consumption for servers.
*
- * @param host A [SimHost] that offers host CPU utilization.
- * @param withoutIdle A [Boolean] flag indicates whether (false) add a constant
- * power consumption value when the server is idle or (true) not
- * with a default value being false.
+ * @param machine The [SimMachine] that the model is measuring.
* @return A [Flow] of values representing the server power draw.
*/
- public fun getPowerDraw(host: SimHost, withoutIdle: Boolean = false): Flow<Double> =
- host.machine.usage.map {
+ public fun getPowerDraw(machine: SimMachine): Flow<Double> =
+ machine.usage.map {
computeCpuPower(it)
}
}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/models/PStatePowerModel.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/models/PStatePowerModel.kt
new file mode 100644
index 00000000..aea089da
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/models/PStatePowerModel.kt
@@ -0,0 +1,96 @@
+package org.opendc.compute.simulator.power.models
+
+import org.opendc.simulator.compute.SimBareMetalMachine
+import java.time.Clock
+import java.util.*
+
+/**
+ * The CPU power model derived from the iCanCloud simulator.
+ *
+ * @param machine The [SimBareMetalMachine] that the model is measuring.
+ * @param clock The virtual [Clock] to track the time spent at each p-state.
+ * @property cpuPowerMeter A [MutableMap] that contains CPU frequencies ([Double]) in GHz
+ * as keys and the time ([Long]) spent in that frequency range in seconds.
+ * @property pStatesToPower A [TreeMap] that contains the frequency ([Double]) of corresponding p-state in GHz
+ * as keys and the energy ([Double]) consumption of that state in Watts.
+ * @property pStatesRange A [Pair] in which the fist and second elements are the lower and upper bounds of the
+ * consumption values of the p-states respectively.
+ * @property lastMeasureTime The last update time of the [cpuPowerMeter].
+ * @property currPState The p-state that the model is currently in.
+ */
+public class PStatePowerModel(
+ private val machine: SimBareMetalMachine,
+ private val clock: Clock,
+) {
+ // TODO: Extract the power meter out of the model.
+ private val cpuPowerMeter = mutableMapOf<Double, Long>()
+ private val pStatesToPower = TreeMap<Double, Double>()
+ private val pStatesRange: Pair<Double, Double>
+ private var lastMeasureTime: Long
+ private var currPState: Double
+
+ init {
+ loadPStates(this)
+ pStatesRange = Pair(pStatesToPower.keys.first(), pStatesToPower.keys.last())
+ pStatesToPower.keys.forEach { cpuPowerMeter[it] = 0L }
+ currPState = pStatesRange.first
+ lastMeasureTime = getClockInstant()
+ updateCpuPowerMeter()
+ }
+
+ /** Recorde the elapsed time to the corresponding p-state. */
+ public fun updateCpuPowerMeter() {
+ val newMeasureTime = getClockInstant()
+ val newMaxFreq: Double = getMaxCpuSpeedInGHz()
+ assert(newMaxFreq in pStatesRange.first..pStatesRange.second) {
+ "The maximum frequency $newMaxFreq is not in the range of the P-state frequency " +
+ "from ${pStatesRange.first} to ${pStatesRange.second}."
+ }
+
+ // Update the current p-state level on which the CPU is running.
+ val newPState = pStatesToPower.ceilingKey(newMaxFreq)
+
+ // Add the time elapsed to the previous state.
+ cpuPowerMeter.merge(currPState, newMeasureTime - lastMeasureTime, Long::plus)
+
+ // Update the current states.
+ currPState = newPState
+ lastMeasureTime = newMeasureTime
+ }
+
+ /** Get the power value of the energy consumption level at which the CPU is working. */
+ public fun getInstantCpuPower(): Double =
+ pStatesToPower.getOrDefault(currPState, 0.0)
+
+ /** Get the accumulated power consumption up until now. */
+ public fun getAccumulatedCpuPower(): Double =
+ pStatesToPower.keys
+ .map {
+ pStatesToPower.getOrDefault(it, 0.0) *
+ cpuPowerMeter.getOrDefault(it, 0.0).toDouble()
+ }.sum()
+
+ private fun getClockInstant() = clock.millis() / 1000
+
+ /** Get the maximum frequency of the CPUs in GHz as that of the package.
+ * @see <a href="https://www.intel.vn/content/dam/www/public/us/en/documents/datasheets/10th-gen-core-families-datasheet-vol-1-datasheet.pdf">
+ * on page 34.
+ */
+ private fun getMaxCpuSpeedInGHz() = (machine.speed.maxOrNull() ?: 0.0) / 1000
+
+ public companion object PStatesLoader {
+ private fun loadPStates(pStatePowerModel: PStatePowerModel) {
+ // TODO: Dynamically load configuration.
+ // See P4 of https://www.intel.com/content/dam/support/us/en/documents/motherboards/server/sb/power_management_of_intel_architecture_servers.pdf
+ pStatePowerModel.pStatesToPower.putAll(
+ sortedMapOf(
+ 3.6 to 103.0,
+ 3.4 to 94.0,
+ 3.2 to 85.0,
+ 3.0 to 76.0,
+ 2.8 to 8.0,
+ )
+ )
+ }
+ }
+}