summaryrefslogtreecommitdiff
path: root/simulator/opendc-simulator/opendc-simulator-compute/src/main
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-04-07 21:59:13 +0200
committerGitHub <noreply@github.com>2021-04-07 21:59:13 +0200
commit5d3b759b18fb0a4278b43dea6a9db478b07804a5 (patch)
tree419dedda10f6a1f1865fbee4d1f546dd8876c940 /simulator/opendc-simulator/opendc-simulator-compute/src/main
parent519141f9af525a853b40eb821e70ca209bc104bf (diff)
parent3d707674ddfa96ae5c090a7c918350b0bef9b50f (diff)
simulator: Optimize bottlenecks in resource layer
This pull request addresses several bottlenecks that were present in the `opendc-simulator-resources` layer and `TimerScheduler`. These changes result into a 4x performance improvement for the energy experiments we are currently doing. * The use of `StateFlow` has been removed where possible. Profiling shows that emitting changes to `StateFlow` becomes a bottleneck in a single-thread context. * `SimSpeedConsumerAdapter` is an alternative for obtaining the changes in speed of a resource. **Breaking API Changes** * `SimResourceSource` does not expose `speed` as `StateFlow` anymore. To monitor speed changes, use `SimSpeedConsumerAdapter`. * Power draw in `SimBareMetalMachine` is not exposed as `StateFlow` anymore.
Diffstat (limited to 'simulator/opendc-simulator/opendc-simulator-compute/src/main')
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt38
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt15
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt2
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt2
4 files changed, 31 insertions, 26 deletions
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
index 2127b066..1f26c9c9 100644
--- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
@@ -25,14 +25,13 @@ package org.opendc.simulator.compute
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import org.opendc.simulator.compute.model.MemoryUnit
import org.opendc.simulator.compute.model.ProcessingUnit
import org.opendc.simulator.compute.workload.SimWorkload
import org.opendc.simulator.resources.SimResourceProvider
import org.opendc.simulator.resources.SimResourceSource
import org.opendc.simulator.resources.consume
+import org.opendc.simulator.resources.consumer.SimSpeedConsumerAdapter
import java.time.Clock
import kotlin.coroutines.CoroutineContext
@@ -47,9 +46,9 @@ public abstract class SimAbstractMachine(private val clock: Clock) : SimMachine
/**
* The speed of the CPU cores.
*/
- public val speed: List<Double>
+ public val speed: DoubleArray
get() = _speed
- private var _speed = mutableListOf<Double>()
+ private var _speed = doubleArrayOf()
/**
* A flag to indicate that the machine is terminated.
@@ -94,29 +93,32 @@ public abstract class SimAbstractMachine(private val clock: Clock) : SimMachine
val ctx = Context(resources, meta)
val totalCapacity = model.cpus.sumByDouble { it.frequency }
- _speed = MutableList(model.cpus.size) { 0.0 }
+ _speed = DoubleArray(model.cpus.size) { 0.0 }
+ var totalSpeed = 0.0
workload.onStart(ctx)
for ((cpu, source) in resources) {
val consumer = workload.getConsumer(ctx, cpu)
- val job = source.speed
- .onEach {
- _speed[cpu.id] = it
- _usage.value = _speed.sum() / totalCapacity
- }
- .launchIn(this)
-
- launch {
- try {
- source.consume(consumer)
- } finally {
- job.cancel()
- }
+ val adapter = SimSpeedConsumerAdapter(consumer) { newSpeed ->
+ val oldSpeed = _speed[cpu.id]
+ _speed[cpu.id] = newSpeed
+ totalSpeed = totalSpeed - oldSpeed + newSpeed
+
+ updateUsage(totalSpeed / totalCapacity)
}
+
+ launch { source.consume(adapter) }
}
}
+ /**
+ * This method is invoked when the usage of the machine is updated.
+ */
+ protected open fun updateUsage(usage: Double) {
+ _usage.value = usage
+ }
+
override fun close() {
if (!isTerminated) {
isTerminated = true
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
index 51b807d2..d5577279 100644
--- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
@@ -84,12 +84,15 @@ public class SimBareMetalMachine(
/**
* The power draw of the machine.
*/
- public val powerDraw: StateFlow<Double> = usage
- .map {
- this.scalingGovernors.forEach { it.onLimit() }
- this.scalingDriver.computePower()
- }
- .stateIn(scope, SharingStarted.Eagerly, 0.0)
+ public var powerDraw: Double = 0.0
+ private set
+
+ override fun updateUsage(usage: Double) {
+ super.updateUsage(usage)
+
+ scalingGovernors.forEach { it.onLimit() }
+ powerDraw = scalingDriver.computePower()
+ }
override fun close() {
super.close()
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt
index b4bbf9fb..4d62c383 100644
--- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt
@@ -28,7 +28,7 @@ package org.opendc.simulator.compute.cpufreq
public class DemandScalingGovernor : ScalingGovernor {
override fun createLogic(ctx: ScalingContext): ScalingGovernor.Logic = object : ScalingGovernor.Logic {
override fun onLimit() {
- ctx.setTarget(ctx.resource.speed.value)
+ ctx.setTarget(ctx.resource.speed)
}
override fun toString(): String = "DemandScalingGovernor.Logic"
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt
index d109e4d8..1c82253c 100644
--- a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt
@@ -59,7 +59,7 @@ public class PStateScalingDriver(states: Map<Double, PowerModel>) : ScalingDrive
for (ctx in contexts) {
targetFreq = max(ctx.target, targetFreq)
- totalSpeed += ctx.resource.speed.value
+ totalSpeed += ctx.resource.speed
}
val maxFreq = states.lastKey()