summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-resources
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-10-03 18:15:09 +0200
committerGitHub <noreply@github.com>2021-10-03 18:15:09 +0200
commitb92d0e8703014f143ff0b1fe67de09fff6f867b1 (patch)
tree34238f56af20f0eb697f25ad5a700bab7fa4d6fb /opendc-simulator/opendc-simulator-resources
parent54bccf522e169d5cba6489291217f3307ae71094 (diff)
parent012fe8fa9be1676b8eef0cce795738a00c4260c0 (diff)
merge: Migrate to flow-based simulation for low-level models
This pull request converts the `opendc-simulator-resources` module into a flow simulator and adapts the existing low-level models (e.g., CPU, network, disk) to this new flow simulator. The flow simulator works differently from the uniform resource consumption model, in that it models flow through a system of connections, as opposed to resource consumptions. Concretely, this means that while in the uniform resource consumption model, consumptions with the same usage are propagated to the resources, in the flow simulator, only changes to the flow in the system are propagated. Overall, this leads to less updates in the system and therefore higher performance. The benchmarks shows that the new implementation obtains more than double the performance of the old implementation. We have focused in the new implementation on reducing the amount of work and memory allocations/loads/stores per updates. * Migrate from kotlinx-benchmark to jmh-gradle (for better profiling support) * Use longer traces for benchmarks (to prevent measuring the benchmark overhead) * Use direct field access for perf-sensitive code * Combine work and deadline to duration * Add support for pushing flow from context (to eliminate the allocation for every `SimResourceCommand`) * Reduce memory allocations in SimResourceInterpreter, by revamping the way timers are allocated. * Simplify max-min aggregator implementation (by utilizing the new push mechanism) * Invoke consumer callback on every invalidation (in order to propagate changes downstream) * Lazily push changes to resource context (by not updating the flow rate immediately after a push, but only after an update) * Remove onUpdate callback * Merge distributor and aggregator into switch * Separate push and pull flags * Remove failure callback from FlowSource * Create separate callbacks for remaining events * Make convergence callback optional * Reduce field accesses in FlowConsumerContextImpl * Optimize hot path in SimTraceWorkload * Expose CPU time counters directly on hypervisor * Optimize telemetry collection **Breaking API Changes** * The entire `opendc-simulator-resources` module has been replaced by the `opendc-simulator-flow` module. * `SimHypervisor.Listener` has been removed in favour of a new interface that exposes the performance counters of the hypervisor directly. To listen for convergence, use `FlowConvergenceListener`.
Diffstat (limited to 'opendc-simulator/opendc-simulator-resources')
-rw-r--r--opendc-simulator/opendc-simulator-resources/build.gradle.kts39
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/jmh/kotlin/org/opendc/simulator/resources/SimResourceBenchmarks.kt144
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceAggregator.kt211
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceProvider.kt128
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregator.kt38
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt74
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCloseableProvider.kt37
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCommand.kt52
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceConsumer.kt56
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceContext.kt61
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceControllableContext.kt64
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCounters.kt48
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributor.kt42
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt373
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceEvent.kt48
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceFlow.kt29
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceInterpreter.kt99
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProvider.kt106
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProviderLogic.kt79
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSource.kt72
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceState.kt43
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitch.kt57
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusive.kt115
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMin.kt102
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSystem.kt43
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceTransformer.kt206
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimConsumerBarrier.kt52
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimSpeedConsumerAdapter.kt83
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimTraceConsumer.kt73
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimWorkConsumer.kt58
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt393
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceCountersImpl.kt42
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceInterpreterImpl.kt351
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceDomain.kt19
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceKey.kt28
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMinTest.kt200
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceCommandTest.kt74
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceContextTest.kt160
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSourceTest.kt273
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusiveTest.kt176
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMinTest.kt150
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceTransformerTest.kt222
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimWorkConsumerTest.kt58
43 files changed, 0 insertions, 4778 deletions
diff --git a/opendc-simulator/opendc-simulator-resources/build.gradle.kts b/opendc-simulator/opendc-simulator-resources/build.gradle.kts
deleted file mode 100644
index e4ffc3ff..00000000
--- a/opendc-simulator/opendc-simulator-resources/build.gradle.kts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-description = "Uniform resource consumption simulation model"
-
-plugins {
- `kotlin-library-conventions`
- `testing-conventions`
- `jacoco-conventions`
- `benchmark-conventions`
-}
-
-dependencies {
- api(platform(projects.opendcPlatform))
- api(libs.kotlinx.coroutines)
- implementation(projects.opendcUtils)
-
- jmhImplementation(projects.opendcSimulator.opendcSimulatorCore)
- testImplementation(projects.opendcSimulator.opendcSimulatorCore)
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/jmh/kotlin/org/opendc/simulator/resources/SimResourceBenchmarks.kt b/opendc-simulator/opendc-simulator-resources/src/jmh/kotlin/org/opendc/simulator/resources/SimResourceBenchmarks.kt
deleted file mode 100644
index b45b2a2f..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/jmh/kotlin/org/opendc/simulator/resources/SimResourceBenchmarks.kt
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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.resources
-
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.launch
-import org.opendc.simulator.core.SimulationCoroutineScope
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.consumer.SimTraceConsumer
-import org.openjdk.jmh.annotations.*
-import java.util.concurrent.TimeUnit
-
-@State(Scope.Thread)
-@Fork(1)
-@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS)
-@Measurement(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS)
-@OptIn(ExperimentalCoroutinesApi::class)
-class SimResourceBenchmarks {
- private lateinit var scope: SimulationCoroutineScope
- private lateinit var interpreter: SimResourceInterpreter
-
- @Setup
- fun setUp() {
- scope = SimulationCoroutineScope()
- interpreter = SimResourceInterpreter(scope.coroutineContext, scope.clock)
- }
-
- @State(Scope.Thread)
- class Workload {
- lateinit var trace: Sequence<SimTraceConsumer.Fragment>
-
- @Setup
- fun setUp() {
- trace = sequenceOf(
- SimTraceConsumer.Fragment(1000, 28.0),
- SimTraceConsumer.Fragment(1000, 3500.0),
- SimTraceConsumer.Fragment(1000, 0.0),
- SimTraceConsumer.Fragment(1000, 183.0),
- SimTraceConsumer.Fragment(1000, 400.0),
- SimTraceConsumer.Fragment(1000, 100.0),
- SimTraceConsumer.Fragment(1000, 3000.0),
- SimTraceConsumer.Fragment(1000, 4500.0),
- )
- }
- }
-
- @Benchmark
- fun benchmarkSource(state: Workload) {
- return scope.runBlockingSimulation {
- val provider = SimResourceSource(4200.0, interpreter)
- return@runBlockingSimulation provider.consume(SimTraceConsumer(state.trace))
- }
- }
-
- @Benchmark
- fun benchmarkForwardOverhead(state: Workload) {
- return scope.runBlockingSimulation {
- val provider = SimResourceSource(4200.0, interpreter)
- val forwarder = SimResourceForwarder()
- provider.startConsumer(forwarder)
- return@runBlockingSimulation forwarder.consume(SimTraceConsumer(state.trace))
- }
- }
-
- @Benchmark
- fun benchmarkSwitchMaxMinSingleConsumer(state: Workload) {
- return scope.runBlockingSimulation {
- val switch = SimResourceSwitchMaxMin(interpreter)
-
- switch.addInput(SimResourceSource(3000.0, interpreter))
- switch.addInput(SimResourceSource(3000.0, interpreter))
-
- val provider = switch.newOutput()
- return@runBlockingSimulation provider.consume(SimTraceConsumer(state.trace))
- }
- }
-
- @Benchmark
- fun benchmarkSwitchMaxMinTripleConsumer(state: Workload) {
- return scope.runBlockingSimulation {
- val switch = SimResourceSwitchMaxMin(interpreter)
-
- switch.addInput(SimResourceSource(3000.0, interpreter))
- switch.addInput(SimResourceSource(3000.0, interpreter))
-
- repeat(3) {
- launch {
- val provider = switch.newOutput()
- provider.consume(SimTraceConsumer(state.trace))
- }
- }
- }
- }
-
- @Benchmark
- fun benchmarkSwitchExclusiveSingleConsumer(state: Workload) {
- return scope.runBlockingSimulation {
- val switch = SimResourceSwitchExclusive()
-
- switch.addInput(SimResourceSource(3000.0, interpreter))
- switch.addInput(SimResourceSource(3000.0, interpreter))
-
- val provider = switch.newOutput()
- return@runBlockingSimulation provider.consume(SimTraceConsumer(state.trace))
- }
- }
-
- @Benchmark
- fun benchmarkSwitchExclusiveTripleConsumer(state: Workload) {
- return scope.runBlockingSimulation {
- val switch = SimResourceSwitchExclusive()
-
- switch.addInput(SimResourceSource(3000.0, interpreter))
- switch.addInput(SimResourceSource(3000.0, interpreter))
-
- repeat(2) {
- launch {
- val provider = switch.newOutput()
- provider.consume(SimTraceConsumer(state.trace))
- }
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceAggregator.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceAggregator.kt
deleted file mode 100644
index 00648876..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceAggregator.kt
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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.resources
-
-/**
- * Abstract implementation of [SimResourceAggregator].
- */
-public abstract class SimAbstractResourceAggregator(
- interpreter: SimResourceInterpreter,
- parent: SimResourceSystem?
-) : SimResourceAggregator {
- /**
- * This method is invoked when the resource consumer consumes resources.
- */
- protected abstract fun doConsume(work: Double, limit: Double, deadline: Long)
-
- /**
- * This method is invoked when the resource consumer enters an idle state.
- */
- protected abstract fun doIdle(deadline: Long)
-
- /**
- * This method is invoked when the resource consumer finishes processing.
- */
- protected abstract fun doFinish()
-
- /**
- * This method is invoked when an input context is started.
- */
- protected abstract fun onInputStarted(input: Input)
-
- /**
- * This method is invoked when an input is stopped.
- */
- protected abstract fun onInputFinished(input: Input)
-
- /* SimResourceAggregator */
- override fun addInput(input: SimResourceProvider) {
- val consumer = Consumer()
- _inputs.add(input)
- _inputConsumers.add(consumer)
- input.startConsumer(consumer)
- }
-
- override val inputs: Set<SimResourceProvider>
- get() = _inputs
- private val _inputs = mutableSetOf<SimResourceProvider>()
- private val _inputConsumers = mutableListOf<Consumer>()
-
- /* SimResourceProvider */
- override val isActive: Boolean
- get() = _output.isActive
-
- override val capacity: Double
- get() = _output.capacity
-
- override val speed: Double
- get() = _output.speed
-
- override val demand: Double
- get() = _output.demand
-
- override val counters: SimResourceCounters
- get() = _output.counters
-
- override fun startConsumer(consumer: SimResourceConsumer) {
- _output.startConsumer(consumer)
- }
-
- override fun cancel() {
- _output.cancel()
- }
-
- override fun interrupt() {
- _output.interrupt()
- }
-
- private val _output = object : SimAbstractResourceProvider(interpreter, parent, initialCapacity = 0.0) {
- override fun createLogic(): SimResourceProviderLogic {
- return object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long {
- doIdle(deadline)
- return Long.MAX_VALUE
- }
-
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long {
- doConsume(work, limit, deadline)
- return Long.MAX_VALUE
- }
-
- override fun onFinish(ctx: SimResourceControllableContext) {
- doFinish()
- }
-
- override fun onUpdate(ctx: SimResourceControllableContext, work: Double, willOvercommit: Boolean) {
- updateCounters(ctx, work, willOvercommit)
- }
-
- override fun getConsumedWork(ctx: SimResourceControllableContext, work: Double, speed: Double, duration: Long): Double {
- return work - _inputConsumers.sumOf { it.remainingWork }
- }
- }
- }
-
- /**
- * Flush the progress of the output if possible.
- */
- fun flush() {
- ctx?.flush()
- }
- }
-
- /**
- * An input for the resource aggregator.
- */
- public interface Input {
- /**
- * The [SimResourceContext] associated with the input.
- */
- public val ctx: SimResourceContext
-
- /**
- * Push the specified [SimResourceCommand] to the input.
- */
- public fun push(command: SimResourceCommand)
- }
-
- /**
- * An internal [SimResourceConsumer] implementation for aggregator inputs.
- */
- private inner class Consumer : Input, SimResourceConsumer {
- /**
- * The resource context associated with the input.
- */
- override val ctx: SimResourceContext
- get() = _ctx!!
- private var _ctx: SimResourceContext? = null
-
- /**
- * The remaining work of the consumer.
- */
- val remainingWork: Double
- get() = _ctx?.remainingWork ?: 0.0
-
- /**
- * The resource command to run next.
- */
- private var command: SimResourceCommand? = null
-
- private fun updateCapacity() {
- // Adjust capacity of output resource
- _output.capacity = _inputConsumers.sumOf { it._ctx?.capacity ?: 0.0 }
- }
-
- /* Input */
- override fun push(command: SimResourceCommand) {
- this.command = command
- _ctx?.interrupt()
- }
-
- /* SimResourceConsumer */
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- var next = command
-
- return if (next != null) {
- this.command = null
- next
- } else {
- _output.flush()
-
- next = command
- this.command = null
- next ?: SimResourceCommand.Idle()
- }
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> {
- _ctx = ctx
- updateCapacity()
-
- onInputStarted(this)
- }
- SimResourceEvent.Capacity -> updateCapacity()
- SimResourceEvent.Exit -> onInputFinished(this)
- else -> {}
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceProvider.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceProvider.kt
deleted file mode 100644
index 4e8e803a..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceProvider.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.impl.SimResourceCountersImpl
-
-/**
- * Abstract implementation of the [SimResourceProvider] which can be re-used by other implementations.
- */
-public abstract class SimAbstractResourceProvider(
- private val interpreter: SimResourceInterpreter,
- private val parent: SimResourceSystem?,
- initialCapacity: Double
-) : SimResourceProvider {
- /**
- * A flag to indicate that the resource provider is active.
- */
- public override val isActive: Boolean
- get() = ctx != null
-
- /**
- * The capacity of the resource.
- */
- public override var capacity: Double = initialCapacity
- set(value) {
- field = value
- ctx?.capacity = value
- }
-
- /**
- * The current processing speed of the resource.
- */
- public override val speed: Double
- get() = ctx?.speed ?: 0.0
-
- /**
- * The resource processing speed demand at this instant.
- */
- public override val demand: Double
- get() = ctx?.demand ?: 0.0
-
- /**
- * The resource counters to track the execution metrics of the resource.
- */
- public override val counters: SimResourceCounters
- get() = _counters
- private val _counters = SimResourceCountersImpl()
-
- /**
- * The [SimResourceControllableContext] that is currently running.
- */
- protected var ctx: SimResourceControllableContext? = null
- private set
-
- /**
- * Construct the [SimResourceProviderLogic] instance for a new consumer.
- */
- protected abstract fun createLogic(): SimResourceProviderLogic
-
- /**
- * Start the specified [SimResourceControllableContext].
- */
- protected open fun start(ctx: SimResourceControllableContext) {
- ctx.start()
- }
-
- /**
- * Update the counters of the resource provider.
- */
- protected fun updateCounters(ctx: SimResourceContext, work: Double, willOvercommit: Boolean) {
- if (work <= 0.0) {
- return
- }
-
- val counters = _counters
- val remainingWork = ctx.remainingWork
- counters.demand += work
- counters.actual += work - remainingWork
-
- if (willOvercommit && remainingWork > 0.0) {
- counters.overcommit += remainingWork
- }
- }
-
- final override fun startConsumer(consumer: SimResourceConsumer) {
- check(ctx == null) { "Resource is in invalid state" }
- val ctx = interpreter.newContext(consumer, createLogic(), parent)
-
- ctx.capacity = capacity
- this.ctx = ctx
-
- start(ctx)
- }
-
- final override fun interrupt() {
- ctx?.interrupt()
- }
-
- final override fun cancel() {
- val ctx = ctx
- if (ctx != null) {
- this.ctx = null
- ctx.close()
- }
- }
-
- override fun toString(): String = "SimAbstractResourceProvider[capacity=$capacity]"
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregator.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregator.kt
deleted file mode 100644
index 00972f43..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregator.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A [SimResourceAggregator] aggregates the capacity of multiple resources into a single resource.
- */
-public interface SimResourceAggregator : SimResourceProvider {
- /**
- * The input resources that will be switched between the output providers.
- */
- public val inputs: Set<SimResourceProvider>
-
- /**
- * Add the specified [input] to the aggregator.
- */
- public fun addInput(input: SimResourceProvider)
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt
deleted file mode 100644
index 991cda7a..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A [SimResourceAggregator] that distributes the load equally across the input resources.
- */
-public class SimResourceAggregatorMaxMin(
- interpreter: SimResourceInterpreter,
- parent: SimResourceSystem? = null
-) : SimAbstractResourceAggregator(interpreter, parent) {
- private val consumers = mutableListOf<Input>()
-
- override fun doConsume(work: Double, limit: Double, deadline: Long) {
- // Sort all consumers by their capacity
- consumers.sortWith(compareBy { it.ctx.capacity })
-
- // Divide the requests over the available capacity of the input resources fairly
- for (input in consumers) {
- val inputCapacity = input.ctx.capacity
- val fraction = inputCapacity / capacity
- val grantedSpeed = limit * fraction
- val grantedWork = fraction * work
-
- val command = if (grantedWork > 0.0 && grantedSpeed > 0.0)
- SimResourceCommand.Consume(grantedWork, grantedSpeed, deadline)
- else
- SimResourceCommand.Idle()
- input.push(command)
- }
- }
-
- override fun doIdle(deadline: Long) {
- for (input in consumers) {
- input.push(SimResourceCommand.Idle(deadline))
- }
- }
-
- override fun doFinish() {
- val iterator = consumers.iterator()
- for (input in iterator) {
- iterator.remove()
- input.push(SimResourceCommand.Exit)
- }
- }
-
- override fun onInputStarted(input: Input) {
- consumers.add(input)
- }
-
- override fun onInputFinished(input: Input) {
- consumers.remove(input)
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCloseableProvider.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCloseableProvider.kt
deleted file mode 100644
index bce8274b..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCloseableProvider.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A [SimResourceProvider] that has a controllable and limited lifetime.
- *
- * This interface is used to signal that the resource provider may be closed and not reused after that point.
- */
-public interface SimResourceCloseableProvider : SimResourceProvider, AutoCloseable {
- /**
- * End the lifetime of the resource provider.
- *
- * This operation cancels the existing resource consumer and prevents the resource provider from being reused.
- */
- public override fun close()
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCommand.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCommand.kt
deleted file mode 100644
index f7f3fa4d..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCommand.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A SimResourceCommand communicates to a resource how it is consumed by a [SimResourceConsumer].
- */
-public sealed class SimResourceCommand {
- /**
- * A request to the resource to perform the specified amount of work before the given [deadline].
- *
- * @param work The amount of work to process.
- * @param limit The maximum amount of work to be processed per second.
- * @param deadline The instant at which the work needs to be fulfilled.
- */
- public data class Consume(val work: Double, val limit: Double, val deadline: Long = Long.MAX_VALUE) : SimResourceCommand() {
- init {
- require(work > 0) { "Amount of work must be positive" }
- require(limit > 0) { "Limit must be positive" }
- }
- }
-
- /**
- * An indication to the resource that the consumer will idle until the specified [deadline] or if it is interrupted.
- */
- public data class Idle(val deadline: Long = Long.MAX_VALUE) : SimResourceCommand()
-
- /**
- * An indication to the resource that the consumer has finished.
- */
- public object Exit : SimResourceCommand()
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceConsumer.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceConsumer.kt
deleted file mode 100644
index 4d937514..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceConsumer.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A [SimResourceConsumer] characterizes how a resource is consumed.
- *
- * Implementors of this interface should be considered stateful and must be assumed not to be re-usable (concurrently)
- * for multiple resource providers, unless explicitly said otherwise.
- */
-public interface SimResourceConsumer {
- /**
- * This method is invoked when a resource asks for the next [command][SimResourceCommand] to process, either because
- * the resource finished processing, reached its deadline or was interrupted.
- *
- * @param ctx The execution context in which the consumer runs.
- * @return The next command that the resource should execute.
- */
- public fun onNext(ctx: SimResourceContext): SimResourceCommand
-
- /**
- * This method is invoked when an event has occurred.
- *
- * @param ctx The execution context in which the consumer runs.
- * @param event The event that has occurred.
- */
- public fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {}
-
- /**
- * This method is invoked when a resource consumer throws an exception.
- *
- * @param ctx The execution context in which the consumer runs.
- * @param cause The cause of the failure.
- */
- public fun onFailure(ctx: SimResourceContext, cause: Throwable) {}
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceContext.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceContext.kt
deleted file mode 100644
index 0d9a6106..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceContext.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.resources
-
-import java.time.Clock
-
-/**
- * The execution context in which a [SimResourceConsumer] runs. It facilitates the communication and control between a
- * resource and a resource consumer.
- */
-public interface SimResourceContext {
- /**
- * The virtual clock tracking simulation time.
- */
- public val clock: Clock
-
- /**
- * The resource capacity available at this instant.
- */
- public val capacity: Double
-
- /**
- * The resource processing speed at this instant.
- */
- public val speed: Double
-
- /**
- * The resource processing speed demand at this instant.
- */
- public val demand: Double
-
- /**
- * The amount of work still remaining at this instant.
- */
- public val remainingWork: Double
-
- /**
- * Ask the resource provider to interrupt its resource.
- */
- public fun interrupt()
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceControllableContext.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceControllableContext.kt
deleted file mode 100644
index ceaca39a..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceControllableContext.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A controllable [SimResourceContext].
- *
- * This interface is used by resource providers to control the resource context.
- */
-public interface SimResourceControllableContext : SimResourceContext, AutoCloseable {
- /**
- * The state of the resource context.
- */
- public val state: SimResourceState
-
- /**
- * The capacity of the resource.
- */
- public override var capacity: Double
-
- /**
- * Start the resource context.
- */
- public fun start()
-
- /**
- * Stop the resource context.
- */
- public override fun close()
-
- /**
- * Invalidate the resource context's state.
- *
- * By invalidating the resource context's current state, the state is re-computed and the current progress is
- * materialized during the next interpreter cycle. As a result, this call run asynchronously. See [flush] for the
- * synchronous variant.
- */
- public fun invalidate()
-
- /**
- * Synchronously flush the progress of the resource context and materialize its current progress.
- */
- public fun flush()
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCounters.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCounters.kt
deleted file mode 100644
index 725aa5bc..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCounters.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.resources
-
-/**
- * An interface that tracks cumulative counts of the work performed by a resource.
- */
-public interface SimResourceCounters {
- /**
- * The amount of work that resource consumers wanted the resource to perform.
- */
- public val demand: Double
-
- /**
- * The amount of work performed by the resource.
- */
- public val actual: Double
-
- /**
- * The amount of work that could not be completed due to overcommitted resources.
- */
- public val overcommit: Double
-
- /**
- * Reset the resource counters.
- */
- public fun reset()
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributor.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributor.kt
deleted file mode 100644
index f384582f..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributor.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.interference.InterferenceKey
-
-/**
- * A [SimResourceDistributor] distributes the capacity of some resource over multiple resource consumers.
- */
-public interface SimResourceDistributor : SimResourceConsumer {
- /**
- * The output resource providers to which resource consumers can be attached.
- */
- public val outputs: Set<SimResourceCloseableProvider>
-
- /**
- * Create a new output for the distributor.
- *
- * @param key The key of the interference member to which the output belongs.
- */
- public fun newOutput(key: InterferenceKey? = null): SimResourceCloseableProvider
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt
deleted file mode 100644
index 6c1e134b..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.interference.InterferenceDomain
-import org.opendc.simulator.resources.interference.InterferenceKey
-import kotlin.math.max
-import kotlin.math.min
-
-/**
- * A [SimResourceDistributor] that distributes the capacity of a resource over consumers using max-min fair sharing.
- *
- * @param interpreter The interpreter for managing the resource contexts.
- * @param parent The parent resource system of the distributor.
- * @param interferenceDomain The interference domain of the distributor.
- */
-public class SimResourceDistributorMaxMin(
- private val interpreter: SimResourceInterpreter,
- private val parent: SimResourceSystem? = null,
- private val interferenceDomain: InterferenceDomain? = null
-) : SimResourceDistributor {
- override val outputs: Set<SimResourceCloseableProvider>
- get() = _outputs
- private val _outputs = mutableSetOf<Output>()
-
- /**
- * The resource context of the consumer.
- */
- private var ctx: SimResourceContext? = null
-
- /**
- * The active outputs.
- */
- private val activeOutputs: MutableList<Output> = mutableListOf()
-
- /**
- * The total amount of work allocated to be executed.
- */
- private var totalAllocatedWork = 0.0
-
- /**
- * The total allocated speed for the output resources.
- */
- private var totalAllocatedSpeed = 0.0
-
- /**
- * The total requested speed for the output resources.
- */
- private var totalRequestedSpeed = 0.0
-
- /**
- * The resource counters of this distributor.
- */
- public val counters: Counters
- get() = _counters
- private val _counters = object : Counters {
- override var demand: Double = 0.0
- override var actual: Double = 0.0
- override var overcommit: Double = 0.0
- override var interference: Double = 0.0
-
- override fun reset() {
- demand = 0.0
- actual = 0.0
- overcommit = 0.0
- interference = 0.0
- }
-
- override fun toString(): String = "SimResourceDistributorMaxMin.Counters[demand=$demand,actual=$actual,overcommit=$overcommit,interference=$interference]"
- }
-
- /* SimResourceDistributor */
- override fun newOutput(key: InterferenceKey?): SimResourceCloseableProvider {
- val provider = Output(ctx?.capacity ?: 0.0, key)
- _outputs.add(provider)
- return provider
- }
-
- /* SimResourceConsumer */
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- return doNext(ctx)
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> {
- this.ctx = ctx
- updateCapacity(ctx)
- }
- SimResourceEvent.Exit -> {
- val iterator = _outputs.iterator()
- while (iterator.hasNext()) {
- val output = iterator.next()
-
- // Remove the output from the outputs to prevent ConcurrentModificationException when removing it
- // during the call to output.close()
- iterator.remove()
-
- output.close()
- }
- }
- SimResourceEvent.Capacity -> updateCapacity(ctx)
- else -> {}
- }
- }
-
- /**
- * Extended [SimResourceCounters] interface for the distributor.
- */
- public interface Counters : SimResourceCounters {
- /**
- * The amount of work lost due to interference.
- */
- public val interference: Double
- }
-
- /**
- * Update the counters of the distributor.
- */
- private fun updateCounters(ctx: SimResourceControllableContext, work: Double, willOvercommit: Boolean) {
- if (work <= 0.0) {
- return
- }
-
- val counters = _counters
- val remainingWork = ctx.remainingWork
-
- counters.demand += work
- counters.actual += work - remainingWork
-
- if (willOvercommit && remainingWork > 0.0) {
- counters.overcommit += remainingWork
- }
- }
-
- /**
- * Schedule the work of the outputs.
- */
- private fun doNext(ctx: SimResourceContext): SimResourceCommand {
- // If there is no work yet, mark the input as idle.
- if (activeOutputs.isEmpty()) {
- return SimResourceCommand.Idle()
- }
-
- val capacity = ctx.capacity
- var duration: Double = Double.MAX_VALUE
- var deadline: Long = Long.MAX_VALUE
- var availableSpeed = capacity
- var totalRequestedSpeed = 0.0
-
- // Pull in the work of the outputs
- val outputIterator = activeOutputs.listIterator()
- for (output in outputIterator) {
- output.pull()
-
- // Remove outputs that have finished
- if (!output.isActive) {
- outputIterator.remove()
- }
- }
-
- // Sort in-place the outputs based on their requested usage.
- // Profiling shows that it is faster than maintaining some kind of sorted set.
- activeOutputs.sort()
-
- // Divide the available input capacity fairly across the outputs using max-min fair sharing
- var remaining = activeOutputs.size
- for (output in activeOutputs) {
- val availableShare = availableSpeed / remaining--
- val grantedSpeed = min(output.allowedSpeed, availableShare)
-
- deadline = min(deadline, output.deadline)
-
- // Ignore idle computation
- if (grantedSpeed <= 0.0 || output.work <= 0.0) {
- output.actualSpeed = 0.0
- continue
- }
-
- totalRequestedSpeed += output.limit
-
- output.actualSpeed = grantedSpeed
- availableSpeed -= grantedSpeed
-
- // The duration that we want to run is that of the shortest request of an output
- duration = min(duration, output.work / grantedSpeed)
- }
-
- val targetDuration = min(duration, (deadline - interpreter.clock.millis()) / 1000.0)
- var totalRequestedWork = 0.0
- var totalAllocatedWork = 0.0
- for (output in activeOutputs) {
- val work = output.work
- val speed = output.actualSpeed
- if (speed > 0.0) {
- val outputDuration = work / speed
- totalRequestedWork += work * (duration / outputDuration)
- totalAllocatedWork += work * (targetDuration / outputDuration)
- }
- }
-
- assert(deadline >= interpreter.clock.millis()) { "Deadline already passed" }
-
- this.totalRequestedSpeed = totalRequestedSpeed
- this.totalAllocatedWork = totalAllocatedWork
- val totalAllocatedSpeed = capacity - availableSpeed
- this.totalAllocatedSpeed = totalAllocatedSpeed
-
- return if (totalAllocatedWork > 0.0 && totalAllocatedSpeed > 0.0)
- SimResourceCommand.Consume(totalAllocatedWork, totalAllocatedSpeed, deadline)
- else
- SimResourceCommand.Idle(deadline)
- }
-
- private fun updateCapacity(ctx: SimResourceContext) {
- for (output in _outputs) {
- output.capacity = ctx.capacity
- }
- }
-
- /**
- * An internal [SimResourceProvider] implementation for switch outputs.
- */
- private inner class Output(capacity: Double, private val key: InterferenceKey?) :
- SimAbstractResourceProvider(interpreter, parent, capacity),
- SimResourceCloseableProvider,
- SimResourceProviderLogic,
- Comparable<Output> {
- /**
- * A flag to indicate that the output is closed.
- */
- private var isClosed: Boolean = false
-
- /**
- * The current requested work.
- */
- var work: Double = 0.0
-
- /**
- * The requested limit.
- */
- var limit: Double = 0.0
-
- /**
- * The current deadline.
- */
- var deadline: Long = Long.MAX_VALUE
-
- /**
- * The processing speed that is allowed by the model constraints.
- */
- var allowedSpeed: Double = 0.0
-
- /**
- * The actual processing speed.
- */
- var actualSpeed: Double = 0.0
-
- /**
- * The timestamp at which we received the last command.
- */
- private var lastCommandTimestamp: Long = Long.MIN_VALUE
-
- /* SimAbstractResourceProvider */
- override fun createLogic(): SimResourceProviderLogic = this
-
- override fun start(ctx: SimResourceControllableContext) {
- check(!isClosed) { "Cannot re-use closed output" }
-
- activeOutputs += this
- interpreter.batch {
- ctx.start()
- // Interrupt the input to re-schedule the resources
- this@SimResourceDistributorMaxMin.ctx?.interrupt()
- }
- }
-
- override fun close() {
- isClosed = true
- cancel()
- _outputs.remove(this)
- }
-
- /* SimResourceProviderLogic */
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long {
- allowedSpeed = 0.0
- this.deadline = deadline
- work = 0.0
- limit = 0.0
- lastCommandTimestamp = ctx.clock.millis()
-
- return Long.MAX_VALUE
- }
-
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long {
- allowedSpeed = min(ctx.capacity, limit)
- this.work = work
- this.limit = limit
- this.deadline = deadline
- lastCommandTimestamp = ctx.clock.millis()
-
- return Long.MAX_VALUE
- }
-
- override fun onUpdate(ctx: SimResourceControllableContext, work: Double, willOvercommit: Boolean) {
- updateCounters(ctx, work, willOvercommit)
-
- this@SimResourceDistributorMaxMin.updateCounters(ctx, work, willOvercommit)
- }
-
- override fun onFinish(ctx: SimResourceControllableContext) {
- work = 0.0
- limit = 0.0
- deadline = Long.MAX_VALUE
- lastCommandTimestamp = ctx.clock.millis()
- }
-
- override fun getConsumedWork(ctx: SimResourceControllableContext, work: Double, speed: Double, duration: Long): Double {
- val totalRemainingWork = this@SimResourceDistributorMaxMin.ctx?.remainingWork ?: 0.0
-
- // Compute the fraction of compute time allocated to the output
- val fraction = actualSpeed / totalAllocatedSpeed
-
- // Compute the performance penalty due to resource interference
- val perfScore = if (interferenceDomain != null) {
- val load = totalAllocatedSpeed / requireNotNull(this@SimResourceDistributorMaxMin.ctx).capacity
- interferenceDomain.apply(key, load)
- } else {
- 1.0
- }
-
- // Compute the work that was actually granted to the output.
- val potentialConsumedWork = (totalAllocatedWork - totalRemainingWork) * fraction
-
- _counters.interference += potentialConsumedWork * max(0.0, 1 - perfScore)
-
- return potentialConsumedWork
- }
-
- /* Comparable */
- override fun compareTo(other: Output): Int = allowedSpeed.compareTo(other.allowedSpeed)
-
- /**
- * Pull the next command if necessary.
- */
- fun pull() {
- val ctx = ctx
- if (ctx != null && lastCommandTimestamp < ctx.clock.millis()) {
- ctx.flush()
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceEvent.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceEvent.kt
deleted file mode 100644
index 959427f1..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceEvent.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A resource event that is communicated to the resource consumer.
- */
-public enum class SimResourceEvent {
- /**
- * This event is emitted to the consumer when it has started.
- */
- Start,
-
- /**
- * This event is emitted to the consumer when it has exited.
- */
- Exit,
-
- /**
- * This event is emitted to the consumer when it has started a new resource consumption or idle cycle.
- */
- Run,
-
- /**
- * This event is emitted to the consumer when the capacity of the resource has changed.
- */
- Capacity,
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceFlow.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceFlow.kt
deleted file mode 100644
index bbf6ad44..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceFlow.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A [SimResourceFlow] acts as both a resource consumer and resource provider at the same time, simplifying bridging
- * between different components.
- */
-public interface SimResourceFlow : SimResourceConsumer, SimResourceProvider
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceInterpreter.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceInterpreter.kt
deleted file mode 100644
index 82631377..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceInterpreter.kt
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-import java.time.Clock
-import kotlin.coroutines.CoroutineContext
-
-/**
- * The resource interpreter is responsible for managing the interaction between resource consumer and provider.
- *
- * The interpreter centralizes the scheduling logic of state updates of resource context, allowing update propagation
- * to happen more efficiently. and overall, reducing the work necessary to transition into a steady state.
- */
-public interface SimResourceInterpreter {
- /**
- * The [Clock] associated with this interpreter.
- */
- public val clock: Clock
-
- /**
- * Create a new [SimResourceControllableContext] with the given [provider].
- *
- * @param consumer The consumer logic.
- * @param provider The logic of the resource provider.
- * @param parent The system to which the resource context belongs.
- */
- public fun newContext(
- consumer: SimResourceConsumer,
- provider: SimResourceProviderLogic,
- parent: SimResourceSystem? = null
- ): SimResourceControllableContext
-
- /**
- * Start batching the execution of resource updates until [popBatch] is called.
- *
- * This method is useful if you want to propagate multiple resources updates (e.g., starting multiple CPUs
- * simultaneously) in a single state update.
- *
- * Multiple calls to this method requires the same number of [popBatch] calls in order to properly flush the
- * resource updates. This allows nested calls to [pushBatch], but might cause issues if [popBatch] is not called
- * the same amount of times. To simplify batching, see [batch].
- */
- public fun pushBatch()
-
- /**
- * Stop the batching of resource updates and run the interpreter on the batch.
- *
- * Note that method will only flush the event once the first call to [pushBatch] has received a [popBatch] call.
- */
- public fun popBatch()
-
- public companion object {
- /**
- * Construct a new [SimResourceInterpreter] implementation.
- *
- * @param context The coroutine context to use.
- * @param clock The virtual simulation clock.
- */
- @JvmName("create")
- public operator fun invoke(context: CoroutineContext, clock: Clock): SimResourceInterpreter {
- return SimResourceInterpreterImpl(context, clock)
- }
- }
-}
-
-/**
- * Batch the execution of several interrupts into a single call.
- *
- * This method is useful if you want to propagate the start of multiple resources (e.g., CPUs) in a single update.
- */
-public inline fun SimResourceInterpreter.batch(block: () -> Unit) {
- try {
- pushBatch()
- block()
- } finally {
- popBatch()
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProvider.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProvider.kt
deleted file mode 100644
index b68b7261..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProvider.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.resources
-
-import kotlinx.coroutines.suspendCancellableCoroutine
-import kotlin.coroutines.resume
-import kotlin.coroutines.resumeWithException
-
-/**
- * A [SimResourceProvider] provides a resource that can be consumed by a [SimResourceConsumer].
- */
-public interface SimResourceProvider {
- /**
- * A flag to indicate that the resource provider is currently being consumed by a [SimResourceConsumer].
- */
- public val isActive: Boolean
-
- /**
- * The resource capacity available at this instant.
- */
- public val capacity: Double
-
- /**
- * The current processing speed of the resource.
- */
- public val speed: Double
-
- /**
- * The resource processing speed demand at this instant.
- */
- public val demand: Double
-
- /**
- * The resource counters to track the execution metrics of the resource.
- */
- public val counters: SimResourceCounters
-
- /**
- * Start the specified [resource consumer][consumer] in the context of this resource provider asynchronously.
- *
- * @throws IllegalStateException if there is already a consumer active or the resource lifetime has ended.
- */
- public fun startConsumer(consumer: SimResourceConsumer)
-
- /**
- * Interrupt the resource consumer. If there is no consumer active, this operation will be a no-op.
- */
- public fun interrupt()
-
- /**
- * Cancel the current resource consumer. If there is no consumer active, this operation will be a no-op.
- */
- public fun cancel()
-}
-
-/**
- * Consume the resource provided by this provider using the specified [consumer] and suspend execution until
- * the consumer has finished.
- */
-public suspend fun SimResourceProvider.consume(consumer: SimResourceConsumer) {
- return suspendCancellableCoroutine { cont ->
- startConsumer(object : SimResourceConsumer by consumer {
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- consumer.onEvent(ctx, event)
-
- if (event == SimResourceEvent.Exit && !cont.isCompleted) {
- cont.resume(Unit)
- }
- }
-
- override fun onFailure(ctx: SimResourceContext, cause: Throwable) {
- try {
- consumer.onFailure(ctx, cause)
- cont.resumeWithException(cause)
- } catch (e: Throwable) {
- e.addSuppressed(cause)
- cont.resumeWithException(e)
- }
- }
-
- override fun toString(): String = "SimSuspendingResourceConsumer"
- })
-
- cont.invokeOnCancellation { cancel() }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProviderLogic.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProviderLogic.kt
deleted file mode 100644
index 2fe1b00f..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProviderLogic.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.resources
-
-/**
- * The logic of a resource provider.
- */
-public interface SimResourceProviderLogic {
- /**
- * This method is invoked when the resource is reported to idle until the specified [deadline].
- *
- * @param ctx The context in which the provider runs.
- * @param deadline The deadline that was requested by the resource consumer.
- * @return The instant at which to resume the consumer.
- */
- public fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long
-
- /**
- * This method is invoked when the resource will be consumed until the specified amount of [work] was processed
- * or [deadline] is reached.
- *
- * @param ctx The context in which the provider runs.
- * @param work The amount of work that was requested by the resource consumer.
- * @param limit The limit on the work rate of the resource consumer.
- * @param deadline The deadline that was requested by the resource consumer.
- * @return The instant at which to resume the consumer.
- */
- public fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long
-
- /**
- * This method is invoked when the progress of the resource consumer is materialized.
- *
- * @param ctx The context in which the provider runs.
- * @param work The amount of work that was requested by the resource consumer.
- * @param willOvercommit A flag to indicate that the remaining work is overcommitted.
- */
- public fun onUpdate(ctx: SimResourceControllableContext, work: Double, willOvercommit: Boolean) {}
-
- /**
- * This method is invoked when the resource consumer has finished.
- */
- public fun onFinish(ctx: SimResourceControllableContext)
-
- /**
- * Compute the amount of work that was consumed over the specified [duration].
- *
- * @param work The total size of the resource consumption.
- * @param speed The speed of the resource provider.
- * @param duration The duration from the start of the consumption until now.
- * @return The amount of work that was consumed by the resource provider.
- */
- public fun getConsumedWork(ctx: SimResourceControllableContext, work: Double, speed: Double, duration: Long): Double {
- return if (duration > 0L) {
- return (duration / 1000.0) * speed
- } else {
- work
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSource.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSource.kt
deleted file mode 100644
index 2d53198a..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSource.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.resources
-
-import kotlin.math.ceil
-import kotlin.math.min
-
-/**
- * A [SimResourceSource] represents a source for some resource that provides bounded processing capacity.
- *
- * @param initialCapacity The initial capacity of the resource.
- * @param interpreter The interpreter that is used for managing the resource contexts.
- * @param parent The parent resource system.
- */
-public class SimResourceSource(
- initialCapacity: Double,
- private val interpreter: SimResourceInterpreter,
- private val parent: SimResourceSystem? = null
-) : SimAbstractResourceProvider(interpreter, parent, initialCapacity) {
- override fun createLogic(): SimResourceProviderLogic {
- return object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long {
- return deadline
- }
-
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long {
- return if (work.isInfinite()) {
- Long.MAX_VALUE
- } else {
- min(deadline, ctx.clock.millis() + getDuration(work, speed))
- }
- }
-
- override fun onUpdate(ctx: SimResourceControllableContext, work: Double, willOvercommit: Boolean) {
- updateCounters(ctx, work, willOvercommit)
- }
-
- override fun onFinish(ctx: SimResourceControllableContext) {
- cancel()
- }
- }
- }
-
- override fun toString(): String = "SimResourceSource[capacity=$capacity]"
-
- /**
- * Compute the duration that a resource consumption will take with the specified [speed].
- */
- private fun getDuration(work: Double, speed: Double): Long {
- return ceil(work / speed * 1000).toLong()
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceState.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceState.kt
deleted file mode 100644
index c72951d0..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceState.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.resources
-
-/**
- * The state of a resource provider.
- */
-public enum class SimResourceState {
- /**
- * The resource provider is pending and the resource is waiting to be consumed.
- */
- Pending,
-
- /**
- * The resource provider is active and the resource is currently being consumed.
- */
- Active,
-
- /**
- * The resource provider is stopped and the resource cannot be consumed anymore.
- */
- Stopped
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitch.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitch.kt
deleted file mode 100644
index d2aab634..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitch.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.interference.InterferenceKey
-
-/**
- * A [SimResourceSwitch] enables switching of capacity of multiple resources between multiple consumers.
- */
-public interface SimResourceSwitch : AutoCloseable {
- /**
- * The output resource providers to which resource consumers can be attached.
- */
- public val outputs: Set<SimResourceCloseableProvider>
-
- /**
- * The input resources that will be switched between the output providers.
- */
- public val inputs: Set<SimResourceProvider>
-
- /**
- * The resource counters to track the execution metrics of all switch resources.
- */
- public val counters: SimResourceCounters
-
- /**
- * Create a new output on the switch.
- *
- * @param key The key of the interference member to which the output belongs.
- */
- public fun newOutput(key: InterferenceKey? = null): SimResourceCloseableProvider
-
- /**
- * Add the specified [input] to the switch.
- */
- public fun addInput(input: SimResourceProvider)
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusive.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusive.kt
deleted file mode 100644
index fbb541e5..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusive.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.interference.InterferenceKey
-import java.util.ArrayDeque
-
-/**
- * A [SimResourceSwitch] implementation that allocates outputs to the inputs of the switch exclusively. This means that
- * a single output is directly connected to an input and that the switch can only support as much outputs as inputs.
- */
-public class SimResourceSwitchExclusive : SimResourceSwitch {
- /**
- * A flag to indicate that the switch is closed.
- */
- private var isClosed: Boolean = false
-
- private val _outputs = mutableSetOf<Provider>()
- override val outputs: Set<SimResourceCloseableProvider>
- get() = _outputs
-
- private val availableResources = ArrayDeque<SimResourceTransformer>()
-
- private val _inputs = mutableSetOf<SimResourceProvider>()
- override val inputs: Set<SimResourceProvider>
- get() = _inputs
-
- override val counters: SimResourceCounters = object : SimResourceCounters {
- override val demand: Double
- get() = _inputs.sumOf { it.counters.demand }
- override val actual: Double
- get() = _inputs.sumOf { it.counters.actual }
- override val overcommit: Double
- get() = _inputs.sumOf { it.counters.overcommit }
-
- override fun reset() {
- for (input in _inputs) {
- input.counters.reset()
- }
- }
-
- override fun toString(): String = "SimResourceCounters[demand=$demand,actual=$actual,overcommit=$overcommit]"
- }
-
- /**
- * Add an output to the switch.
- */
- override fun newOutput(key: InterferenceKey?): SimResourceCloseableProvider {
- check(!isClosed) { "Switch has been closed" }
- check(availableResources.isNotEmpty()) { "No capacity to serve request" }
- val forwarder = availableResources.poll()
- val output = Provider(forwarder)
- _outputs += output
- return output
- }
-
- override fun addInput(input: SimResourceProvider) {
- check(!isClosed) { "Switch has been closed" }
-
- if (input in inputs) {
- return
- }
-
- val forwarder = SimResourceForwarder()
-
- _inputs += input
- availableResources += forwarder
-
- input.startConsumer(object : SimResourceConsumer by forwarder {
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- if (event == SimResourceEvent.Exit) {
- // De-register the input after it has finished
- _inputs -= input
- }
-
- forwarder.onEvent(ctx, event)
- }
- })
- }
-
- override fun close() {
- isClosed = true
-
- // Cancel all upstream subscriptions
- _inputs.forEach(SimResourceProvider::cancel)
- }
-
- private inner class Provider(private val forwarder: SimResourceTransformer) : SimResourceCloseableProvider, SimResourceProvider by forwarder {
- override fun close() {
- // We explicitly do not close the forwarder here in order to re-use it across output resources.
- _outputs -= this
- availableResources += forwarder
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMin.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMin.kt
deleted file mode 100644
index e368609f..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMin.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.interference.InterferenceDomain
-import org.opendc.simulator.resources.interference.InterferenceKey
-
-/**
- * A [SimResourceSwitch] implementation that switches resource consumptions over the available resources using max-min
- * fair sharing.
- *
- * @param interpreter The interpreter for managing the resource contexts.
- * @param parent The parent resource system of the switch.
- * @param interferenceDomain The interference domain of the switch.
- */
-public class SimResourceSwitchMaxMin(
- interpreter: SimResourceInterpreter,
- parent: SimResourceSystem? = null,
- interferenceDomain: InterferenceDomain? = null
-) : SimResourceSwitch {
- /**
- * The output resource providers to which resource consumers can be attached.
- */
- override val outputs: Set<SimResourceCloseableProvider>
- get() = distributor.outputs
-
- /**
- * The input resources that will be switched between the output providers.
- */
- override val inputs: Set<SimResourceProvider>
- get() = aggregator.inputs
-
- /**
- * The resource counters to track the execution metrics of all switch resources.
- */
- override val counters: SimResourceDistributorMaxMin.Counters
- get() = distributor.counters
-
- /**
- * A flag to indicate that the switch was closed.
- */
- private var isClosed = false
-
- /**
- * The aggregator to aggregate the resources.
- */
- private val aggregator = SimResourceAggregatorMaxMin(interpreter, parent)
-
- /**
- * The distributor to distribute the aggregated resources.
- */
- private val distributor = SimResourceDistributorMaxMin(interpreter, parent, interferenceDomain)
-
- init {
- aggregator.startConsumer(distributor)
- }
-
- /**
- * Add an output to the switch.
- */
- override fun newOutput(key: InterferenceKey?): SimResourceCloseableProvider {
- check(!isClosed) { "Switch has been closed" }
-
- return distributor.newOutput(key)
- }
-
- /**
- * Add the specified [input] to the switch.
- */
- override fun addInput(input: SimResourceProvider) {
- check(!isClosed) { "Switch has been closed" }
-
- aggregator.addInput(input)
- }
-
- override fun close() {
- if (!isClosed) {
- isClosed = true
- aggregator.cancel()
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSystem.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSystem.kt
deleted file mode 100644
index 609262cb..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSystem.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.resources
-
-/**
- * A system of possible multiple sub-resources.
- *
- * This interface is used to model hierarchies of resource providers, which can listen efficiently to changes of the
- * resource provider.
- */
-public interface SimResourceSystem {
- /**
- * The parent system to which this system belongs or `null` if it has no parent.
- */
- public val parent: SimResourceSystem?
-
- /**
- * This method is invoked when the system has converged to a steady-state.
- *
- * @param timestamp The timestamp at which the system converged.
- */
- public fun onConverge(timestamp: Long)
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceTransformer.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceTransformer.kt
deleted file mode 100644
index cec27e1c..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceTransformer.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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.resources
-
-import org.opendc.simulator.resources.impl.SimResourceCountersImpl
-
-/**
- * A [SimResourceFlow] that transforms the resource commands emitted by the resource commands to the resource provider.
- *
- * @param isCoupled A flag to indicate that the transformer will exit when the resource consumer exits.
- * @param transform The function to transform the received resource command.
- */
-public class SimResourceTransformer(
- private val isCoupled: Boolean = false,
- private val transform: (SimResourceContext, SimResourceCommand) -> SimResourceCommand
-) : SimResourceFlow, AutoCloseable {
- /**
- * The [SimResourceContext] in which the forwarder runs.
- */
- private var ctx: SimResourceContext? = null
-
- /**
- * The delegate [SimResourceConsumer].
- */
- private var delegate: SimResourceConsumer? = null
-
- /**
- * A flag to indicate that the delegate was started.
- */
- private var hasDelegateStarted: Boolean = false
-
- override val isActive: Boolean
- get() = delegate != null
-
- override val capacity: Double
- get() = ctx?.capacity ?: 0.0
-
- override val speed: Double
- get() = ctx?.speed ?: 0.0
-
- override val demand: Double
- get() = ctx?.demand ?: 0.0
-
- override val counters: SimResourceCounters
- get() = _counters
- private val _counters = SimResourceCountersImpl()
-
- override fun startConsumer(consumer: SimResourceConsumer) {
- check(delegate == null) { "Resource transformer already active" }
-
- delegate = consumer
-
- // Interrupt the provider to replace the consumer
- interrupt()
- }
-
- override fun interrupt() {
- ctx?.interrupt()
- }
-
- override fun cancel() {
- val delegate = delegate
- val ctx = ctx
-
- if (delegate != null) {
- this.delegate = null
-
- if (ctx != null) {
- delegate.onEvent(ctx, SimResourceEvent.Exit)
- }
- }
- }
-
- override fun close() {
- val ctx = ctx
-
- if (ctx != null) {
- this.ctx = null
- ctx.interrupt()
- }
- }
-
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- val delegate = delegate
-
- if (!hasDelegateStarted) {
- start()
- }
-
- updateCounters(ctx)
-
- return if (delegate != null) {
- val command = transform(ctx, delegate.onNext(ctx))
-
- _work = if (command is SimResourceCommand.Consume) command.work else 0.0
-
- if (command == SimResourceCommand.Exit) {
- // Warning: resumption of the continuation might change the entire state of the forwarder. Make sure we
- // reset beforehand the existing state and check whether it has been updated afterwards
- reset()
-
- delegate.onEvent(ctx, SimResourceEvent.Exit)
-
- if (isCoupled)
- SimResourceCommand.Exit
- else
- onNext(ctx)
- } else {
- command
- }
- } else {
- SimResourceCommand.Idle()
- }
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> {
- this.ctx = ctx
- }
- SimResourceEvent.Exit -> {
- this.ctx = null
-
- val delegate = delegate
- if (delegate != null) {
- reset()
- delegate.onEvent(ctx, SimResourceEvent.Exit)
- }
- }
- else -> delegate?.onEvent(ctx, event)
- }
- }
-
- override fun onFailure(ctx: SimResourceContext, cause: Throwable) {
- this.ctx = null
-
- val delegate = delegate
- if (delegate != null) {
- reset()
- delegate.onFailure(ctx, cause)
- }
- }
-
- /**
- * Start the delegate.
- */
- private fun start() {
- val delegate = delegate ?: return
- delegate.onEvent(checkNotNull(ctx), SimResourceEvent.Start)
-
- hasDelegateStarted = true
- }
-
- /**
- * Reset the delegate.
- */
- private fun reset() {
- delegate = null
- hasDelegateStarted = false
- }
-
- /**
- * Counter to track the current submitted work.
- */
- private var _work = 0.0
-
- /**
- * Update the resource counters for the transformer.
- */
- private fun updateCounters(ctx: SimResourceContext) {
- val counters = _counters
- val remainingWork = ctx.remainingWork
- counters.demand += _work
- counters.actual += _work - remainingWork
- counters.overcommit += remainingWork
- }
-}
-
-/**
- * Constructs a [SimResourceTransformer] that forwards the received resource command with an identity transform.
- *
- * @param isCoupled A flag to indicate that the transformer will exit when the resource consumer exits.
- */
-public fun SimResourceForwarder(isCoupled: Boolean = false): SimResourceTransformer {
- return SimResourceTransformer(isCoupled) { _, command -> command }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimConsumerBarrier.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimConsumerBarrier.kt
deleted file mode 100644
index 52a42241..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimConsumerBarrier.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.resources.consumer
-
-/**
- * The [SimConsumerBarrier] is a barrier that allows consumers to wait for a select number of other consumers to
- * complete, before proceeding its operation.
- */
-public class SimConsumerBarrier(public val parties: Int) {
- private var counter = 0
-
- /**
- * Enter the barrier and determine whether the caller is the last to reach the barrier.
- *
- * @return `true` if the caller is the last to reach the barrier, `false` otherwise.
- */
- public fun enter(): Boolean {
- val last = ++counter == parties
- if (last) {
- counter = 0
- return true
- }
- return false
- }
-
- /**
- * Reset the barrier.
- */
- public fun reset() {
- counter = 0
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimSpeedConsumerAdapter.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimSpeedConsumerAdapter.kt
deleted file mode 100644
index 4f4ebb14..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimSpeedConsumerAdapter.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.resources.consumer
-
-import org.opendc.simulator.resources.SimResourceCommand
-import org.opendc.simulator.resources.SimResourceConsumer
-import org.opendc.simulator.resources.SimResourceContext
-import org.opendc.simulator.resources.SimResourceEvent
-import kotlin.math.min
-
-/**
- * Helper class to expose an observable [speed] field describing the speed of the consumer.
- */
-public class SimSpeedConsumerAdapter(
- private val delegate: SimResourceConsumer,
- private val callback: (Double) -> Unit = {}
-) : SimResourceConsumer by delegate {
- /**
- * The resource processing speed at this instant.
- */
- public var speed: Double = 0.0
- private set(value) {
- if (field != value) {
- callback(value)
- field = value
- }
- }
-
- init {
- callback(0.0)
- }
-
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- return delegate.onNext(ctx)
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- val oldSpeed = speed
-
- delegate.onEvent(ctx, event)
-
- when (event) {
- SimResourceEvent.Run -> speed = ctx.speed
- SimResourceEvent.Capacity -> {
- // Check if the consumer interrupted the consumer and updated the resource consumption. If not, we might
- // need to update the current speed.
- if (oldSpeed == speed) {
- speed = min(ctx.capacity, speed)
- }
- }
- SimResourceEvent.Exit -> speed = 0.0
- else -> {}
- }
- }
-
- override fun onFailure(ctx: SimResourceContext, cause: Throwable) {
- speed = 0.0
-
- delegate.onFailure(ctx, cause)
- }
-
- override fun toString(): String = "SimSpeedConsumerAdapter[delegate=$delegate]"
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimTraceConsumer.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimTraceConsumer.kt
deleted file mode 100644
index 2e94e1c1..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimTraceConsumer.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.resources.consumer
-
-import org.opendc.simulator.resources.SimResourceCommand
-import org.opendc.simulator.resources.SimResourceConsumer
-import org.opendc.simulator.resources.SimResourceContext
-import org.opendc.simulator.resources.SimResourceEvent
-
-/**
- * A [SimResourceConsumer] that replays a workload trace consisting of multiple fragments, each indicating the resource
- * consumption for some period of time.
- */
-public class SimTraceConsumer(private val trace: Sequence<Fragment>) : SimResourceConsumer {
- private var iterator: Iterator<Fragment>? = null
-
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- val iterator = checkNotNull(iterator)
- return if (iterator.hasNext()) {
- val now = ctx.clock.millis()
- val fragment = iterator.next()
- val work = (fragment.duration / 1000) * fragment.usage
- val deadline = now + fragment.duration
-
- assert(deadline >= now) { "Deadline already passed" }
-
- if (work > 0.0)
- SimResourceCommand.Consume(work, fragment.usage, deadline)
- else
- SimResourceCommand.Idle(deadline)
- } else {
- SimResourceCommand.Exit
- }
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> {
- check(iterator == null) { "Consumer already running" }
- iterator = trace.iterator()
- }
- SimResourceEvent.Exit -> {
- iterator = null
- }
- else -> {}
- }
- }
-
- /**
- * A fragment of the workload.
- */
- public data class Fragment(val duration: Long, val usage: Double)
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimWorkConsumer.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimWorkConsumer.kt
deleted file mode 100644
index faa693c4..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimWorkConsumer.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.resources.consumer
-
-import org.opendc.simulator.resources.SimResourceCommand
-import org.opendc.simulator.resources.SimResourceConsumer
-import org.opendc.simulator.resources.SimResourceContext
-
-/**
- * A [SimResourceConsumer] that consumes the specified amount of work at the specified utilization.
- */
-public class SimWorkConsumer(
- private val work: Double,
- private val utilization: Double
-) : SimResourceConsumer {
-
- init {
- require(work >= 0.0) { "Work must be positive" }
- require(utilization > 0.0 && utilization <= 1.0) { "Utilization must be in (0, 1]" }
- }
-
- private var isFirst = true
-
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- val limit = ctx.capacity * utilization
- val work = if (isFirst) {
- isFirst = false
- work
- } else {
- ctx.remainingWork
- }
- return if (work > 0.0) {
- SimResourceCommand.Consume(work, limit)
- } else {
- SimResourceCommand.Exit
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt
deleted file mode 100644
index b79998a3..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * 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.resources.impl
-
-import org.opendc.simulator.resources.*
-import java.time.Clock
-import kotlin.math.max
-import kotlin.math.min
-
-/**
- * Implementation of a [SimResourceContext] managing the communication between resources and resource consumers.
- */
-internal class SimResourceContextImpl(
- override val parent: SimResourceSystem?,
- private val interpreter: SimResourceInterpreterImpl,
- private val consumer: SimResourceConsumer,
- private val logic: SimResourceProviderLogic
-) : SimResourceControllableContext, SimResourceSystem {
- /**
- * The clock of the context.
- */
- override val clock: Clock
- get() = _clock
- private val _clock = interpreter.clock
-
- /**
- * The capacity of the resource.
- */
- override var capacity: Double = 0.0
- set(value) {
- val oldValue = field
-
- // Only changes will be propagated
- if (value != oldValue) {
- field = value
- onCapacityChange()
- }
- }
-
- /**
- * The amount of work still remaining at this instant.
- */
- override val remainingWork: Double
- get() = getRemainingWork(_clock.millis())
-
- /**
- * A flag to indicate the state of the context.
- */
- override val state: SimResourceState
- get() = _state
- private var _state = SimResourceState.Pending
-
- /**
- * The current processing speed of the resource.
- */
- override val speed: Double
- get() = _speed
- private var _speed = 0.0
-
- /**
- * The current resource processing demand.
- */
- override val demand: Double
- get() = _limit
-
- /**
- * The current state of the resource context.
- */
- private var _timestamp: Long = Long.MIN_VALUE
- private var _work: Double = 0.0
- private var _limit: Double = 0.0
- private var _deadline: Long = Long.MAX_VALUE
-
- /**
- * The update flag indicating why the update was triggered.
- */
- private var _flag: Int = 0
-
- /**
- * The current pending update.
- */
- private var _pendingUpdate: SimResourceInterpreterImpl.Update? = null
-
- override fun start() {
- check(_state == SimResourceState.Pending) { "Consumer is already started" }
- interpreter.batch {
- consumer.onEvent(this, SimResourceEvent.Start)
- _state = SimResourceState.Active
- interrupt()
- }
- }
-
- override fun close() {
- if (_state != SimResourceState.Stopped) {
- interpreter.batch {
- _state = SimResourceState.Stopped
- doStop()
- }
- }
- }
-
- override fun interrupt() {
- if (_state == SimResourceState.Stopped) {
- return
- }
-
- _flag = _flag or FLAG_INTERRUPT
- scheduleUpdate()
- }
-
- override fun invalidate() {
- if (_state == SimResourceState.Stopped) {
- return
- }
-
- _flag = _flag or FLAG_INVALIDATE
- scheduleUpdate()
- }
-
- override fun flush() {
- if (_state == SimResourceState.Stopped) {
- return
- }
-
- interpreter.scheduleSync(this)
- }
-
- /**
- * Determine whether the state of the resource context should be updated.
- */
- fun requiresUpdate(timestamp: Long): Boolean {
- // Either the resource context is flagged or there is a pending update at this timestamp
- return _flag != 0 || _pendingUpdate?.timestamp == timestamp
- }
-
- /**
- * Update the state of the resource context.
- */
- fun doUpdate(timestamp: Long) {
- try {
- val oldState = _state
- val newState = doUpdate(timestamp, oldState)
-
- _state = newState
- _flag = 0
-
- when (newState) {
- SimResourceState.Pending ->
- if (oldState != SimResourceState.Pending) {
- throw IllegalStateException("Illegal transition to pending state")
- }
- SimResourceState.Stopped ->
- if (oldState != SimResourceState.Stopped) {
- doStop()
- }
- else -> {}
- }
- } catch (cause: Throwable) {
- doFail(cause)
- } finally {
- _remainingWorkFlush = Long.MIN_VALUE
- _timestamp = timestamp
- }
- }
-
- override fun onConverge(timestamp: Long) {
- if (_state == SimResourceState.Active) {
- consumer.onEvent(this, SimResourceEvent.Run)
- }
- }
-
- override fun toString(): String = "SimResourceContextImpl[capacity=$capacity]"
-
- /**
- * Update the state of the resource context.
- */
- private fun doUpdate(timestamp: Long, state: SimResourceState): SimResourceState {
- return when (state) {
- // Resource context is not active, so its state will not update
- SimResourceState.Pending, SimResourceState.Stopped -> state
- SimResourceState.Active -> {
- val isInterrupted = _flag and FLAG_INTERRUPT != 0
- val remainingWork = getRemainingWork(timestamp)
- val isConsume = _limit > 0.0
- val reachedDeadline = _deadline <= timestamp
-
- // Update the resource counters only if there is some progress
- if (timestamp > _timestamp) {
- logic.onUpdate(this, _work, reachedDeadline)
- }
-
- // We should only continue processing the next command if:
- // 1. The resource consumption was finished.
- // 2. The resource capacity cannot satisfy the demand.
- // 3. The resource consumer should be interrupted (e.g., someone called .interrupt())
- if ((isConsume && remainingWork == 0.0) || reachedDeadline || isInterrupted) {
- when (val command = consumer.onNext(this)) {
- is SimResourceCommand.Idle -> interpretIdle(timestamp, command.deadline)
- is SimResourceCommand.Consume -> interpretConsume(timestamp, command.work, command.limit, command.deadline)
- is SimResourceCommand.Exit -> interpretExit()
- }
- } else if (isConsume) {
- interpretConsume(timestamp, remainingWork, _limit, _deadline)
- } else {
- interpretIdle(timestamp, _deadline)
- }
- }
- }
- }
-
- /**
- * Stop the resource context.
- */
- private fun doStop() {
- try {
- consumer.onEvent(this, SimResourceEvent.Exit)
- logic.onFinish(this)
- } catch (cause: Throwable) {
- doFail(cause)
- }
- }
-
- /**
- * Fail the resource consumer.
- */
- private fun doFail(cause: Throwable) {
- try {
- consumer.onFailure(this, cause)
- } catch (e: Throwable) {
- e.addSuppressed(cause)
- e.printStackTrace()
- }
-
- logic.onFinish(this)
- }
-
- /**
- * Interpret the [SimResourceCommand.Consume] command.
- */
- private fun interpretConsume(now: Long, work: Double, limit: Double, deadline: Long): SimResourceState {
- require(deadline >= now) { "Deadline already passed" }
-
- _speed = min(capacity, limit)
- _work = work
- _limit = limit
- _deadline = deadline
-
- val timestamp = logic.onConsume(this, work, limit, deadline)
- scheduleUpdate(timestamp)
-
- return SimResourceState.Active
- }
-
- /**
- * Interpret the [SimResourceCommand.Idle] command.
- */
- private fun interpretIdle(now: Long, deadline: Long): SimResourceState {
- require(deadline >= now) { "Deadline already passed" }
-
- _speed = 0.0
- _work = 0.0
- _limit = 0.0
- _deadline = deadline
-
- val timestamp = logic.onIdle(this, deadline)
- scheduleUpdate(timestamp)
-
- return SimResourceState.Active
- }
-
- /**
- * Interpret the [SimResourceCommand.Exit] command.
- */
- private fun interpretExit(): SimResourceState {
- _speed = 0.0
- _work = 0.0
- _limit = 0.0
- _deadline = Long.MAX_VALUE
-
- return SimResourceState.Stopped
- }
-
- private var _remainingWork: Double = 0.0
- private var _remainingWorkFlush: Long = Long.MIN_VALUE
-
- /**
- * Obtain the remaining work at the given timestamp.
- */
- private fun getRemainingWork(now: Long): Double {
- return if (_remainingWorkFlush < now) {
- _remainingWorkFlush = now
- computeRemainingWork(now).also { _remainingWork = it }
- } else {
- _remainingWork
- }
- }
-
- /**
- * Compute the remaining work based on the current state.
- */
- private fun computeRemainingWork(now: Long): Double {
- return if (_work > 0.0)
- max(0.0, _work - logic.getConsumedWork(this, _work, speed, now - _timestamp))
- else 0.0
- }
-
- /**
- * Indicate that the capacity of the resource has changed.
- */
- private fun onCapacityChange() {
- // Do not inform the consumer if it has not been started yet
- if (state != SimResourceState.Active) {
- return
- }
-
- val isThrottled = speed > capacity
-
- interpreter.batch {
- // Inform the consumer of the capacity change. This might already trigger an interrupt.
- consumer.onEvent(this, SimResourceEvent.Capacity)
-
- // Optimization: only invalidate context if the new capacity cannot satisfy the active resource command.
- if (isThrottled) {
- invalidate()
- }
- }
- }
-
- /**
- * Schedule an update for this resource context.
- */
- private fun scheduleUpdate() {
- // Cancel the pending update
- val pendingUpdate = _pendingUpdate
- if (pendingUpdate != null) {
- _pendingUpdate = null
- pendingUpdate.cancel()
- }
-
- interpreter.scheduleImmediate(this)
- }
-
- /**
- * Schedule a delayed update for this resource context.
- */
- private fun scheduleUpdate(timestamp: Long) {
- val pendingUpdate = _pendingUpdate
- if (pendingUpdate != null) {
- if (pendingUpdate.timestamp == timestamp) {
- // Fast-path: A pending update for the same timestamp already exists
- return
- } else {
- // Cancel the old pending update
- _pendingUpdate = null
- pendingUpdate.cancel()
- }
- }
-
- if (timestamp != Long.MAX_VALUE) {
- _pendingUpdate = interpreter.scheduleDelayed(this, timestamp)
- }
- }
-
- /**
- * A flag to indicate that the context should be invalidated.
- */
- private val FLAG_INVALIDATE = 0b01
-
- /**
- * A flag to indicate that the context should be interrupted.
- */
- private val FLAG_INTERRUPT = 0b10
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceCountersImpl.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceCountersImpl.kt
deleted file mode 100644
index 827019c5..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceCountersImpl.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.resources.impl
-
-import org.opendc.simulator.resources.SimResourceCounters
-
-/**
- * Mutable implementation of the [SimResourceCounters] interface.
- */
-internal class SimResourceCountersImpl : SimResourceCounters {
- override var demand: Double = 0.0
- override var actual: Double = 0.0
- override var overcommit: Double = 0.0
-
- override fun reset() {
- demand = 0.0
- actual = 0.0
- overcommit = 0.0
- }
-
- override fun toString(): String = "SimResourceCounters[demand=$demand,actual=$actual,overcommit=$overcommit]"
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceInterpreterImpl.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceInterpreterImpl.kt
deleted file mode 100644
index c3dcebd0..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceInterpreterImpl.kt
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * 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.resources.impl
-
-import kotlinx.coroutines.Delay
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.InternalCoroutinesApi
-import kotlinx.coroutines.Runnable
-import org.opendc.simulator.resources.*
-import java.time.Clock
-import java.util.*
-import kotlin.coroutines.ContinuationInterceptor
-import kotlin.coroutines.CoroutineContext
-
-/**
- * A [SimResourceInterpreter] queues all interrupts that occur during execution to be executed after.
- *
- * @param context The coroutine context to use.
- * @param clock The virtual simulation clock.
- */
-internal class SimResourceInterpreterImpl(private val context: CoroutineContext, override val clock: Clock) : SimResourceInterpreter {
- /**
- * The [Delay] instance that provides scheduled execution of [Runnable]s.
- */
- @OptIn(InternalCoroutinesApi::class)
- private val delay = requireNotNull(context[ContinuationInterceptor] as? Delay) { "Invalid CoroutineDispatcher: no delay implementation" }
-
- /**
- * The queue of resource updates that are scheduled for immediate execution.
- */
- private val queue = ArrayDeque<SimResourceContextImpl>()
-
- /**
- * A priority queue containing the resource updates to be scheduled in the future.
- */
- private val futureQueue = PriorityQueue<Update>(compareBy { it.timestamp })
-
- /**
- * The stack of interpreter invocations to occur in the future.
- */
- private val futureInvocations = ArrayDeque<Invocation>()
-
- /**
- * The systems that have been visited during the interpreter cycle.
- */
- private val visited = linkedSetOf<SimResourceSystem>()
-
- /**
- * The index in the batch stack.
- */
- private var batchIndex = 0
-
- /**
- * A flag to indicate that the interpreter is currently active.
- */
- private val isRunning: Boolean
- get() = batchIndex > 0
-
- /**
- * Enqueue the specified [ctx] to be updated immediately during the active interpreter cycle.
- *
- * This method should be used when the state of a resource context is invalidated/interrupted and needs to be
- * re-computed. In case no interpreter is currently active, the interpreter will be started.
- */
- fun scheduleImmediate(ctx: SimResourceContextImpl) {
- queue.add(ctx)
-
- // In-case the interpreter is already running in the call-stack, return immediately. The changes will be picked
- // up by the active interpreter.
- if (isRunning) {
- return
- }
-
- try {
- batchIndex++
- runInterpreter()
- } finally {
- batchIndex--
- }
- }
-
- /**
- * Update the specified [ctx] synchronously.
- */
- fun scheduleSync(ctx: SimResourceContextImpl) {
- ctx.doUpdate(clock.millis())
-
- if (visited.add(ctx)) {
- collectAncestors(ctx, visited)
- }
-
- // In-case the interpreter is already running in the call-stack, return immediately. The changes will be picked
- // up by the active interpreter.
- if (isRunning) {
- return
- }
-
- try {
- batchIndex++
- runInterpreter()
- } finally {
- batchIndex--
- }
- }
-
- /**
- * Schedule the interpreter to run at [timestamp] to update the resource contexts.
- *
- * This method will override earlier calls to this method for the same [ctx].
- *
- * @param ctx The resource context to which the event applies.
- * @param timestamp The timestamp when the interrupt should happen.
- */
- fun scheduleDelayed(ctx: SimResourceContextImpl, timestamp: Long): Update {
- val now = clock.millis()
- val futureQueue = futureQueue
-
- require(timestamp >= now) { "Timestamp must be in the future" }
-
- val update = allocUpdate(ctx, timestamp)
- futureQueue.add(update)
-
- // Optimization: Check if we need to push the interruption forward. Note that we check by timer reference.
- if (futureQueue.peek() === update) {
- trySchedule(futureQueue, futureInvocations)
- }
-
- return update
- }
-
- override fun newContext(
- consumer: SimResourceConsumer,
- provider: SimResourceProviderLogic,
- parent: SimResourceSystem?
- ): SimResourceControllableContext = SimResourceContextImpl(parent, this, consumer, provider)
-
- override fun pushBatch() {
- batchIndex++
- }
-
- override fun popBatch() {
- try {
- // Flush the work if the platform is not already running
- if (batchIndex == 1 && queue.isNotEmpty()) {
- runInterpreter()
- }
- } finally {
- batchIndex--
- }
- }
-
- /**
- * Interpret all actions that are scheduled for the current timestamp.
- */
- private fun runInterpreter() {
- val now = clock.millis()
- val queue = queue
- val futureQueue = futureQueue
- val futureInvocations = futureInvocations
- val visited = visited
-
- // Execute all scheduled updates at current timestamp
- while (true) {
- val update = futureQueue.peek() ?: break
-
- assert(update.timestamp >= now) { "Internal inconsistency: found update of the past" }
-
- if (update.timestamp > now && !update.isCancelled) {
- // Schedule a task for the next event to occur.
- trySchedule(futureQueue, futureInvocations)
- break
- }
-
- futureQueue.poll()
-
- val shouldExecute = !update.isCancelled && update.ctx.requiresUpdate(now)
- if (shouldExecute) {
- update.ctx.doUpdate(now)
-
- if (visited.add(update.ctx)) {
- collectAncestors(update.ctx, visited)
- }
- }
-
- updatePool.add(update)
- }
-
- // Repeat execution of all immediate updates until the system has converged to a steady-state
- // We have to take into account that the onConverge callback can also trigger new actions.
- do {
- // Execute all immediate updates
- while (true) {
- val ctx = queue.poll() ?: break
- val shouldExecute = ctx.requiresUpdate(now)
-
- if (shouldExecute) {
- ctx.doUpdate(now)
-
- if (visited.add(ctx)) {
- collectAncestors(ctx, visited)
- }
- }
- }
-
- for (system in visited) {
- system.onConverge(now)
- }
-
- visited.clear()
- } while (queue.isNotEmpty())
- }
-
- /**
- * Try to schedule the next interpreter event.
- */
- private fun trySchedule(queue: PriorityQueue<Update>, scheduled: ArrayDeque<Invocation>) {
- val nextTimer = queue.peek()
- val now = clock.millis()
-
- // Check whether we need to update our schedule:
- if (nextTimer == null) {
- // Case 1: all timers are cancelled
- for (invocation in scheduled) {
- invocation.cancel()
- }
- scheduled.clear()
- return
- }
-
- while (true) {
- val invocation = scheduled.peekFirst()
- if (invocation == null || invocation.timestamp > nextTimer.timestamp) {
- // Case 2: A new timer was registered ahead of the other timers.
- // Solution: Schedule a new scheduler invocation
- val nextTimestamp = nextTimer.timestamp
- @OptIn(InternalCoroutinesApi::class)
- val handle = delay.invokeOnTimeout(
- nextTimestamp - now,
- {
- try {
- batchIndex++
- runInterpreter()
- } finally {
- batchIndex--
- }
- },
- context
- )
- scheduled.addFirst(Invocation(nextTimestamp, handle))
- break
- } else if (invocation.timestamp < nextTimer.timestamp) {
- // Case 2: A timer was cancelled and the head of the timer queue is now later than excepted
- // Solution: Cancel the next scheduler invocation
- invocation.cancel()
- scheduled.pollFirst()
- } else {
- break
- }
- }
- }
-
- /**
- * Collect all the ancestors of the specified [system].
- */
- private tailrec fun collectAncestors(system: SimResourceSystem, systems: MutableSet<SimResourceSystem>) {
- val parent = system.parent
- if (parent != null) {
- systems.add(parent)
- collectAncestors(parent, systems)
- }
- }
-
- /**
- * The pool of existing updates.
- */
- private val updatePool = ArrayDeque<Update>()
-
- /**
- * Allocate an [Update] object.
- */
- private fun allocUpdate(ctx: SimResourceContextImpl, timestamp: Long): Update {
- val update = updatePool.poll()
- return if (update != null) {
- update.ctx = ctx
- update.timestamp = timestamp
- update.isCancelled = false
- update
- } else {
- Update(ctx, timestamp)
- }
- }
-
- /**
- * A future interpreter invocation.
- *
- * This class is used to keep track of the future scheduler invocations created using the [Delay] instance. In case
- * the invocation is not needed anymore, it can be cancelled via [cancel].
- */
- private data class Invocation(
- @JvmField val timestamp: Long,
- private val disposableHandle: DisposableHandle
- ) {
- /**
- * Cancel the interpreter invocation.
- */
- fun cancel() = disposableHandle.dispose()
- }
-
- /**
- * An update call for [ctx] that is scheduled for [timestamp].
- *
- * This class represents an update in the future at [timestamp] requested by [ctx]. A deferred update might be
- * cancelled if the resource context was invalidated in the meantime.
- */
- class Update(@JvmField var ctx: SimResourceContextImpl, @JvmField var timestamp: Long) {
- /**
- * A flag to indicate that the task has been cancelled.
- */
- @JvmField
- var isCancelled: Boolean = false
-
- /**
- * Cancel the update.
- */
- fun cancel() {
- isCancelled = true
- }
-
- override fun toString(): String = "Update[ctx=$ctx,timestamp=$timestamp]"
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceDomain.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceDomain.kt
deleted file mode 100644
index 1066777f..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceDomain.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.opendc.simulator.resources.interference
-
-import org.opendc.simulator.resources.SimResourceConsumer
-
-/**
- * An interference domain represents a system of resources where [resource consumers][SimResourceConsumer] may incur
- * performance variability due to operating on the same resources and therefore causing interference.
- */
-public interface InterferenceDomain {
- /**
- * Compute the performance score of a participant in this interference domain.
- *
- * @param key The participant to obtain the score of or `null` if the participant has no key.
- * @param load The overall load on the interference domain.
- * @return A score representing the performance score to be applied to the resource consumer, with 1
- * meaning no influence, <1 means that performance degrades, and >1 means that performance improves.
- */
- public fun apply(key: InterferenceKey?, load: Double): Double
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceKey.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceKey.kt
deleted file mode 100644
index 8b12e7b4..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/interference/InterferenceKey.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.resources.interference
-
-/**
- * A key that uniquely identifies a participant of an interference domain.
- */
-public interface InterferenceKey
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMinTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMinTest.kt
deleted file mode 100644
index 2f01a8c4..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMinTest.kt
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.resources
-
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.verify
-import kotlinx.coroutines.*
-import org.junit.jupiter.api.Assertions.*
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertAll
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.consumer.SimSpeedConsumerAdapter
-import org.opendc.simulator.resources.consumer.SimWorkConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * Test suite for the [SimResourceAggregatorMaxMin] class.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimResourceAggregatorMaxMinTest {
- @Test
- fun testSingleCapacity() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val aggregator = SimResourceAggregatorMaxMin(scheduler)
- val forwarder = SimResourceForwarder()
- val sources = listOf(
- forwarder,
- SimResourceSource(1.0, scheduler)
- )
- sources.forEach(aggregator::addInput)
-
- val consumer = SimWorkConsumer(1.0, 0.5)
- val usage = mutableListOf<Double>()
- val source = SimResourceSource(1.0, scheduler)
- val adapter = SimSpeedConsumerAdapter(forwarder, usage::add)
- source.startConsumer(adapter)
-
- aggregator.consume(consumer)
- yield()
-
- assertAll(
- { assertEquals(1000, clock.millis()) },
- { assertEquals(listOf(0.0, 0.5, 0.0), usage) }
- )
- }
-
- @Test
- fun testDoubleCapacity() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val aggregator = SimResourceAggregatorMaxMin(scheduler)
- val sources = listOf(
- SimResourceSource(1.0, scheduler),
- SimResourceSource(1.0, scheduler)
- )
- sources.forEach(aggregator::addInput)
-
- val consumer = SimWorkConsumer(2.0, 1.0)
- val usage = mutableListOf<Double>()
- val adapter = SimSpeedConsumerAdapter(consumer, usage::add)
-
- aggregator.consume(adapter)
- yield()
- assertAll(
- { assertEquals(1000, clock.millis()) },
- { assertEquals(listOf(0.0, 2.0, 0.0), usage) }
- )
- }
-
- @Test
- fun testOvercommit() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val aggregator = SimResourceAggregatorMaxMin(scheduler)
- val sources = listOf(
- SimResourceSource(1.0, scheduler),
- SimResourceSource(1.0, scheduler)
- )
- sources.forEach(aggregator::addInput)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(4.0, 4.0, 1000))
- .andThen(SimResourceCommand.Exit)
-
- aggregator.consume(consumer)
- yield()
- assertEquals(1000, clock.millis())
-
- verify(exactly = 2) { consumer.onNext(any()) }
- }
-
- @Test
- fun testException() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val aggregator = SimResourceAggregatorMaxMin(scheduler)
- val sources = listOf(
- SimResourceSource(1.0, scheduler),
- SimResourceSource(1.0, scheduler)
- )
- sources.forEach(aggregator::addInput)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(1.0, 1.0))
- .andThenThrows(IllegalStateException("Test Exception"))
-
- assertThrows<IllegalStateException> { aggregator.consume(consumer) }
- yield()
- assertFalse(sources[0].isActive)
- }
-
- @Test
- fun testAdjustCapacity() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val aggregator = SimResourceAggregatorMaxMin(scheduler)
- val sources = listOf(
- SimResourceSource(1.0, scheduler),
- SimResourceSource(1.0, scheduler)
- )
- sources.forEach(aggregator::addInput)
-
- val consumer = SimWorkConsumer(4.0, 1.0)
- coroutineScope {
- launch { aggregator.consume(consumer) }
- delay(1000)
- sources[0].capacity = 0.5
- }
- yield()
- assertEquals(2334, clock.millis())
- }
-
- @Test
- fun testFailOverCapacity() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val aggregator = SimResourceAggregatorMaxMin(scheduler)
- val sources = listOf(
- SimResourceSource(1.0, scheduler),
- SimResourceSource(1.0, scheduler)
- )
- sources.forEach(aggregator::addInput)
-
- val consumer = SimWorkConsumer(1.0, 0.5)
- coroutineScope {
- launch { aggregator.consume(consumer) }
- delay(500)
- sources[0].capacity = 0.5
- }
- yield()
- assertEquals(1000, clock.millis())
- }
-
- @Test
- fun testCounters() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val aggregator = SimResourceAggregatorMaxMin(scheduler)
- val sources = listOf(
- SimResourceSource(1.0, scheduler),
- SimResourceSource(1.0, scheduler)
- )
- sources.forEach(aggregator::addInput)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(4.0, 4.0, 1000))
- .andThen(SimResourceCommand.Exit)
-
- aggregator.consume(consumer)
- yield()
- assertEquals(1000, clock.millis())
- assertEquals(2.0, aggregator.counters.actual) { "Actual work mismatch" }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceCommandTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceCommandTest.kt
deleted file mode 100644
index 02d456ff..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceCommandTest.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.resources
-
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertDoesNotThrow
-import org.junit.jupiter.api.assertThrows
-
-/**
- * Test suite for [SimResourceCommand].
- */
-class SimResourceCommandTest {
- @Test
- fun testZeroWork() {
- assertThrows<IllegalArgumentException> {
- SimResourceCommand.Consume(0.0, 1.0)
- }
- }
-
- @Test
- fun testNegativeWork() {
- assertThrows<IllegalArgumentException> {
- SimResourceCommand.Consume(-1.0, 1.0)
- }
- }
-
- @Test
- fun testZeroLimit() {
- assertThrows<IllegalArgumentException> {
- SimResourceCommand.Consume(1.0, 0.0)
- }
- }
-
- @Test
- fun testNegativeLimit() {
- assertThrows<IllegalArgumentException> {
- SimResourceCommand.Consume(1.0, -1.0, 1)
- }
- }
-
- @Test
- fun testConsumeCorrect() {
- assertDoesNotThrow {
- SimResourceCommand.Consume(1.0, 1.0)
- }
- }
-
- @Test
- fun testIdleCorrect() {
- assertDoesNotThrow {
- SimResourceCommand.Idle(1)
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceContextTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceContextTest.kt
deleted file mode 100644
index 6cb507ce..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceContextTest.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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.resources
-
-import io.mockk.*
-import kotlinx.coroutines.*
-import org.junit.jupiter.api.*
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.impl.SimResourceContextImpl
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * A test suite for the [SimResourceContextImpl] class.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-class SimResourceContextTest {
- @Test
- fun testFlushWithoutCommand() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Consume(10.0, 1.0) andThen SimResourceCommand.Exit
-
- val logic = object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long = deadline
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long = deadline
- override fun onFinish(ctx: SimResourceControllableContext) {}
- }
- val context = SimResourceContextImpl(null, interpreter, consumer, logic)
-
- context.doUpdate(interpreter.clock.millis())
- }
-
- @Test
- fun testIntermediateFlush() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Consume(10.0, 1.0) andThen SimResourceCommand.Exit
-
- val logic = spyk(object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long = deadline
- override fun onFinish(ctx: SimResourceControllableContext) {}
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long = deadline
- })
- val context = spyk(SimResourceContextImpl(null, interpreter, consumer, logic))
-
- context.start()
- delay(1) // Delay 1 ms to prevent hitting the fast path
- context.doUpdate(interpreter.clock.millis())
-
- verify(exactly = 2) { logic.onConsume(any(), any(), any(), any()) }
- }
-
- @Test
- fun testIntermediateFlushIdle() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Idle(10) andThen SimResourceCommand.Exit
-
- val logic = spyk(object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long = deadline
- override fun onFinish(ctx: SimResourceControllableContext) {}
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long = deadline
- })
- val context = spyk(SimResourceContextImpl(null, interpreter, consumer, logic))
-
- context.start()
- delay(5)
- context.invalidate()
- delay(5)
- context.invalidate()
-
- assertAll(
- { verify(exactly = 2) { logic.onIdle(any(), any()) } },
- { verify(exactly = 1) { logic.onFinish(any()) } }
- )
- }
-
- @Test
- fun testDoubleStart() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Idle(10) andThen SimResourceCommand.Exit
-
- val logic = object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long = deadline
- override fun onFinish(ctx: SimResourceControllableContext) {}
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long = deadline
- }
- val context = SimResourceContextImpl(null, interpreter, consumer, logic)
-
- context.start()
-
- assertThrows<IllegalStateException> {
- context.start()
- }
- }
-
- @Test
- fun testIdempodentCapacityChange() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Consume(10.0, 1.0) andThen SimResourceCommand.Exit
-
- val logic = object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long = deadline
- override fun onFinish(ctx: SimResourceControllableContext) {}
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long = deadline
- }
-
- val context = SimResourceContextImpl(null, interpreter, consumer, logic)
- context.capacity = 4200.0
- context.start()
- context.capacity = 4200.0
-
- verify(exactly = 0) { consumer.onEvent(any(), SimResourceEvent.Capacity) }
- }
-
- @Test
- fun testFailureNoInfiniteLoop() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Exit
- every { consumer.onEvent(any(), SimResourceEvent.Exit) } throws IllegalStateException("onEvent")
- every { consumer.onFailure(any(), any()) } throws IllegalStateException("onFailure")
-
- val logic = spyk(object : SimResourceProviderLogic {
- override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long = deadline
- override fun onFinish(ctx: SimResourceControllableContext) {}
- override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long = deadline
- })
-
- val context = SimResourceContextImpl(null, interpreter, consumer, logic)
-
- context.start()
-
- delay(1)
-
- verify(exactly = 1) { consumer.onFailure(any(), any()) }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSourceTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSourceTest.kt
deleted file mode 100644
index 4895544d..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSourceTest.kt
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * 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.resources
-
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.spyk
-import io.mockk.verify
-import kotlinx.coroutines.*
-import org.junit.jupiter.api.*
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.consumer.SimSpeedConsumerAdapter
-import org.opendc.simulator.resources.consumer.SimWorkConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * A test suite for the [SimResourceSource] class.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-class SimResourceSourceTest {
- @Test
- fun testSpeed() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(1000 * capacity, capacity))
- .andThen(SimResourceCommand.Exit)
-
- val res = mutableListOf<Double>()
- val adapter = SimSpeedConsumerAdapter(consumer, res::add)
-
- provider.consume(adapter)
-
- assertEquals(listOf(0.0, capacity, 0.0), res) { "Speed is reported correctly" }
- }
-
- @Test
- fun testAdjustCapacity() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val provider = SimResourceSource(1.0, scheduler)
-
- val consumer = spyk(SimWorkConsumer(2.0, 1.0))
-
- coroutineScope {
- launch { provider.consume(consumer) }
- delay(1000)
- provider.capacity = 0.5
- }
- assertEquals(3000, clock.millis())
- verify(exactly = 1) { consumer.onEvent(any(), SimResourceEvent.Capacity) }
- }
-
- @Test
- fun testSpeedLimit() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(1000 * capacity, 2 * capacity))
- .andThen(SimResourceCommand.Exit)
-
- val res = mutableListOf<Double>()
- val adapter = SimSpeedConsumerAdapter(consumer, res::add)
-
- provider.consume(adapter)
-
- assertEquals(listOf(0.0, capacity, 0.0), res) { "Speed is reported correctly" }
- }
-
- /**
- * Test to see whether no infinite recursion occurs when interrupting during [SimResourceConsumer.onStart] or
- * [SimResourceConsumer.onNext].
- */
- @Test
- fun testIntermediateInterrupt() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- return SimResourceCommand.Exit
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- ctx.interrupt()
- }
- }
-
- provider.consume(consumer)
- }
-
- @Test
- fun testInterrupt() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
- lateinit var resCtx: SimResourceContext
-
- val consumer = object : SimResourceConsumer {
- var isFirst = true
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> resCtx = ctx
- else -> {}
- }
- }
-
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- assertEquals(0.0, ctx.remainingWork)
- return if (isFirst) {
- isFirst = false
- SimResourceCommand.Consume(4.0, 1.0)
- } else {
- SimResourceCommand.Exit
- }
- }
- }
-
- launch {
- yield()
- resCtx.interrupt()
- }
- provider.consume(consumer)
-
- assertEquals(0, clock.millis())
- }
-
- @Test
- fun testFailure() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onEvent(any(), eq(SimResourceEvent.Start)) }
- .throws(IllegalStateException())
-
- assertThrows<IllegalStateException> {
- provider.consume(consumer)
- }
- }
-
- @Test
- fun testExceptionPropagationOnNext() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(1.0, 1.0))
- .andThenThrows(IllegalStateException())
-
- assertThrows<IllegalStateException> {
- provider.consume(consumer)
- }
- }
-
- @Test
- fun testConcurrentConsumption() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(1.0, 1.0))
- .andThenThrows(IllegalStateException())
-
- assertThrows<IllegalStateException> {
- coroutineScope {
- launch { provider.consume(consumer) }
- provider.consume(consumer)
- }
- }
- }
-
- @Test
- fun testCancelDuringConsumption() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Consume(1.0, 1.0))
- .andThenThrows(IllegalStateException())
-
- launch { provider.consume(consumer) }
- delay(500)
- provider.cancel()
-
- assertEquals(500, clock.millis())
- }
-
- @Test
- fun testIdle() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Idle(clock.millis() + 500))
- .andThen(SimResourceCommand.Exit)
-
- provider.consume(consumer)
-
- assertEquals(500, clock.millis())
- }
-
- @Test
- fun testInfiniteSleep() {
- assertThrows<IllegalStateException> {
- runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Idle())
- .andThenThrows(IllegalStateException())
-
- provider.consume(consumer)
- }
- }
- }
-
- @Test
- fun testIncorrectDeadline() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) }
- .returns(SimResourceCommand.Idle(2))
- .andThen(SimResourceCommand.Exit)
-
- delay(10)
-
- assertThrows<IllegalArgumentException> { provider.consume(consumer) }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusiveTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusiveTest.kt
deleted file mode 100644
index ad8d82e3..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusiveTest.kt
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.resources
-
-import io.mockk.every
-import io.mockk.mockk
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertAll
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.consumer.SimSpeedConsumerAdapter
-import org.opendc.simulator.resources.consumer.SimTraceConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * Test suite for the [SimResourceSwitchExclusive] class.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimResourceSwitchExclusiveTest {
- /**
- * Test a trace workload.
- */
- @Test
- fun testTrace() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val speed = mutableListOf<Double>()
-
- val duration = 5 * 60L
- val workload =
- SimTraceConsumer(
- sequenceOf(
- SimTraceConsumer.Fragment(duration * 1000, 28.0),
- SimTraceConsumer.Fragment(duration * 1000, 3500.0),
- SimTraceConsumer.Fragment(duration * 1000, 0.0),
- SimTraceConsumer.Fragment(duration * 1000, 183.0)
- ),
- )
-
- val switch = SimResourceSwitchExclusive()
- val source = SimResourceSource(3200.0, scheduler)
- val forwarder = SimResourceForwarder()
- val adapter = SimSpeedConsumerAdapter(forwarder, speed::add)
- source.startConsumer(adapter)
- switch.addInput(forwarder)
-
- val provider = switch.newOutput()
-
- try {
- provider.consume(workload)
- yield()
- } finally {
- provider.close()
- }
-
- assertAll(
- { assertEquals(listOf(0.0, 28.0, 3200.0, 0.0, 183.0, 0.0), speed) { "Correct speed" } },
- { assertEquals(5 * 60L * 4000, clock.millis()) { "Took enough time" } }
- )
- }
-
- /**
- * Test runtime workload on hypervisor.
- */
- @Test
- fun testRuntimeWorkload() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val duration = 5 * 60L * 1000
- val workload = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { workload.onNext(any()) } returns SimResourceCommand.Consume(duration / 1000.0, 1.0) andThen SimResourceCommand.Exit
-
- val switch = SimResourceSwitchExclusive()
- val source = SimResourceSource(3200.0, scheduler)
-
- switch.addInput(source)
-
- val provider = switch.newOutput()
-
- try {
- provider.consume(workload)
- yield()
- } finally {
- provider.close()
- }
- assertEquals(duration, clock.millis()) { "Took enough time" }
- }
-
- /**
- * Test two workloads running sequentially.
- */
- @Test
- fun testTwoWorkloads() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val duration = 5 * 60L * 1000
- val workload = object : SimResourceConsumer {
- var isFirst = true
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> isFirst = true
- else -> {}
- }
- }
-
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- return if (isFirst) {
- isFirst = false
- SimResourceCommand.Consume(duration / 1000.0, 1.0)
- } else {
- SimResourceCommand.Exit
- }
- }
- }
-
- val switch = SimResourceSwitchExclusive()
- val source = SimResourceSource(3200.0, scheduler)
-
- switch.addInput(source)
-
- val provider = switch.newOutput()
-
- try {
- provider.consume(workload)
- yield()
- provider.consume(workload)
- } finally {
- provider.close()
- }
- assertEquals(duration * 2, clock.millis()) { "Took enough time" }
- }
-
- /**
- * Test concurrent workloads on the machine.
- */
- @Test
- fun testConcurrentWorkloadFails() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val duration = 5 * 60L * 1000
- val workload = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { workload.onNext(any()) } returns SimResourceCommand.Consume(duration / 1000.0, 1.0) andThen SimResourceCommand.Exit
-
- val switch = SimResourceSwitchExclusive()
- val source = SimResourceSource(3200.0, scheduler)
-
- switch.addInput(source)
-
- switch.newOutput()
- assertThrows<IllegalStateException> { switch.newOutput() }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMinTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMinTest.kt
deleted file mode 100644
index e4292ec0..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMinTest.kt
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.resources
-
-import io.mockk.every
-import io.mockk.mockk
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.*
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.consumer.SimTraceConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * Test suite for the [SimResourceSwitch] implementations
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimResourceSwitchMaxMinTest {
- @Test
- fun testSmoke() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val switch = SimResourceSwitchMaxMin(scheduler)
-
- val sources = List(2) { SimResourceSource(2000.0, scheduler) }
- sources.forEach { switch.addInput(it) }
-
- val provider = switch.newOutput()
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Consume(1.0, 1.0) andThen SimResourceCommand.Exit
-
- try {
- provider.consume(consumer)
- yield()
- } finally {
- switch.close()
- }
- }
-
- /**
- * Test overcommitting of resources via the hypervisor with a single VM.
- */
- @Test
- fun testOvercommittedSingle() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val duration = 5 * 60L
- val workload =
- SimTraceConsumer(
- sequenceOf(
- SimTraceConsumer.Fragment(duration * 1000, 28.0),
- SimTraceConsumer.Fragment(duration * 1000, 3500.0),
- SimTraceConsumer.Fragment(duration * 1000, 0.0),
- SimTraceConsumer.Fragment(duration * 1000, 183.0)
- ),
- )
-
- val switch = SimResourceSwitchMaxMin(scheduler)
- val provider = switch.newOutput()
-
- try {
- switch.addInput(SimResourceSource(3200.0, scheduler))
- provider.consume(workload)
- yield()
- } finally {
- switch.close()
- }
-
- assertAll(
- { assertEquals(1113300.0, switch.counters.demand, "Requested work does not match") },
- { assertEquals(1023300.0, switch.counters.actual, "Actual work does not match") },
- { assertEquals(90000.0, switch.counters.overcommit, "Overcommitted work does not match") },
- { assertEquals(1200000, clock.millis()) }
- )
- }
-
- /**
- * Test overcommitting of resources via the hypervisor with two VMs.
- */
- @Test
- fun testOvercommittedDual() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- val duration = 5 * 60L
- val workloadA =
- SimTraceConsumer(
- sequenceOf(
- SimTraceConsumer.Fragment(duration * 1000, 28.0),
- SimTraceConsumer.Fragment(duration * 1000, 3500.0),
- SimTraceConsumer.Fragment(duration * 1000, 0.0),
- SimTraceConsumer.Fragment(duration * 1000, 183.0)
- ),
- )
- val workloadB =
- SimTraceConsumer(
- sequenceOf(
- SimTraceConsumer.Fragment(duration * 1000, 28.0),
- SimTraceConsumer.Fragment(duration * 1000, 3100.0),
- SimTraceConsumer.Fragment(duration * 1000, 0.0),
- SimTraceConsumer.Fragment(duration * 1000, 73.0)
- )
- )
-
- val switch = SimResourceSwitchMaxMin(scheduler)
- val providerA = switch.newOutput()
- val providerB = switch.newOutput()
-
- try {
- switch.addInput(SimResourceSource(3200.0, scheduler))
-
- coroutineScope {
- launch { providerA.consume(workloadA) }
- providerB.consume(workloadB)
- }
-
- yield()
- } finally {
- switch.close()
- }
- assertAll(
- { assertEquals(2073600.0, switch.counters.demand, "Requested work does not match") },
- { assertEquals(1053600.0, switch.counters.actual, "Granted work does not match") },
- { assertEquals(1020000.0, switch.counters.overcommit, "Overcommitted work does not match") },
- { assertEquals(1200000, clock.millis()) }
- )
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceTransformerTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceTransformerTest.kt
deleted file mode 100644
index cf69b7b5..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceTransformerTest.kt
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * 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.resources
-
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.spyk
-import io.mockk.verify
-import kotlinx.coroutines.*
-import org.junit.jupiter.api.Assertions.*
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.consumer.SimWorkConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * A test suite for the [SimResourceTransformer] class.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimResourceTransformerTest {
- @Test
- fun testCancelImmediately() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(2000.0, scheduler)
-
- launch { source.consume(forwarder) }
-
- forwarder.consume(object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- return SimResourceCommand.Exit
- }
- })
-
- forwarder.close()
- source.cancel()
- }
-
- @Test
- fun testCancel() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(2000.0, scheduler)
-
- launch { source.consume(forwarder) }
-
- forwarder.consume(object : SimResourceConsumer {
- var isFirst = true
-
- override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- return if (isFirst) {
- isFirst = false
- SimResourceCommand.Consume(10.0, 1.0)
- } else {
- SimResourceCommand.Exit
- }
- }
- })
-
- forwarder.close()
- source.cancel()
- }
-
- @Test
- fun testState() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val consumer = object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext): SimResourceCommand = SimResourceCommand.Exit
- }
-
- assertFalse(forwarder.isActive)
-
- forwarder.startConsumer(consumer)
- assertTrue(forwarder.isActive)
-
- assertThrows<IllegalStateException> { forwarder.startConsumer(consumer) }
-
- forwarder.cancel()
- assertFalse(forwarder.isActive)
-
- forwarder.close()
- assertFalse(forwarder.isActive)
- }
-
- @Test
- fun testCancelPendingDelegate() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Exit
-
- forwarder.startConsumer(consumer)
- forwarder.cancel()
-
- verify(exactly = 0) { consumer.onEvent(any(), SimResourceEvent.Exit) }
- }
-
- @Test
- fun testCancelStartedDelegate() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(2000.0, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Idle(10)
-
- source.startConsumer(forwarder)
- yield()
- forwarder.startConsumer(consumer)
- yield()
- forwarder.cancel()
-
- verify(exactly = 1) { consumer.onEvent(any(), SimResourceEvent.Start) }
- verify(exactly = 1) { consumer.onEvent(any(), SimResourceEvent.Exit) }
- }
-
- @Test
- fun testCancelPropagation() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(2000.0, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Idle(10)
-
- source.startConsumer(forwarder)
- yield()
- forwarder.startConsumer(consumer)
- yield()
- source.cancel()
-
- verify(exactly = 1) { consumer.onEvent(any(), SimResourceEvent.Start) }
- verify(exactly = 1) { consumer.onEvent(any(), SimResourceEvent.Exit) }
- }
-
- @Test
- fun testExitPropagation() = runBlockingSimulation {
- val forwarder = SimResourceForwarder(isCoupled = true)
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(2000.0, scheduler)
-
- val consumer = mockk<SimResourceConsumer>(relaxUnitFun = true)
- every { consumer.onNext(any()) } returns SimResourceCommand.Exit
-
- source.startConsumer(forwarder)
- forwarder.consume(consumer)
- yield()
-
- assertFalse(forwarder.isActive)
- }
-
- @Test
- fun testAdjustCapacity() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(1.0, scheduler)
-
- val consumer = spyk(SimWorkConsumer(2.0, 1.0))
- source.startConsumer(forwarder)
-
- coroutineScope {
- launch { forwarder.consume(consumer) }
- delay(1000)
- source.capacity = 0.5
- }
-
- assertEquals(3000, clock.millis())
- verify(exactly = 1) { consumer.onEvent(any(), SimResourceEvent.Capacity) }
- }
-
- @Test
- fun testTransformExit() = runBlockingSimulation {
- val forwarder = SimResourceTransformer { _, _ -> SimResourceCommand.Exit }
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(1.0, scheduler)
-
- val consumer = spyk(SimWorkConsumer(2.0, 1.0))
- source.startConsumer(forwarder)
- forwarder.consume(consumer)
-
- assertEquals(0, clock.millis())
- verify(exactly = 1) { consumer.onNext(any()) }
- }
-
- @Test
- fun testCounters() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val source = SimResourceSource(1.0, scheduler)
-
- val consumer = SimWorkConsumer(2.0, 1.0)
- source.startConsumer(forwarder)
-
- forwarder.consume(consumer)
-
- assertEquals(source.counters.actual, forwarder.counters.actual) { "Actual work" }
- assertEquals(source.counters.demand, forwarder.counters.demand) { "Work demand" }
- assertEquals(source.counters.overcommit, forwarder.counters.overcommit) { "Overcommitted work" }
- assertEquals(2000, clock.millis())
- }
-}
diff --git a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimWorkConsumerTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimWorkConsumerTest.kt
deleted file mode 100644
index 42648cf1..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimWorkConsumerTest.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.resources
-
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.opendc.simulator.core.runBlockingSimulation
-import org.opendc.simulator.resources.consumer.SimWorkConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * A test suite for the [SimWorkConsumer] class.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimWorkConsumerTest {
- @Test
- fun testSmoke() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val provider = SimResourceSource(1.0, scheduler)
-
- val consumer = SimWorkConsumer(1.0, 1.0)
-
- provider.consume(consumer)
- assertEquals(1000, clock.millis())
- }
-
- @Test
- fun testUtilization() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val provider = SimResourceSource(1.0, scheduler)
-
- val consumer = SimWorkConsumer(1.0, 0.5)
-
- provider.consume(consumer)
- assertEquals(2000, clock.millis())
- }
-}