diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-04-25 16:01:14 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-04-25 16:01:14 +0200 |
| commit | cd0b45627f0d8da8c8dc4edde223f3c36e9bcfbf (patch) | |
| tree | 6ae1681630a0e270c23804e6dbb3bd414ebe5d6e /opendc-simulator/opendc-simulator-compute/src/main/kotlin | |
| parent | 128a1db017545597a5c035b7960eb3fd36b5f987 (diff) | |
build: Migrate to flat project structure
This change updates the project structure to become flattened.
Previously, the simulator, frontend and API each lived into their own
directory.
With this change, all modules of the project live in the top-level
directory of the repository. This should improve discoverability of
modules of the project.
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src/main/kotlin')
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 +} |
