summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-compute/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src/main')
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt189
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt124
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt134
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt56
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt32
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt71
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt41
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt51
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt53
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt34
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimProcessingUnit.kt41
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt32
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt86
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingContext.kt46
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt53
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt54
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt49
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt134
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt31
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt10
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt19
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt54
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt20
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt27
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt16
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt19
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt19
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt17
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt53
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt53
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt94
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt45
38 files changed, 1979 insertions, 0 deletions
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt
new file mode 100644
index 00000000..713376e7
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractHypervisor.kt
@@ -0,0 +1,189 @@
+/*
+ * 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
+
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+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.*
+import java.time.Clock
+
+/**
+ * Abstract implementation of the [SimHypervisor] interface.
+ */
+public abstract class SimAbstractHypervisor : SimHypervisor {
+ /**
+ * The machine on which the hypervisor runs.
+ */
+ private lateinit var context: SimMachineContext
+
+ /**
+ * The resource switch to use.
+ */
+ private lateinit var switch: SimResourceSwitch
+
+ /**
+ * The virtual machines running on this hypervisor.
+ */
+ private val _vms = mutableSetOf<VirtualMachine>()
+ override val vms: Set<SimMachine>
+ get() = _vms
+
+ /**
+ * Construct the [SimResourceSwitch] implementation that performs the actual scheduling of the CPUs.
+ */
+ public abstract fun createSwitch(ctx: SimMachineContext): SimResourceSwitch
+
+ /**
+ * Check whether the specified machine model fits on this hypervisor.
+ */
+ public abstract fun canFit(model: SimMachineModel, switch: SimResourceSwitch): Boolean
+
+ override fun canFit(model: SimMachineModel): Boolean {
+ return canFit(model, switch)
+ }
+
+ override fun createMachine(
+ model: SimMachineModel,
+ performanceInterferenceModel: PerformanceInterferenceModel?
+ ): SimMachine {
+ require(canFit(model)) { "Machine does not fit" }
+ val vm = VirtualMachine(model, performanceInterferenceModel)
+ _vms.add(vm)
+ return vm
+ }
+
+ /**
+ * A virtual machine running on the hypervisor.
+ *
+ * @property model The machine model of the virtual machine.
+ * @property performanceInterferenceModel The performance interference model to utilize.
+ */
+ private inner class VirtualMachine(
+ override val model: SimMachineModel,
+ val performanceInterferenceModel: PerformanceInterferenceModel? = null,
+ ) : SimMachine {
+ /**
+ * A [StateFlow] representing the CPU usage of the simulated machine.
+ */
+ override val usage: MutableStateFlow<Double> = MutableStateFlow(0.0)
+
+ /**
+ * A flag to indicate that the machine is terminated.
+ */
+ private var isTerminated = false
+
+ /**
+ * The vCPUs of the machine.
+ */
+ private val cpus = model.cpus.map { ProcessingUnitImpl(it, switch) }
+
+ /**
+ * Run the specified [SimWorkload] on this machine and suspend execution util the workload has finished.
+ */
+ override suspend fun run(workload: SimWorkload, meta: Map<String, Any>) {
+ coroutineScope {
+ require(!isTerminated) { "Machine is terminated" }
+
+ val ctx = object : SimMachineContext {
+ override val cpus: List<SimProcessingUnit> = this@VirtualMachine.cpus
+
+ override val memory: List<MemoryUnit>
+ get() = model.memory
+
+ override val clock: Clock
+ get() = this@SimAbstractHypervisor.context.clock
+
+ override val meta: Map<String, Any> = meta
+ }
+
+ workload.onStart(ctx)
+
+ for (cpu in cpus) {
+ launch {
+ cpu.consume(workload.getConsumer(ctx, cpu.model))
+ }
+ }
+ }
+ }
+
+ /**
+ * Terminate this VM instance.
+ */
+ override fun close() {
+ if (!isTerminated) {
+ isTerminated = true
+
+ cpus.forEach(SimProcessingUnit::close)
+ _vms.remove(this)
+ }
+ }
+ }
+
+ override fun onStart(ctx: SimMachineContext) {
+ context = ctx
+ switch = createSwitch(ctx)
+ }
+
+ override fun getConsumer(ctx: SimMachineContext, cpu: ProcessingUnit): SimResourceConsumer {
+ val forwarder = SimResourceForwarder()
+ switch.addInput(forwarder)
+ return forwarder
+ }
+
+ /**
+ * The [SimProcessingUnit] of this machine.
+ */
+ public inner class ProcessingUnitImpl(override val model: ProcessingUnit, switch: SimResourceSwitch) : SimProcessingUnit {
+ /**
+ * The actual resource supporting the processing unit.
+ */
+ private val source = switch.addOutput(model.frequency)
+
+ override val speed: Double = 0.0 /* TODO Implement */
+
+ override val state: SimResourceState
+ get() = source.state
+
+ override fun startConsumer(consumer: SimResourceConsumer) {
+ source.startConsumer(consumer)
+ }
+
+ override fun interrupt() {
+ source.interrupt()
+ }
+
+ override fun cancel() {
+ source.cancel()
+ }
+
+ override fun close() {
+ source.close()
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
new file mode 100644
index 00000000..0244c5c1
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
@@ -0,0 +1,124 @@
+/*
+ * 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
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.workload.SimWorkload
+import org.opendc.simulator.resources.consume
+import org.opendc.simulator.resources.consumer.SimSpeedConsumerAdapter
+import java.time.Clock
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * Abstract implementation of the [SimMachine] interface.
+ */
+public abstract class SimAbstractMachine(private val clock: Clock) : SimMachine {
+ private val _usage = MutableStateFlow(0.0)
+ override val usage: StateFlow<Double>
+ get() = _usage
+
+ /**
+ * The speed of the CPU cores.
+ */
+ public val speed: DoubleArray
+ get() = _speed
+ private var _speed = doubleArrayOf()
+
+ /**
+ * A flag to indicate that the machine is terminated.
+ */
+ private var isTerminated = false
+
+ /**
+ * The [CoroutineContext] to run in.
+ */
+ protected abstract val context: CoroutineContext
+
+ /**
+ * The resources allocated for this machine.
+ */
+ protected abstract val cpus: List<SimProcessingUnit>
+
+ /**
+ * The execution context in which the workload runs.
+ */
+ private inner class Context(override val meta: Map<String, Any>) : SimMachineContext {
+ override val clock: Clock
+ get() = this@SimAbstractMachine.clock
+
+ override val cpus: List<SimProcessingUnit> = this@SimAbstractMachine.cpus
+
+ override val memory: List<MemoryUnit> = model.memory
+ }
+
+ /**
+ * Run the specified [SimWorkload] on this machine and suspend execution util the workload has finished.
+ */
+ override suspend fun run(workload: SimWorkload, meta: Map<String, Any>): Unit = withContext(context) {
+ require(!isTerminated) { "Machine is terminated" }
+ val ctx = Context(meta)
+ val totalCapacity = model.cpus.sumByDouble { it.frequency }
+
+ _speed = DoubleArray(model.cpus.size) { 0.0 }
+ var totalSpeed = 0.0
+
+ workload.onStart(ctx)
+
+ for (cpu in cpus) {
+ val model = cpu.model
+ val consumer = workload.getConsumer(ctx, model)
+ val adapter = SimSpeedConsumerAdapter(consumer) { newSpeed ->
+ val _speed = _speed
+ val _usage = _usage
+
+ val oldSpeed = _speed[model.id]
+ _speed[model.id] = newSpeed
+ totalSpeed = totalSpeed - oldSpeed + newSpeed
+
+ val newUsage = totalSpeed / totalCapacity
+ if (_usage.value != newUsage) {
+ updateUsage(totalSpeed / totalCapacity)
+ }
+ }
+
+ launch { cpu.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
+ cpus.forEach(SimProcessingUnit::close)
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
new file mode 100644
index 00000000..09ee601e
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2020 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
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import org.opendc.simulator.compute.cpufreq.ScalingDriver
+import org.opendc.simulator.compute.cpufreq.ScalingGovernor
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.resources.*
+import org.opendc.utils.TimerScheduler
+import java.time.Clock
+import kotlin.coroutines.*
+
+/**
+ * A simulated bare-metal machine that is able to run a single workload.
+ *
+ * A [SimBareMetalMachine] is a stateful object and you should be careful when operating this object concurrently. For
+ * example. the class expects only a single concurrent call to [run].
+ *
+ * @param context The [CoroutineContext] to run the simulated workload in.
+ * @param clock The virtual clock to track the simulation time.
+ * @param model The machine model to simulate.
+ */
+@OptIn(ExperimentalCoroutinesApi::class, InternalCoroutinesApi::class)
+public class SimBareMetalMachine(
+ context: CoroutineContext,
+ private val clock: Clock,
+ override val model: SimMachineModel,
+ scalingGovernor: ScalingGovernor,
+ scalingDriver: ScalingDriver
+) : SimAbstractMachine(clock) {
+ /**
+ * The [Job] associated with this machine.
+ */
+ private val scope = CoroutineScope(context + Job())
+
+ override val context: CoroutineContext = scope.coroutineContext
+
+ /**
+ * The [TimerScheduler] to use for scheduling the interrupts.
+ */
+ private val scheduler = TimerScheduler<Any>(this.context, clock)
+
+ override val cpus: List<SimProcessingUnit> = model.cpus.map { ProcessingUnitImpl(it) }
+
+ /**
+ * Construct the [ScalingDriver.Logic] for this machine.
+ */
+ private val scalingDriver = scalingDriver.createLogic(this)
+
+ /**
+ * The scaling contexts associated with each CPU.
+ */
+ private val scalingGovernors = cpus.map { cpu ->
+ scalingGovernor.createLogic(this.scalingDriver.createContext(cpu))
+ }
+
+ init {
+ scalingGovernors.forEach { it.onStart() }
+ }
+
+ /**
+ * The power draw of the machine.
+ */
+ 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()
+
+ scheduler.close()
+ scope.cancel()
+ }
+
+ /**
+ * The [SimProcessingUnit] of this machine.
+ */
+ public inner class ProcessingUnitImpl(override val model: ProcessingUnit) : SimProcessingUnit {
+ /**
+ * The actual resource supporting the processing unit.
+ */
+ private val source = SimResourceSource(model.frequency, clock, scheduler)
+
+ override val speed: Double
+ get() = source.speed
+
+ override val state: SimResourceState
+ get() = source.state
+
+ override fun startConsumer(consumer: SimResourceConsumer) {
+ source.startConsumer(consumer)
+ }
+
+ override fun interrupt() {
+ source.interrupt()
+ }
+
+ override fun cancel() {
+ source.cancel()
+ }
+
+ override fun close() {
+ source.interrupt()
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt
new file mode 100644
index 00000000..fa677de9
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisor.kt
@@ -0,0 +1,56 @@
+/*
+ * 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
+
+import org.opendc.simulator.compute.workload.SimWorkload
+import org.opendc.simulator.resources.*
+
+/**
+ * A [SimHypervisor] that distributes the computing requirements of multiple [SimWorkload] on a single
+ * [SimBareMetalMachine] concurrently using weighted fair sharing.
+ *
+ * @param listener The hypervisor listener to use.
+ */
+public class SimFairShareHypervisor(private val listener: SimHypervisor.Listener? = null) : SimAbstractHypervisor() {
+
+ override fun canFit(model: SimMachineModel, switch: SimResourceSwitch): Boolean = true
+
+ override fun createSwitch(ctx: SimMachineContext): SimResourceSwitch {
+ return SimResourceSwitchMaxMin(
+ ctx.clock,
+ object : SimResourceSwitchMaxMin.Listener {
+ override fun onSliceFinish(
+ switch: SimResourceSwitchMaxMin,
+ requestedWork: Long,
+ grantedWork: Long,
+ overcommittedWork: Long,
+ interferedWork: Long,
+ cpuUsage: Double,
+ cpuDemand: Double
+ ) {
+ listener?.onSliceFinish(this@SimFairShareHypervisor, requestedWork, grantedWork, overcommittedWork, interferedWork, cpuUsage, cpuDemand)
+ }
+ }
+ )
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt
new file mode 100644
index 00000000..02eb6ad0
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimFairShareHypervisorProvider.kt
@@ -0,0 +1,32 @@
+/*
+ * 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
+
+/**
+ * A [SimHypervisorProvider] for the [SimFairShareHypervisor] implementation.
+ */
+public class SimFairShareHypervisorProvider : SimHypervisorProvider {
+ override val id: String = "fair-share"
+
+ override fun create(listener: SimHypervisor.Listener?): SimHypervisor = SimFairShareHypervisor(listener)
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt
new file mode 100644
index 00000000..4a233fec
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 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
+
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+import org.opendc.simulator.compute.workload.SimWorkload
+
+/**
+ * A SimHypervisor facilitates the execution of multiple concurrent [SimWorkload]s, while acting as a single workload
+ * to a [SimBareMetalMachine].
+ */
+public interface SimHypervisor : SimWorkload {
+ /**
+ * The machines running on the hypervisor.
+ */
+ public val vms: Set<SimMachine>
+
+ /**
+ * Determine whether the specified machine characterized by [model] can fit on this hypervisor at this moment.
+ */
+ public fun canFit(model: SimMachineModel): Boolean
+
+ /**
+ * Create a [SimMachine] instance on which users may run a [SimWorkload].
+ *
+ * @param model The machine to create.
+ * @param performanceInterferenceModel The performance interference model to use.
+ */
+ public fun createMachine(
+ model: SimMachineModel,
+ performanceInterferenceModel: PerformanceInterferenceModel? = null
+ ): SimMachine
+
+ /**
+ * Event listener for hypervisor events.
+ */
+ public interface Listener {
+ /**
+ * This method is invoked when a slice is finished.
+ */
+ public fun onSliceFinish(
+ hypervisor: SimHypervisor,
+ requestedWork: Long,
+ grantedWork: Long,
+ overcommittedWork: Long,
+ interferedWork: Long,
+ cpuUsage: Double,
+ cpuDemand: Double
+ )
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt
new file mode 100644
index 00000000..a5b4526b
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisorProvider.kt
@@ -0,0 +1,41 @@
+/*
+ * 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
+
+/**
+ * A service provider interface for constructing a [SimHypervisor].
+ */
+public interface SimHypervisorProvider {
+ /**
+ * A unique identifier for this hypervisor implementation.
+ *
+ * Each hypervisor must provide a unique ID, so that they can be selected by the user.
+ * When in doubt, you may use the fully qualified name of your custom [SimHypervisor] implementation class.
+ */
+ public val id: String
+
+ /**
+ * Create a [SimHypervisor] instance with the specified [listener].
+ */
+ public fun create(listener: SimHypervisor.Listener? = null): SimHypervisor
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt
new file mode 100644
index 00000000..bfaa60bc
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 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
+
+import kotlinx.coroutines.flow.StateFlow
+import org.opendc.simulator.compute.workload.SimWorkload
+
+/**
+ * A generic machine that is able to run a [SimWorkload].
+ */
+public interface SimMachine : AutoCloseable {
+ /**
+ * The model of the machine containing its specifications.
+ */
+ public val model: SimMachineModel
+
+ /**
+ * A [StateFlow] representing the CPU usage of the simulated machine.
+ */
+ public val usage: StateFlow<Double>
+
+ /**
+ * Run the specified [SimWorkload] on this machine and suspend execution util the workload has finished.
+ */
+ public suspend fun run(workload: SimWorkload, meta: Map<String, Any> = emptyMap())
+
+ /**
+ * Terminate this machine.
+ */
+ public override fun close()
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt
new file mode 100644
index 00000000..c2523a2a
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 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
+
+import org.opendc.simulator.compute.model.MemoryUnit
+import java.time.Clock
+
+/**
+ * A simulated execution context in which a bootable image runs. This interface represents the
+ * firmware interface between the running image (e.g. operating system) and the physical or virtual firmware on
+ * which the image runs.
+ */
+public interface SimMachineContext {
+ /**
+ * The virtual clock tracking simulation time.
+ */
+ public val clock: Clock
+
+ /**
+ * The metadata associated with the context.
+ */
+ public val meta: Map<String, Any>
+
+ /**
+ * The CPUs available on the machine.
+ */
+ public val cpus: List<SimProcessingUnit>
+
+ /**
+ * The memory available on the machine
+ */
+ public val memory: List<MemoryUnit>
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt
new file mode 100644
index 00000000..2b414540
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt
@@ -0,0 +1,34 @@
+/*
+ * 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
+
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingUnit
+
+/**
+ * A description of the physical or virtual machine on which a bootable image runs.
+ *
+ * @property cpus The list of processing units available to the image.
+ * @property memory The list of memory units available to the image.
+ */
+public data class SimMachineModel(public val cpus: List<ProcessingUnit>, public val memory: List<MemoryUnit>)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimProcessingUnit.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimProcessingUnit.kt
new file mode 100644
index 00000000..13c7d9b2
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimProcessingUnit.kt
@@ -0,0 +1,41 @@
+/*
+ * 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
+
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.resources.SimResourceProvider
+
+/**
+ * A simulated processing unit.
+ */
+public interface SimProcessingUnit : SimResourceProvider {
+ /**
+ * The model representing the static properties of the processing unit.
+ */
+ public val model: ProcessingUnit
+
+ /**
+ * The current speed of the processing unit.
+ */
+ public val speed: Double
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt
new file mode 100644
index 00000000..fd8e546f
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisor.kt
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+import org.opendc.simulator.resources.*
+
+/**
+ * A [SimHypervisor] that allocates its sub-resources exclusively for the virtual machine that it hosts.
+ */
+public class SimSpaceSharedHypervisor : SimAbstractHypervisor() {
+ override fun canFit(model: SimMachineModel, switch: SimResourceSwitch): Boolean {
+ return switch.inputs.size - switch.outputs.size >= model.cpus.size
+ }
+
+ override fun createSwitch(ctx: SimMachineContext): SimResourceSwitch {
+ return SimResourceSwitchExclusive()
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt
new file mode 100644
index 00000000..e2044d05
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimSpaceSharedHypervisorProvider.kt
@@ -0,0 +1,32 @@
+/*
+ * 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
+
+/**
+ * A [SimHypervisorProvider] for the [SimSpaceSharedHypervisor] implementation.
+ */
+public class SimSpaceSharedHypervisorProvider : SimHypervisorProvider {
+ override val id: String = "space-shared"
+
+ override fun create(listener: SimHypervisor.Listener?): SimHypervisor = SimSpaceSharedHypervisor()
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt
new file mode 100644
index 00000000..ddbe1ca0
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/DemandScalingGovernor.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.cpufreq
+
+/**
+ * A CPUFreq [ScalingGovernor] that requests the frequency based on the utilization of the machine.
+ */
+public class DemandScalingGovernor : ScalingGovernor {
+ override fun createLogic(ctx: ScalingContext): ScalingGovernor.Logic = object : ScalingGovernor.Logic {
+ override fun onLimit() {
+ ctx.setTarget(ctx.cpu.speed)
+ }
+
+ override fun toString(): String = "DemandScalingGovernor.Logic"
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt
new file mode 100644
index 00000000..6f44d778
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PStateScalingDriver.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.cpufreq
+
+import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.SimProcessingUnit
+import org.opendc.simulator.compute.power.PowerModel
+import java.util.*
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * A [ScalingDriver] that scales the frequency of the processor based on a discrete set of frequencies.
+ *
+ * @param states A map describing the states of the driver.
+ */
+public class PStateScalingDriver(states: Map<Double, PowerModel>) : ScalingDriver {
+ /**
+ * The P-States defined by the user and ordered by key.
+ */
+ private val states = TreeMap(states)
+
+ override fun createLogic(machine: SimMachine): ScalingDriver.Logic = object : ScalingDriver.Logic {
+ /**
+ * The scaling contexts.
+ */
+ private val contexts = mutableListOf<ScalingContextImpl>()
+
+ override fun createContext(cpu: SimProcessingUnit): ScalingContext {
+ val ctx = ScalingContextImpl(machine, cpu)
+ contexts.add(ctx)
+ return ctx
+ }
+
+ override fun computePower(): Double {
+ var targetFreq = 0.0
+ var totalSpeed = 0.0
+
+ for (ctx in contexts) {
+ targetFreq = max(ctx.target, targetFreq)
+ totalSpeed += ctx.cpu.speed
+ }
+
+ val maxFreq = states.lastKey()
+ val (actualFreq, model) = states.ceilingEntry(min(maxFreq, targetFreq))
+ val utilization = totalSpeed / (actualFreq * contexts.size)
+ return model.computePower(utilization)
+ }
+
+ override fun toString(): String = "PStateScalingDriver.Logic"
+ }
+
+ private class ScalingContextImpl(
+ override val machine: SimMachine,
+ override val cpu: SimProcessingUnit
+ ) : ScalingContext {
+ var target = cpu.model.frequency
+ private set
+
+ override fun setTarget(freq: Double) {
+ target = freq
+ }
+
+ override fun toString(): String = "PStateScalingDriver.Context"
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt
new file mode 100644
index 00000000..96f8775a
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/PerformanceScalingGovernor.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.cpufreq
+
+/**
+ * A CPUFreq [ScalingGovernor] that causes the highest possible frequency to be requested from the resource.
+ */
+public class PerformanceScalingGovernor : ScalingGovernor {
+ override fun createLogic(ctx: ScalingContext): ScalingGovernor.Logic = object : ScalingGovernor.Logic {
+ override fun onLimit() {
+ ctx.setTarget(ctx.cpu.model.frequency)
+ }
+
+ override fun toString(): String = "PerformanceScalingGovernor.Logic"
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingContext.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingContext.kt
new file mode 100644
index 00000000..18338079
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingContext.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.cpufreq
+
+import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.SimProcessingUnit
+
+/**
+ * A [ScalingContext] is used to communicate frequency scaling changes between the [ScalingGovernor] and driver.
+ */
+public interface ScalingContext {
+ /**
+ * The machine the processing unit belongs to.
+ */
+ public val machine: SimMachine
+
+ /**
+ * The processing unit associated with this context.
+ */
+ public val cpu: SimProcessingUnit
+
+ /**
+ * Target the processor to run at the specified target [frequency][freq].
+ */
+ public fun setTarget(freq: Double)
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt
new file mode 100644
index 00000000..b4fd7550
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingDriver.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.cpufreq
+
+import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.SimProcessingUnit
+
+/**
+ * A [ScalingDriver] is responsible for switching the processor to the correct frequency.
+ */
+public interface ScalingDriver {
+ /**
+ * Create the scaling logic for the specified [machine]
+ */
+ public fun createLogic(machine: SimMachine): Logic
+
+ /**
+ * The logic of the scaling driver.
+ */
+ public interface Logic {
+ /**
+ * Create the [ScalingContext] for the specified [cpu] instance.
+ */
+ public fun createContext(cpu: SimProcessingUnit): ScalingContext
+
+ /**
+ * Compute the power consumption of the processor.
+ *
+ * @return The power consumption of the processor in W.
+ */
+ public fun computePower(): Double
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt
new file mode 100644
index 00000000..c9aea580
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/ScalingGovernor.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.cpufreq
+
+/**
+ * A [ScalingGovernor] in the CPUFreq subsystem of OpenDC is responsible for scaling the frequency of simulated CPUs
+ * independent of the particular implementation of the CPU.
+ *
+ * Each of the scaling governors implements a single, possibly parametrized, performance scaling algorithm.
+ *
+ * For more information, see the documentation of the Linux CPUFreq subsystem:
+ * https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html
+ */
+public interface ScalingGovernor {
+ /**
+ * Create the scaling logic for the specified [context]
+ */
+ public fun createLogic(ctx: ScalingContext): Logic
+
+ /**
+ * The logic of the scaling governor.
+ */
+ public interface Logic {
+ /**
+ * This method is invoked when the governor is started.
+ */
+ public fun onStart() {}
+
+ /**
+ * This method is invoked when the governor should re-decide the frequency limits.
+ */
+ public fun onLimit() {}
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt
new file mode 100644
index 00000000..cf0bbb28
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/cpufreq/SimpleScalingDriver.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.cpufreq
+
+import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.SimProcessingUnit
+import org.opendc.simulator.compute.power.PowerModel
+
+/**
+ * A [ScalingDriver] that ignores the instructions of the [ScalingGovernor] and directly computes the power consumption
+ * based on the specified [power model][model].
+ */
+public class SimpleScalingDriver(private val model: PowerModel) : ScalingDriver {
+ override fun createLogic(machine: SimMachine): ScalingDriver.Logic = object : ScalingDriver.Logic {
+ override fun createContext(cpu: SimProcessingUnit): ScalingContext {
+ return object : ScalingContext {
+ override val machine: SimMachine = machine
+
+ override val cpu: SimProcessingUnit = cpu
+
+ override fun setTarget(freq: Double) {}
+ }
+ }
+
+ override fun computePower(): Double = model.computePower(machine.usage.value)
+
+ override fun toString(): String = "SimpleScalingDriver.Logic"
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt
new file mode 100644
index 00000000..4c409887
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2020 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.interference
+
+import java.util.*
+import kotlin.random.Random
+
+/**
+ * Meta-data key for the [PerformanceInterferenceModel] of an image.
+ */
+public const val IMAGE_PERF_INTERFERENCE_MODEL: String = "image:performance-interference"
+
+/**
+ * Performance Interference Model describing the variability incurred by different sets of workloads if colocated.
+ *
+ * @param items The [PerformanceInterferenceModel.Item]s that make up this model.
+ */
+public class PerformanceInterferenceModel(
+ public val items: SortedSet<Item>,
+ private val random: Random = Random(0)
+) {
+ private var intersectingItems: List<Item> = emptyList()
+ private val colocatedWorkloads = TreeMap<String, Int>()
+
+ /**
+ * Indicate that a VM has started.
+ */
+ public fun onStart(name: String) {
+ colocatedWorkloads.merge(name, 1, Int::plus)
+ intersectingItems = items.filter { item -> doesMatch(item) }
+ }
+
+ /**
+ * Indicate that a VM has stopped.
+ */
+ public fun onStop(name: String) {
+ colocatedWorkloads.computeIfPresent(name) { _, v -> (v - 1).takeUnless { it == 0 } }
+ intersectingItems = items.filter { item -> doesMatch(item) }
+ }
+
+ /**
+ * Compute the performance interference based on the current server load.
+ */
+ public fun apply(currentServerLoad: Double): Double {
+ if (intersectingItems.isEmpty()) {
+ return 1.0
+ }
+ val score = intersectingItems
+ .firstOrNull { it.minServerLoad <= currentServerLoad }
+
+ // Apply performance penalty to (on average) only one of the VMs
+ return if (score != null && random.nextInt(score.workloadNames.size) == 0) {
+ score.performanceScore
+ } else {
+ 1.0
+ }
+ }
+
+ private fun doesMatch(item: Item): Boolean {
+ var count = 0
+ for (
+ name in item.workloadNames.subSet(
+ colocatedWorkloads.firstKey(),
+ colocatedWorkloads.lastKey() + "\u0000"
+ )
+ ) {
+ count += colocatedWorkloads.getOrDefault(name, 0)
+ if (count > 1)
+ return true
+ }
+ 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 Item
+
+ if (workloadNames != other.workloadNames) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int = workloadNames.hashCode()
+
+ 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
+ }
+
+ return hashCode().compareTo(other.hashCode())
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt
new file mode 100644
index 00000000..bcbde5b1
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 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.model
+
+/**
+ * A memory unit of a compute resource, either virtual or physical.
+ *
+ * @property vendor The vendor string of the memory.
+ * @property modelName The name of the memory model.
+ * @property speed The access speed of the memory in MHz.
+ * @property size The size of the memory unit in MBs.
+ */
+public data class MemoryUnit(
+ public val vendor: String,
+ public val modelName: String,
+ public val speed: Double,
+ public val size: Long
+)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt
new file mode 100644
index 00000000..58ed816c
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 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.model
+
+/**
+ * A processing node/package/socket containing possibly several CPU cores.
+ *
+ * @property vendor The vendor string of the processor node.
+ * @property modelName The name of the processor node.
+ * @property arch The micro-architecture of the processor node.
+ * @property coreCount The number of logical CPUs in the processor node.
+ */
+public data class ProcessingNode(
+ public val vendor: String,
+ public val arch: String,
+ public val modelName: String,
+ public val coreCount: Int
+)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt
new file mode 100644
index 00000000..415e95e6
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 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.model
+
+/**
+ * A single logical compute unit of processor node, either virtual or physical.
+ *
+ * @property node The processing node containing the CPU core.
+ * @property id The identifier of the CPU core within the processing node.
+ * @property frequency The clock rate of the CPU in MHz.
+ */
+public data class ProcessingUnit(
+ public val node: ProcessingNode,
+ public val id: Int,
+ public val frequency: Double
+)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt
new file mode 100644
index 00000000..ddc6d5b1
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt
@@ -0,0 +1,31 @@
+package org.opendc.simulator.compute.power
+
+import kotlin.math.E
+import kotlin.math.pow
+
+/**
+ * The asymptotic power model partially adapted from GreenCloud.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ * @param asymUtil A utilization level at which the server attains asymptotic,
+ * i.e., close to linear power consumption versus the offered load.
+ * For most of the CPUs,a is in [0.2, 0.5].
+ * @param isDvfsEnabled A flag indicates whether DVFS is enabled.
+ */
+public class AsymptoticPowerModel(
+ private val maxPower: Double,
+ private val idlePower: Double,
+ private val asymUtil: Double,
+ private val isDvfsEnabled: Boolean,
+) : PowerModel {
+ private val factor: Double = (maxPower - idlePower) / 100
+
+ public override fun computePower(utilization: Double): Double =
+ if (isDvfsEnabled)
+ idlePower + (factor * 100) / 2 * (1 + utilization.pow(3) - E.pow(-utilization.pow(3) / asymUtil))
+ else
+ idlePower + (factor * 100) / 2 * (1 + utilization - E.pow(-utilization / asymUtil))
+
+ override fun toString(): String = "AsymptoticPowerModel[max=$maxPower,idle=$idlePower,asymptotic=$asymUtil]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt
new file mode 100644
index 00000000..b8cb8412
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt
@@ -0,0 +1,10 @@
+package org.opendc.simulator.compute.power
+
+/**
+ * A power model which produces a constant value [power].
+ */
+public class ConstantPowerModel(private val power: Double) : PowerModel {
+ public override fun computePower(utilization: Double): Double = power
+
+ override fun toString(): String = "ConstantPowerModel[power=$power]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt
new file mode 100644
index 00000000..9c44438a
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt
@@ -0,0 +1,19 @@
+package org.opendc.simulator.compute.power
+
+import kotlin.math.pow
+
+/**
+ * The cubic power model partially adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+public class CubicPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
+ private val factor: Double = (maxPower - idlePower) / 100.0.pow(3)
+
+ public override fun computePower(utilization: Double): Double {
+ return idlePower + factor * (utilization * 100).pow(3)
+ }
+
+ override fun toString(): String = "CubicPowerModel[max=$maxPower,idle=$idlePower]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt
new file mode 100644
index 00000000..cbfcd810
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt
@@ -0,0 +1,54 @@
+package org.opendc.simulator.compute.power
+
+import org.yaml.snakeyaml.Yaml
+import kotlin.math.ceil
+import kotlin.math.floor
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * The linear interpolation power model partially adapted from CloudSim.
+ * This model is developed to adopt the <a href="http://www.spec.org/power_ssj2008/">SPECpower benchmark</a>.
+ *
+ * @param powerValues A [List] of average active power measured by the power analyzer(s) and accumulated by the
+ * PTDaemon (Power and Temperature Daemon) for this measurement interval, displayed as watts (W).
+ * @see <a href="http://www.spec.org/power_ssj2008/results/res2011q1/">Machines used in the SPEC benchmark</a>
+ */
+public class InterpolationPowerModel(private val powerValues: List<Double>) : PowerModel {
+ public constructor(hardwareName: String) : this(loadAveragePowerValue(hardwareName))
+
+ public override fun computePower(utilization: Double): Double {
+ val clampedUtilization = min(1.0, max(0.0, utilization))
+ val utilizationFlr = floor(clampedUtilization * 10).toInt()
+ val utilizationCil = ceil(clampedUtilization * 10).toInt()
+ val powerFlr: Double = getAveragePowerValue(utilizationFlr)
+ val powerCil: Double = getAveragePowerValue(utilizationCil)
+ val delta = (powerCil - powerFlr) / 10
+
+ return if (utilization % 0.1 == 0.0)
+ getAveragePowerValue((clampedUtilization * 10).toInt())
+ else
+ powerFlr + delta * (clampedUtilization - utilizationFlr.toDouble() / 10) * 100
+ }
+
+ override fun toString(): String = "InterpolationPowerModel[entries=${powerValues.size}]"
+
+ /**
+ * Gets the power consumption for a given utilization percentage.
+ *
+ * @param index the utilization percentage in the scale from [0 to 10],
+ * where 10 means 100% of utilization.
+ * @return the power consumption for the given utilization percentage
+ */
+ private fun getAveragePowerValue(index: Int): Double = powerValues[index]
+
+ private companion object {
+ private fun loadAveragePowerValue(hardwareName: String, path: String = "spec_machines.yml"): List<Double> {
+ val content = this::class
+ .java.classLoader
+ .getResourceAsStream(path)
+ val hardwareToAveragePowerValues: Map<String, List<Double>> = Yaml().load(content)
+ return hardwareToAveragePowerValues.getOrDefault(hardwareName, listOf())
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt
new file mode 100644
index 00000000..0f45afae
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt
@@ -0,0 +1,20 @@
+package org.opendc.simulator.compute.power
+
+/**
+ * The linear power model partially adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+public class LinearPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
+ /**
+ * The linear interpolation factor of the model.
+ */
+ private val factor: Double = (maxPower - idlePower) / 100
+
+ public override fun computePower(utilization: Double): Double {
+ return idlePower + factor * utilization * 100
+ }
+
+ override fun toString(): String = "LinearPowerModel[max=$maxPower,idle=$idlePower]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt
new file mode 100644
index 00000000..8486d680
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt
@@ -0,0 +1,27 @@
+package org.opendc.simulator.compute.power
+
+import kotlin.math.pow
+
+/**
+ * The power model that minimizes the mean squared error (MSE)
+ * to the actual power measurement by tuning the calibration parameter.
+ * @see <a href="https://dl.acm.org/doi/abs/10.1145/1273440.1250665">
+ * Fan et al., Power provisioning for a warehouse-sized computer, ACM SIGARCH'07</a>
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ * @param calibrationParam The parameter set to minimize the MSE.
+ */
+public class MsePowerModel(
+ private val maxPower: Double,
+ private val idlePower: Double,
+ private val calibrationParam: Double,
+) : PowerModel {
+ private val factor: Double = (maxPower - idlePower) / 100
+
+ public override fun computePower(utilization: Double): Double {
+ return idlePower + factor * (2 * utilization - utilization.pow(calibrationParam)) * 100
+ }
+
+ override fun toString(): String = "MsePowerModel[max=$maxPower,idle=$idlePower,MSE_param=$calibrationParam]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt
new file mode 100644
index 00000000..1387e65a
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt
@@ -0,0 +1,16 @@
+package org.opendc.simulator.compute.power
+
+import org.opendc.simulator.compute.SimMachine
+
+/**
+ * A model for estimating the power usage of a [SimMachine].
+ */
+public interface PowerModel {
+ /**
+ * Computes CPU power consumption for each host.
+ *
+ * @param utilization The CPU utilization percentage.
+ * @return A [Double] value of CPU power consumption.
+ */
+ public fun computePower(utilization: Double): Double
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt
new file mode 100644
index 00000000..afa1d82f
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt
@@ -0,0 +1,19 @@
+package org.opendc.simulator.compute.power
+
+import kotlin.math.sqrt
+
+/**
+ * The square root power model partially adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+public class SqrtPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
+ private val factor: Double = (maxPower - idlePower) / sqrt(100.0)
+
+ override fun computePower(utilization: Double): Double {
+ return idlePower + factor * sqrt(utilization * 100)
+ }
+
+ override fun toString(): String = "SqrtPowerModel[max=$maxPower,idle=$idlePower]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt
new file mode 100644
index 00000000..82a9d37d
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt
@@ -0,0 +1,19 @@
+package org.opendc.simulator.compute.power
+
+import kotlin.math.pow
+
+/**
+ * The square power model partially adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+public class SquarePowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
+ private val factor: Double = (maxPower - idlePower) / 100.0.pow(2)
+
+ override fun computePower(utilization: Double): Double {
+ return idlePower + factor * (utilization * 100).pow(2)
+ }
+
+ override fun toString(): String = "SquarePowerModel[max=$maxPower,idle=$idlePower]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt
new file mode 100644
index 00000000..19dfcadd
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt
@@ -0,0 +1,17 @@
+package org.opendc.simulator.compute.power
+
+/**
+ * A decorator for ignoring the idle power when computing energy consumption of components.
+ *
+ * @param delegate The [PowerModel] to delegate to.
+ */
+public class ZeroIdlePowerDecorator(private val delegate: PowerModel) : PowerModel {
+ override fun computePower(utilization: Double): Double {
+ return if (utilization == 0.0)
+ 0.0
+ else
+ delegate.computePower(utilization)
+ }
+
+ override fun toString(): String = "ZeroIdlePowerDecorator[delegate=$delegate]"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt
new file mode 100644
index 00000000..63c9d28c
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 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.workload
+
+import org.opendc.simulator.compute.SimMachineContext
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.resources.SimResourceConsumer
+import org.opendc.simulator.resources.consumer.SimWorkConsumer
+
+/**
+ * A [SimWorkload] that models applications as a static number of floating point operations ([flops]) executed on
+ * multiple cores of a compute resource.
+ *
+ * @property flops The number of floating point operations to perform for this task in MFLOPs.
+ * @property utilization A model of the CPU utilization of the application.
+ */
+public class SimFlopsWorkload(
+ public val flops: Long,
+ public val utilization: Double = 0.8
+) : SimWorkload {
+ init {
+ require(flops >= 0) { "Number of FLOPs must be positive" }
+ require(utilization > 0.0 && utilization <= 1.0) { "Utilization must be in (0, 1]" }
+ }
+
+ override fun onStart(ctx: SimMachineContext) {}
+
+ override fun getConsumer(ctx: SimMachineContext, cpu: ProcessingUnit): SimResourceConsumer {
+ return SimWorkConsumer(flops.toDouble() / ctx.cpus.size, utilization)
+ }
+
+ override fun toString(): String = "SimFlopsWorkload(FLOPs=$flops,utilization=$utilization)"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt
new file mode 100644
index 00000000..a3420e32
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 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.workload
+
+import org.opendc.simulator.compute.SimMachineContext
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.resources.SimResourceConsumer
+import org.opendc.simulator.resources.consumer.SimWorkConsumer
+
+/**
+ * A [SimWorkload] that models application execution as a single duration.
+ *
+ * @property duration The duration of the workload.
+ * @property utilization The utilization of the application during runtime.
+ */
+public class SimRuntimeWorkload(
+ public val duration: Long,
+ public val utilization: Double = 0.8
+) : SimWorkload {
+ init {
+ require(duration >= 0) { "Duration must be non-negative" }
+ require(utilization > 0.0 && utilization <= 1.0) { "Utilization must be in (0, 1]" }
+ }
+
+ override fun onStart(ctx: SimMachineContext) {}
+
+ override fun getConsumer(ctx: SimMachineContext, cpu: ProcessingUnit): SimResourceConsumer {
+ val limit = cpu.frequency * utilization
+ return SimWorkConsumer((limit / 1000) * duration, utilization)
+ }
+
+ override fun toString(): String = "SimRuntimeWorkload(duration=$duration,utilization=$utilization)"
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt
new file mode 100644
index 00000000..ffb332d1
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 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.workload
+
+import org.opendc.simulator.compute.SimMachineContext
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.resources.SimResourceCommand
+import org.opendc.simulator.resources.SimResourceConsumer
+import org.opendc.simulator.resources.SimResourceContext
+import org.opendc.simulator.resources.consumer.SimConsumerBarrier
+
+/**
+ * A [SimWorkload] that replays a workload trace consisting of multiple fragments, each indicating the resource
+ * consumption for some period of time.
+ */
+public class SimTraceWorkload(public val trace: Sequence<Fragment>) : SimWorkload {
+ private var offset = Long.MIN_VALUE
+ private val iterator = trace.iterator()
+ private var fragment: Fragment? = null
+ private lateinit var barrier: SimConsumerBarrier
+
+ override fun onStart(ctx: SimMachineContext) {
+ check(offset == Long.MIN_VALUE) { "Workload does not support re-use" }
+
+ barrier = SimConsumerBarrier(ctx.cpus.size)
+ fragment = nextFragment()
+ offset = ctx.clock.millis()
+ }
+
+ override fun getConsumer(ctx: SimMachineContext, cpu: ProcessingUnit): SimResourceConsumer {
+ return object : SimResourceConsumer {
+ override fun onNext(ctx: SimResourceContext): SimResourceCommand {
+ val now = ctx.clock.millis()
+ val fragment = fragment ?: return SimResourceCommand.Exit
+ val usage = fragment.usage / fragment.cores
+ val work = (fragment.duration / 1000) * usage
+ val deadline = offset + fragment.duration
+
+ assert(deadline >= now) { "Deadline already passed" }
+
+ val cmd =
+ if (cpu.id < fragment.cores && work > 0.0)
+ SimResourceCommand.Consume(work, usage, deadline)
+ else
+ SimResourceCommand.Idle(deadline)
+
+ if (barrier.enter()) {
+ this@SimTraceWorkload.fragment = nextFragment()
+ this@SimTraceWorkload.offset += fragment.duration
+ }
+
+ return cmd
+ }
+ }
+ }
+
+ override fun toString(): String = "SimTraceWorkload"
+
+ /**
+ * Obtain the next fragment.
+ */
+ private fun nextFragment(): Fragment? {
+ return if (iterator.hasNext()) {
+ iterator.next()
+ } else {
+ null
+ }
+ }
+
+ /**
+ * A fragment of the workload.
+ */
+ public data class Fragment(val duration: Long, val usage: Double, val cores: Int)
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt
new file mode 100644
index 00000000..bdc12bb5
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 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.workload
+
+import org.opendc.simulator.compute.SimMachineContext
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.resources.SimResourceConsumer
+
+/**
+ * A model that characterizes the runtime behavior of some particular workload.
+ *
+ * Workloads are stateful objects that may be paused and resumed at a later moment. As such, be careful when using the
+ * same [SimWorkload] from multiple contexts.
+ */
+public interface SimWorkload {
+ /**
+ * This method is invoked when the workload is started.
+ */
+ public fun onStart(ctx: SimMachineContext)
+
+ /**
+ * Obtain the resource consumer for the specified processing unit.
+ */
+ public fun getConsumer(ctx: SimMachineContext, cpu: ProcessingUnit): SimResourceConsumer
+}