summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-resources/src
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-simulator/opendc-simulator-resources/src')
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/jmh/kotlin/org/opendc/simulator/resources/SimResourceBenchmarks.kt138
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceProvider.kt146
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceConsumer.kt57
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceContext.kt68
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceControllableContext.kt54
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCounters.kt53
-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/SimResourceForwarder.kt220
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceInterpreter.kt94
-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.kt58
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSource.kt61
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitch.kt67
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusive.kt129
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMin.kt407
-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/consumer/SimConsumerBarrier.kt52
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimSpeedConsumerAdapter.kt82
-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.kt61
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt367
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceCountersImpl.kt46
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceInterpreterImpl.kt298
-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/SimResourceContextTest.kt173
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceForwarderTest.kt220
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSourceTest.kt240
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusiveTest.kt156
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMinTest.kt145
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimWorkConsumerTest.kt56
31 files changed, 0 insertions, 3765 deletions
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 fbc3f319..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/jmh/kotlin/org/opendc/simulator/resources/SimResourceBenchmarks.kt
+++ /dev/null
@@ -1,138 +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.ThreadLocalRandom
-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() {
- val random = ThreadLocalRandom.current()
- val entries = List(10000) { SimTraceConsumer.Fragment(1000, random.nextDouble(0.0, 4500.0)) }
- trace = entries.asSequence()
- }
- }
-
- @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/SimAbstractResourceProvider.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceProvider.kt
deleted file mode 100644
index 085cba63..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimAbstractResourceProvider.kt
+++ /dev/null
@@ -1,146 +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,
- 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()
- }
-
- /**
- * The previous demand for the resource.
- */
- private var previousDemand = 0.0
-
- /**
- * Update the counters of the resource provider.
- */
- protected fun updateCounters(ctx: SimResourceContext, delta: Long) {
- val demand = previousDemand
- previousDemand = ctx.demand
-
- if (delta <= 0) {
- return
- }
-
- val counters = _counters
- val deltaS = delta / 1000.0
- val work = demand * deltaS
- val actualWork = ctx.speed * deltaS
- val remainingWork = work - actualWork
-
- counters.demand += work
- counters.actual += actualWork
- counters.overcommit += remainingWork
- }
-
- /**
- * Update the counters of the resource provider.
- */
- protected fun updateCounters(demand: Double, actual: Double, overcommit: Double) {
- val counters = _counters
- counters.demand += demand
- counters.actual += actual
- counters.overcommit += overcommit
- }
-
- final override fun startConsumer(consumer: SimResourceConsumer) {
- check(ctx == null) { "Resource is in invalid state" }
- val ctx = interpreter.newContext(consumer, createLogic())
-
- 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/SimResourceConsumer.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceConsumer.kt
deleted file mode 100644
index 0b25358a..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceConsumer.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
-
-/**
- * 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 the resource provider is pulling this resource consumer.
- *
- * @param ctx The execution context in which the consumer runs.
- * @param now The virtual timestamp in milliseconds at which the update is occurring.
- * @param delta The virtual duration between this call and the last call in milliseconds.
- * @return The duration after which the resource consumer should be pulled again.
- */
- public fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long
-
- /**
- * 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 225cae0b..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceContext.kt
+++ /dev/null
@@ -1,68 +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 : AutoCloseable {
- /**
- * 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
-
- /**
- * Ask the resource provider to interrupt its resource.
- */
- public fun interrupt()
-
- /**
- * Push the given flow to this context.
- *
- * @param rate The rate of the flow to push.
- */
- public fun push(rate: Double)
-
- /**
- * Stop the resource context.
- */
- public override fun close()
-}
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 b406b896..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceControllableContext.kt
+++ /dev/null
@@ -1,54 +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 {
- /**
- * The capacity of the resource.
- */
- public override var capacity: Double
-
- /**
- * Start the resource context.
- */
- public fun start()
-
- /**
- * 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 11924db2..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceCounters.kt
+++ /dev/null
@@ -1,53 +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
-
- /**
- * The amount of work lost due to interference.
- */
- public val interference: Double
-
- /**
- * Reset the resource counters.
- */
- public fun reset()
-}
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/SimResourceForwarder.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceForwarder.kt
deleted file mode 100644
index 0cd2bfc7..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceForwarder.kt
+++ /dev/null
@@ -1,220 +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
-import java.time.Clock
-
-/**
- * A class that acts as a [SimResourceConsumer] and [SimResourceProvider] at the same time.
- *
- * @param isCoupled A flag to indicate that the transformer will exit when the resource consumer exits.
- */
-public class SimResourceForwarder(private val isCoupled: Boolean = false) : SimResourceConsumer, SimResourceProvider, AutoCloseable {
- /**
- * The delegate [SimResourceConsumer].
- */
- private var delegate: SimResourceConsumer? = null
-
- /**
- * A flag to indicate that the delegate was started.
- */
- private var hasDelegateStarted: Boolean = false
-
- /**
- * The exposed [SimResourceContext].
- */
- private val _ctx = object : SimResourceContext {
- override val clock: Clock
- get() = _innerCtx!!.clock
-
- override val capacity: Double
- get() = _innerCtx?.capacity ?: 0.0
-
- override val demand: Double
- get() = _innerCtx?.demand ?: 0.0
-
- override val speed: Double
- get() = _innerCtx?.speed ?: 0.0
-
- override fun interrupt() {
- _innerCtx?.interrupt()
- }
-
- override fun push(rate: Double) {
- _innerCtx?.push(rate)
- _limit = rate
- }
-
- override fun close() {
- val delegate = checkNotNull(delegate) { "Delegate not active" }
-
- if (isCoupled)
- _innerCtx?.close()
- else
- _innerCtx?.push(0.0)
-
- // 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(this, SimResourceEvent.Exit)
- }
- }
-
- /**
- * The [SimResourceContext] in which the forwarder runs.
- */
- private var _innerCtx: SimResourceContext? = null
-
- override val isActive: Boolean
- get() = delegate != null
-
- override val capacity: Double
- get() = _ctx.capacity
-
- override val speed: Double
- get() = _ctx.speed
-
- override val demand: Double
- get() = _ctx.demand
-
- 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 = _innerCtx
-
- if (delegate != null) {
- this.delegate = null
-
- if (ctx != null) {
- delegate.onEvent(this._ctx, SimResourceEvent.Exit)
- }
- }
- }
-
- override fun close() {
- val ctx = _innerCtx
-
- if (ctx != null) {
- this._innerCtx = null
- ctx.interrupt()
- }
- }
-
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- val delegate = delegate
-
- if (!hasDelegateStarted) {
- start()
- }
-
- updateCounters(ctx, delta)
-
- return delegate?.onNext(this._ctx, now, delta) ?: Long.MAX_VALUE
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> {
- _innerCtx = ctx
- }
- SimResourceEvent.Exit -> {
- _innerCtx = null
-
- val delegate = delegate
- if (delegate != null) {
- reset()
- delegate.onEvent(this._ctx, SimResourceEvent.Exit)
- }
- }
- else -> delegate?.onEvent(this._ctx, event)
- }
- }
-
- override fun onFailure(ctx: SimResourceContext, cause: Throwable) {
- _innerCtx = null
-
- val delegate = delegate
- if (delegate != null) {
- reset()
- delegate.onFailure(this._ctx, cause)
- }
- }
-
- /**
- * Start the delegate.
- */
- private fun start() {
- val delegate = delegate ?: return
- delegate.onEvent(checkNotNull(_innerCtx), SimResourceEvent.Start)
-
- hasDelegateStarted = true
- }
-
- /**
- * Reset the delegate.
- */
- private fun reset() {
- delegate = null
- hasDelegateStarted = false
- }
-
- /**
- * The requested speed.
- */
- private var _limit: Double = 0.0
-
- /**
- * Update the resource counters for the transformer.
- */
- private fun updateCounters(ctx: SimResourceContext, delta: Long) {
- if (delta <= 0) {
- return
- }
-
- val counters = _counters
- val deltaS = delta / 1000.0
- val work = _limit * deltaS
- val actualWork = ctx.speed * deltaS
- counters.demand += work
- counters.actual += actualWork
- counters.overcommit += (work - actualWork)
- }
-}
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 4bfeaf20..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceInterpreter.kt
+++ /dev/null
@@ -1,94 +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.
- */
- public fun newContext(consumer: SimResourceConsumer, provider: SimResourceProviderLogic): 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 cc718165..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceProviderLogic.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
-
-/**
- * A collection of callbacks associated with a flow stage.
- */
-public interface SimResourceProviderLogic {
- /**
- * This method is invoked when the consumer ask to consume the resource for the specified [duration].
- *
- * @param ctx The context in which the provider runs.
- * @param now The virtual timestamp in milliseconds at which the update is occurring.
- * @param delta The virtual duration between this call and the last call to [onConsume] in milliseconds.
- * @param limit The limit on the work rate of the resource consumer.
- * @param duration The duration of the consumption in milliseconds.
- * @return The deadline of the resource consumption.
- */
- public fun onConsume(ctx: SimResourceControllableContext, now: Long, delta: Long, limit: Double, duration: Long) {}
-
- /**
- * This method is invoked when the flow graph has converged into a steady-state system.
- *
- * @param ctx The context in which the provider runs.
- * @param now The virtual timestamp in milliseconds at which the system converged.
- * @param delta The virtual duration between this call and the last call to [onConverge] in milliseconds.
- */
- public fun onConverge(ctx: SimResourceControllableContext, now: Long, delta: Long) {}
-
- /**
- * This method is invoked when the resource consumer has finished.
- *
- * @param ctx The context in which the provider runs.
- * @param now The virtual timestamp in milliseconds at which the provider finished.
- * @param delta The virtual duration between this call and the last call to [onConsume] in milliseconds.
- */
- public fun onFinish(ctx: SimResourceControllableContext, now: Long, delta: Long) {}
-}
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 c8d4cf0d..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSource.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
-
-/**
- * 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, initialCapacity) {
- override fun createLogic(): SimResourceProviderLogic {
- return object : SimResourceProviderLogic {
- override fun onConsume(
- ctx: SimResourceControllableContext,
- now: Long,
- delta: Long,
- limit: Double,
- duration: Long
- ) {
- updateCounters(ctx, delta)
- }
-
- override fun onFinish(ctx: SimResourceControllableContext, now: Long, delta: Long) {
- updateCounters(ctx, delta)
- cancel()
- }
-
- override fun onConverge(ctx: SimResourceControllableContext, now: Long, delta: Long) {
- parent?.onConverge(now)
- }
- }
- }
-
- override fun toString(): String = "SimResourceSource[capacity=$capacity]"
-}
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 3c25b76d..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitch.kt
+++ /dev/null
@@ -1,67 +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 {
- /**
- * The output resource providers to which resource consumers can be attached.
- */
- public val outputs: Set<SimResourceProvider>
-
- /**
- * 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): SimResourceProvider
-
- /**
- * Remove [output] from this switch.
- */
- public fun removeOutput(output: SimResourceProvider)
-
- /**
- * Add the specified [input] to the switch.
- */
- public fun addInput(input: SimResourceProvider)
-
- /**
- * Clear all inputs and outputs from the switch.
- */
- public fun clear()
-}
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 f1e004d2..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusive.kt
+++ /dev/null
@@ -1,129 +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 many outputs as inputs.
- */
-public class SimResourceSwitchExclusive : SimResourceSwitch {
- override val outputs: Set<SimResourceProvider>
- get() = _outputs
- private val _outputs = mutableSetOf<Output>()
-
- private val _inputs = mutableSetOf<SimResourceProvider>()
- override val inputs: Set<SimResourceProvider>
- get() = _inputs
- private val _availableInputs = ArrayDeque<SimResourceForwarder>()
-
- 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 val interference: Double
- get() = _inputs.sumOf { it.counters.interference }
-
- 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?): SimResourceProvider {
- val forwarder = checkNotNull(_availableInputs.poll()) { "No capacity to serve request" }
- val output = Output(forwarder)
- _outputs += output
- return output
- }
-
- override fun removeOutput(output: SimResourceProvider) {
- if (!_outputs.remove(output)) {
- return
- }
-
- (output as Output).close()
- }
-
- /**
- * Add an input to the switch.
- */
- override fun addInput(input: SimResourceProvider) {
- if (input in inputs) {
- return
- }
-
- val forwarder = SimResourceForwarder()
-
- _inputs += input
- _availableInputs += 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 clear() {
- for (input in _inputs) {
- input.cancel()
- }
- _inputs.clear()
-
- // Outputs are implicitly cancelled by the inputs forwarders
- _outputs.clear()
- }
-
- /**
- * An output of the resource switch.
- */
- private inner class Output(private val forwarder: SimResourceForwarder) : SimResourceProvider by forwarder {
- /**
- * Close the output.
- */
- fun close() {
- // We explicitly do not close the forwarder here in order to re-use it across output resources.
- _outputs -= this
- _availableInputs += forwarder
- }
-
- override fun toString(): String = "SimResourceSwitchExclusive.Output"
- }
-}
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 574fb443..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMin.kt
+++ /dev/null
@@ -1,407 +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
-import org.opendc.simulator.resources.interference.InterferenceDomain
-import org.opendc.simulator.resources.interference.InterferenceKey
-import kotlin.math.max
-import kotlin.math.min
-
-/**
- * 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(
- private val interpreter: SimResourceInterpreter,
- private val parent: SimResourceSystem? = null,
- private val interferenceDomain: InterferenceDomain? = null
-) : SimResourceSwitch {
- /**
- * The output resource providers to which resource consumers can be attached.
- */
- override val outputs: Set<SimResourceProvider>
- get() = _outputs
- private val _outputs = mutableSetOf<Output>()
- private val _activeOutputs: MutableList<Output> = mutableListOf()
-
- /**
- * The input resources that will be switched between the output providers.
- */
- override val inputs: Set<SimResourceProvider>
- get() = _inputs
- private val _inputs = mutableSetOf<SimResourceProvider>()
- private val _activeInputs = mutableListOf<Input>()
-
- /**
- * The resource counters of this switch.
- */
- public override val counters: SimResourceCounters
- get() = _counters
- private val _counters = SimResourceCountersImpl()
-
- /**
- * The actual processing rate of the switch.
- */
- private var _rate = 0.0
-
- /**
- * The demanded processing rate of the outputs.
- */
- private var _demand = 0.0
-
- /**
- * The capacity of the switch.
- */
- private var _capacity = 0.0
-
- /**
- * Flag to indicate that the scheduler is active.
- */
- private var _schedulerActive = false
-
- /**
- * Add an output to the switch.
- */
- override fun newOutput(key: InterferenceKey?): SimResourceProvider {
- val provider = Output(_capacity, key)
- _outputs.add(provider)
- return provider
- }
-
- /**
- * Add the specified [input] to the switch.
- */
- override fun addInput(input: SimResourceProvider) {
- val consumer = Input(input)
- if (_inputs.add(input)) {
- _activeInputs.add(consumer)
- input.startConsumer(consumer)
- }
- }
-
- /**
- * Remove [output] from this switch.
- */
- override fun removeOutput(output: SimResourceProvider) {
- if (!_outputs.remove(output)) {
- return
- }
- // This cast should always succeed since only `Output` instances should be added to _outputs
- (output as Output).close()
- }
-
- override fun clear() {
- for (input in _activeInputs) {
- input.cancel()
- }
- _activeInputs.clear()
-
- for (output in _activeOutputs) {
- output.cancel()
- }
- _activeOutputs.clear()
- }
-
- /**
- * Run the scheduler of the switch.
- */
- private fun runScheduler(now: Long) {
- if (_schedulerActive) {
- return
- }
-
- _schedulerActive = true
- try {
- doSchedule(now)
- } finally {
- _schedulerActive = false
- }
- }
-
- /**
- * Schedule the outputs over the input.
- */
- private fun doSchedule(now: Long) {
- // If there is no work yet, mark the input as idle.
- if (_activeOutputs.isEmpty()) {
- return
- }
-
- val capacity = _capacity
- var availableCapacity = capacity
-
- // Pull in the work of the outputs
- val outputIterator = _activeOutputs.listIterator()
- for (output in outputIterator) {
- output.pull(now)
-
- // Remove outputs that have finished
- if (!output.isActive) {
- outputIterator.remove()
- }
- }
-
- var demand = 0.0
-
- // 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 = availableCapacity / remaining--
- val grantedSpeed = min(output.allowedRate, availableShare)
-
- // Ignore idle computation
- if (grantedSpeed <= 0.0) {
- output.actualRate = 0.0
- continue
- }
-
- demand += output.limit
-
- output.actualRate = grantedSpeed
- availableCapacity -= grantedSpeed
- }
-
- val rate = capacity - availableCapacity
-
- _demand = demand
- _rate = rate
-
- // Sort all consumers by their capacity
- _activeInputs.sort()
-
- // Divide the requests over the available capacity of the input resources fairly
- for (input in _activeInputs) {
- val inputCapacity = input.capacity
- val fraction = inputCapacity / capacity
- val grantedSpeed = rate * fraction
-
- input.push(grantedSpeed)
- }
- }
-
- /**
- * Recompute the capacity of the switch.
- */
- private fun updateCapacity() {
- val newCapacity = _activeInputs.sumOf(Input::capacity)
-
- // No-op if the capacity is unchanged
- if (_capacity == newCapacity) {
- return
- }
-
- _capacity = newCapacity
-
- for (output in _outputs) {
- output.capacity = newCapacity
- }
- }
-
- /**
- * An internal [SimResourceProvider] implementation for switch outputs.
- */
- private inner class Output(capacity: Double, val key: InterferenceKey?) :
- SimAbstractResourceProvider(interpreter, capacity),
- SimResourceProviderLogic,
- Comparable<Output> {
- /**
- * The requested limit.
- */
- @JvmField var limit: Double = 0.0
-
- /**
- * The actual processing speed.
- */
- @JvmField var actualRate: Double = 0.0
-
- /**
- * The processing speed that is allowed by the model constraints.
- */
- val allowedRate: Double
- get() = min(capacity, limit)
-
- /**
- * A flag to indicate that the output is closed.
- */
- private var _isClosed: Boolean = false
-
- /**
- * The timestamp at which we received the last command.
- */
- private var _lastPull: Long = Long.MIN_VALUE
-
- /**
- * Close the output.
- *
- * This method is invoked when the user removes an output from the switch.
- */
- fun close() {
- _isClosed = true
- cancel()
- }
-
- /* SimAbstractResourceProvider */
- override fun createLogic(): SimResourceProviderLogic = this
-
- override fun start(ctx: SimResourceControllableContext) {
- check(!_isClosed) { "Cannot re-use closed output" }
-
- _activeOutputs += this
- super.start(ctx)
- }
-
- /* SimResourceProviderLogic */
- override fun onConsume(
- ctx: SimResourceControllableContext,
- now: Long,
- delta: Long,
- limit: Double,
- duration: Long
- ) {
- doUpdateCounters(delta)
-
- actualRate = 0.0
- this.limit = limit
- _lastPull = now
-
- runScheduler(now)
- }
-
- override fun onConverge(ctx: SimResourceControllableContext, now: Long, delta: Long) {
- parent?.onConverge(now)
- }
-
- override fun onFinish(ctx: SimResourceControllableContext, now: Long, delta: Long) {
- doUpdateCounters(delta)
-
- limit = 0.0
- actualRate = 0.0
- _lastPull = now
- }
-
- /* Comparable */
- override fun compareTo(other: Output): Int = allowedRate.compareTo(other.allowedRate)
-
- /**
- * Pull the next command if necessary.
- */
- fun pull(now: Long) {
- val ctx = ctx
- if (ctx != null && _lastPull < now) {
- ctx.flush()
- }
- }
-
- /**
- * Helper method to update the resource counters of the distributor.
- */
- private fun doUpdateCounters(delta: Long) {
- if (delta <= 0L) {
- return
- }
-
- // Compute the performance penalty due to resource interference
- val perfScore = if (interferenceDomain != null) {
- val load = _rate / capacity
- interferenceDomain.apply(key, load)
- } else {
- 1.0
- }
-
- val deltaS = delta / 1000.0
- val work = limit * deltaS
- val actualWork = actualRate * deltaS
- val remainingWork = work - actualWork
-
- updateCounters(work, actualWork, remainingWork)
-
- val distCounters = _counters
- distCounters.demand += work
- distCounters.actual += actualWork
- distCounters.overcommit += remainingWork
- distCounters.interference += actualWork * max(0.0, 1 - perfScore)
- }
- }
-
- /**
- * An internal [SimResourceConsumer] implementation for switch inputs.
- */
- private inner class Input(private val provider: SimResourceProvider) : SimResourceConsumer, Comparable<Input> {
- /**
- * The active [SimResourceContext] of this consumer.
- */
- private var _ctx: SimResourceContext? = null
-
- /**
- * The capacity of this input.
- */
- val capacity: Double
- get() = _ctx?.capacity ?: 0.0
-
- /**
- * Push the specified rate to the provider.
- */
- fun push(rate: Double) {
- _ctx?.push(rate)
- }
-
- /**
- * Cancel this input.
- */
- fun cancel() {
- provider.cancel()
- }
-
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- runScheduler(now)
- return Long.MAX_VALUE
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- when (event) {
- SimResourceEvent.Start -> {
- assert(_ctx == null) { "Consumer running concurrently" }
- _ctx = ctx
- updateCapacity()
- }
- SimResourceEvent.Exit -> {
- _ctx = null
- updateCapacity()
- }
- SimResourceEvent.Capacity -> updateCapacity()
- else -> {}
- }
- }
-
- override fun compareTo(other: Input): Int = capacity.compareTo(other.capacity)
- }
-}
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/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 46885640..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimSpeedConsumerAdapter.kt
+++ /dev/null
@@ -1,82 +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.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, now: Long, delta: Long): Long {
- return delegate.onNext(ctx, now, delta)
- }
-
- 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 4c0e075c..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.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
- private var _nextTarget = Long.MIN_VALUE
-
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- // Check whether the trace fragment was fully consumed, otherwise wait until we have done so
- val nextTarget = _nextTarget
- if (nextTarget > now) {
- return now - nextTarget
- }
-
- val iterator = checkNotNull(_iterator)
- return if (iterator.hasNext()) {
- val fragment = iterator.next()
- _nextTarget = now + fragment.duration
- ctx.push(fragment.usage)
- fragment.duration
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
-
- 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 bf76711f..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/consumer/SimWorkConsumer.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.consumer
-
-import org.opendc.simulator.resources.SimResourceConsumer
-import org.opendc.simulator.resources.SimResourceContext
-import kotlin.math.roundToLong
-
-/**
- * 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 must be positive" }
- }
-
- private var remainingWork = work
-
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- val actualWork = ctx.speed * delta / 1000.0
- val limit = ctx.capacity * utilization
-
- remainingWork -= actualWork
-
- val remainingWork = remainingWork
- val duration = (remainingWork / limit * 1000).roundToLong()
-
- return if (duration > 0) {
- ctx.push(limit)
- duration
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
-}
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 cbfa7afd..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt
+++ /dev/null
@@ -1,367 +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 java.util.ArrayDeque
-import kotlin.math.max
-import kotlin.math.min
-
-/**
- * Implementation of a [SimResourceContext] managing the communication between resources and resource consumers.
- */
-internal class SimResourceContextImpl(
- private val interpreter: SimResourceInterpreterImpl,
- private val consumer: SimResourceConsumer,
- private val logic: SimResourceProviderLogic
-) : SimResourceControllableContext {
- /**
- * 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()
- }
- }
-
- /**
- * A flag to indicate the state of the context.
- */
- private var _state = State.Pending
-
- /**
- * The current processing speed of the resource.
- */
- override val speed: Double
- get() = _rate
- private var _rate = 0.0
-
- /**
- * The current resource processing demand.
- */
- override val demand: Double
- get() = _limit
-
- /**
- * The current state of the resource context.
- */
- private var _limit: Double = 0.0
- private var _activeLimit: Double = 0.0
- private var _deadline: Long = Long.MIN_VALUE
-
- /**
- * A flag to indicate that an update is active.
- */
- private var _updateActive = false
-
- /**
- * The update flag indicating why the update was triggered.
- */
- private var _flag: Int = 0
-
- /**
- * The timestamp of calls to the callbacks.
- */
- private var _lastUpdate: Long = Long.MIN_VALUE
- private var _lastConvergence: Long = Long.MAX_VALUE
-
- /**
- * The timers at which the context is scheduled to be interrupted.
- */
- private val _timers: ArrayDeque<SimResourceInterpreterImpl.Timer> = ArrayDeque()
-
- override fun start() {
- check(_state == State.Pending) { "Consumer is already started" }
- interpreter.batch {
- consumer.onEvent(this, SimResourceEvent.Start)
- _state = State.Active
- interrupt()
- }
- }
-
- override fun close() {
- if (_state == State.Stopped) {
- return
- }
-
- interpreter.batch {
- _state = State.Stopped
- if (!_updateActive) {
- val now = clock.millis()
- val delta = max(0, now - _lastUpdate)
- doStop(now, delta)
-
- // FIX: Make sure the context converges
- _flag = _flag or FLAG_INVALIDATE
- scheduleUpdate(clock.millis())
- }
- }
- }
-
- override fun interrupt() {
- if (_state == State.Stopped) {
- return
- }
-
- _flag = _flag or FLAG_INTERRUPT
- scheduleUpdate(clock.millis())
- }
-
- override fun invalidate() {
- if (_state == State.Stopped) {
- return
- }
-
- _flag = _flag or FLAG_INVALIDATE
- scheduleUpdate(clock.millis())
- }
-
- override fun flush() {
- if (_state == State.Stopped) {
- return
- }
-
- interpreter.scheduleSync(clock.millis(), this)
- }
-
- override fun push(rate: Double) {
- if (_limit == rate) {
- return
- }
-
- _limit = rate
-
- // Invalidate only if the active limit is change and no update is active
- // If an update is active, it will already get picked up at the end of the update
- if (_activeLimit != rate && !_updateActive) {
- invalidate()
- }
- }
-
- /**
- * Determine whether the state of the resource context should be updated.
- */
- fun shouldUpdate(timestamp: Long): Boolean {
- // Either the resource context is flagged or there is a pending update at this timestamp
- return _flag != 0 || _limit != _activeLimit || _deadline == timestamp
- }
-
- /**
- * Update the state of the resource context.
- */
- fun doUpdate(now: Long) {
- val oldState = _state
- if (oldState != State.Active) {
- return
- }
-
- val lastUpdate = _lastUpdate
-
- _lastUpdate = now
- _updateActive = true
-
- val delta = max(0, now - lastUpdate)
-
- try {
- val duration = consumer.onNext(this, now, delta)
- val newDeadline = if (duration != Long.MAX_VALUE) now + duration else duration
-
- // Reset update flags
- _flag = 0
-
- // Check whether the state has changed after [consumer.onNext]
- when (_state) {
- State.Active -> {
- logic.onConsume(this, now, delta, _limit, duration)
-
- // Schedule an update at the new deadline
- scheduleUpdate(now, newDeadline)
- }
- State.Stopped -> doStop(now, delta)
- State.Pending -> throw IllegalStateException("Illegal transition to pending state")
- }
-
- // Note: pending limit might be changed by [logic.onConsume], so re-fetch the value
- val newLimit = _limit
-
- // Flush the changes to the flow
- _activeLimit = newLimit
- _deadline = newDeadline
- _rate = min(capacity, newLimit)
- } catch (cause: Throwable) {
- doFail(now, delta, cause)
- } finally {
- _updateActive = false
- }
- }
-
- /**
- * Prune the elapsed timers from this context.
- */
- fun pruneTimers(now: Long) {
- val timers = _timers
- while (true) {
- val head = timers.peek()
- if (head == null || head.target > now) {
- break
- }
- timers.poll()
- }
- }
-
- /**
- * Try to re-schedule the resource context in case it was skipped.
- */
- fun tryReschedule(now: Long) {
- val deadline = _deadline
- if (deadline > now && deadline != Long.MAX_VALUE) {
- scheduleUpdate(now, deadline)
- }
- }
-
- /**
- * This method is invoked when the system converges into a steady state.
- */
- fun onConverge(timestamp: Long) {
- val delta = max(0, timestamp - _lastConvergence)
- _lastConvergence = timestamp
-
- try {
- if (_state == State.Active) {
- consumer.onEvent(this, SimResourceEvent.Run)
- }
-
- logic.onConverge(this, timestamp, delta)
- } catch (cause: Throwable) {
- doFail(timestamp, max(0, timestamp - _lastUpdate), cause)
- }
- }
-
- override fun toString(): String = "SimResourceContextImpl[capacity=$capacity,rate=$_rate]"
-
- /**
- * Stop the resource context.
- */
- private fun doStop(now: Long, delta: Long) {
- try {
- consumer.onEvent(this, SimResourceEvent.Exit)
- logic.onFinish(this, now, delta)
- } catch (cause: Throwable) {
- doFail(now, delta, cause)
- } finally {
- _deadline = Long.MAX_VALUE
- _limit = 0.0
- }
- }
-
- /**
- * Fail the resource consumer.
- */
- private fun doFail(now: Long, delta: Long, cause: Throwable) {
- try {
- consumer.onFailure(this, cause)
- } catch (e: Throwable) {
- e.addSuppressed(cause)
- e.printStackTrace()
- }
-
- logic.onFinish(this, now, delta)
- }
-
- /**
- * 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 != State.Active) {
- return
- }
-
- interpreter.batch {
- // Inform the consumer of the capacity change. This might already trigger an interrupt.
- consumer.onEvent(this, SimResourceEvent.Capacity)
-
- interrupt()
- }
- }
-
- /**
- * Schedule an update for this resource context.
- */
- private fun scheduleUpdate(now: Long) {
- interpreter.scheduleImmediate(now, this)
- }
-
- /**
- * Schedule a delayed update for this resource context.
- */
- private fun scheduleUpdate(now: Long, target: Long) {
- val timers = _timers
- if (target != Long.MAX_VALUE && (timers.isEmpty() || target < timers.peek().target)) {
- timers.addFirst(interpreter.scheduleDelayed(now, this, target))
- }
- }
-
- /**
- * The state of a resource context.
- */
- private enum class State {
- /**
- * The resource context is pending and the resource is waiting to be consumed.
- */
- Pending,
-
- /**
- * The resource context is active and the resource is currently being consumed.
- */
- Active,
-
- /**
- * The resource context is stopped and the resource cannot be consumed anymore.
- */
- Stopped
- }
-
- /**
- * 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 01062179..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceCountersImpl.kt
+++ /dev/null
@@ -1,46 +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 var interference: Double = 0.0
-
- override fun reset() {
- demand = 0.0
- actual = 0.0
- overcommit = 0.0
- interference = 0.0
- }
-
- override fun toString(): String {
- return "SimResourceCounters[demand=$demand,actual=$actual,overcommit=$overcommit,interference=$interference]"
- }
-}
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 2abf0749..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceInterpreterImpl.kt
+++ /dev/null
@@ -1,298 +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<Timer>()
-
- /**
- * 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<SimResourceContextImpl>()
-
- /**
- * 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
-
- /**
- * Update the specified [ctx] synchronously.
- */
- fun scheduleSync(now: Long, ctx: SimResourceContextImpl) {
- ctx.doUpdate(now)
- visited.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(now)
- } finally {
- batchIndex--
- }
- }
-
- /**
- * 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(now: Long, 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(now)
- } finally {
- batchIndex--
- }
- }
-
- /**
- * Schedule the interpreter to run at [target] to update the resource contexts.
- *
- * This method will override earlier calls to this method for the same [ctx].
- *
- * @param now The current virtual timestamp.
- * @param ctx The resource context to which the event applies.
- * @param target The timestamp when the interrupt should happen.
- */
- fun scheduleDelayed(now: Long, ctx: SimResourceContextImpl, target: Long): Timer {
- val futureQueue = futureQueue
-
- require(target >= now) { "Timestamp must be in the future" }
-
- val timer = Timer(ctx, target)
- futureQueue.add(timer)
-
- return timer
- }
-
- override fun newContext(consumer: SimResourceConsumer, provider: SimResourceProviderLogic): SimResourceControllableContext = SimResourceContextImpl(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(clock.millis())
- }
- } finally {
- batchIndex--
- }
- }
-
- /**
- * Interpret all actions that are scheduled for the current timestamp.
- */
- private fun runInterpreter(now: Long) {
- val queue = queue
- val futureQueue = futureQueue
- val futureInvocations = futureInvocations
- val visited = visited
-
- // Remove any entries in the `futureInvocations` queue from the past
- while (true) {
- val head = futureInvocations.peek()
- if (head == null || head.timestamp > now) {
- break
- }
- futureInvocations.poll()
- }
-
- // Execute all scheduled updates at current timestamp
- while (true) {
- val timer = futureQueue.peek() ?: break
- val ctx = timer.ctx
- val target = timer.target
-
- assert(target >= now) { "Internal inconsistency: found update of the past" }
-
- if (target > now) {
- break
- }
-
- futureQueue.poll()
-
- ctx.pruneTimers(now)
-
- if (ctx.shouldUpdate(now)) {
- ctx.doUpdate(now)
- visited.add(ctx)
- } else {
- ctx.tryReschedule(now)
- }
- }
-
- // 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
-
- if (ctx.shouldUpdate(now)) {
- ctx.doUpdate(now)
- visited.add(ctx)
- }
- }
-
- for (system in visited) {
- system.onConverge(now)
- }
-
- visited.clear()
- } while (queue.isNotEmpty())
-
- // Schedule an interpreter invocation for the next update to occur.
- val headTimer = futureQueue.peek()
- if (headTimer != null) {
- trySchedule(now, futureInvocations, headTimer.target)
- }
- }
-
- /**
- * Try to schedule an interpreter invocation at the specified [target].
- *
- * @param now The current virtual timestamp.
- * @param target The virtual timestamp at which the interpreter invocation should happen.
- * @param scheduled The queue of scheduled invocations.
- */
- private fun trySchedule(now: Long, scheduled: ArrayDeque<Invocation>, target: Long) {
- while (true) {
- val invocation = scheduled.peekFirst()
- if (invocation == null || invocation.timestamp > target) {
- // Case 2: A new timer was registered ahead of the other timers.
- // Solution: Schedule a new scheduler invocation
- @OptIn(InternalCoroutinesApi::class)
- val handle = delay.invokeOnTimeout(
- target - now,
- {
- try {
- batchIndex++
- runInterpreter(target)
- } finally {
- batchIndex--
- }
- },
- context
- )
- scheduled.addFirst(Invocation(target, handle))
- break
- } else if (invocation.timestamp < target) {
- // Case 2: A timer was cancelled and the head of the timer queue is now later than excepted
- // Solution: Cancel the next scheduler invocation
- scheduled.pollFirst()
-
- invocation.cancel()
- } else {
- break
- }
- }
- }
-
- /**
- * 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,
- @JvmField val handle: DisposableHandle
- ) {
- /**
- * Cancel the interpreter invocation.
- */
- fun cancel() = handle.dispose()
- }
-
- /**
- * An update call for [ctx] that is scheduled for [target].
- *
- * This class represents an update in the future at [target] requested by [ctx]. A deferred update might be
- * cancelled if the resource context was invalidated in the meantime.
- */
- class Timer(@JvmField val ctx: SimResourceContextImpl, @JvmField val target: Long) : Comparable<Timer> {
- override fun compareTo(other: Timer): Int {
- return target.compareTo(other.target)
- }
-
- override fun toString(): String = "Timer[ctx=$ctx,timestamp=$target]"
- }
-}
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/SimResourceContextTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceContextTest.kt
deleted file mode 100644
index 1428ce42..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceContextTest.kt
+++ /dev/null
@@ -1,173 +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.consumer.SimWorkConsumer
-import org.opendc.simulator.resources.impl.SimResourceContextImpl
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * A test suite for the [SimResourceContextImpl] class.
- */
-class SimResourceContextTest {
- @Test
- fun testFlushWithoutCommand() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- return if (now == 0L) {
- ctx.push(1.0)
- 1000
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
- }
-
- val logic = object : SimResourceProviderLogic {}
- val context = SimResourceContextImpl(interpreter, consumer, logic)
-
- interpreter.scheduleSync(interpreter.clock.millis(), context)
- }
-
- @Test
- fun testIntermediateFlush() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = SimWorkConsumer(1.0, 1.0)
-
- val logic = spyk(object : SimResourceProviderLogic {})
- val context = SimResourceContextImpl(interpreter, consumer, logic)
- context.capacity = 1.0
-
- context.start()
- delay(1) // Delay 1 ms to prevent hitting the fast path
- interpreter.scheduleSync(interpreter.clock.millis(), context)
-
- verify(exactly = 2) { logic.onConsume(any(), any(), any(), any(), any()) }
- }
-
- @Test
- fun testIntermediateFlushIdle() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = SimWorkConsumer(1.0, 1.0)
-
- val logic = spyk(object : SimResourceProviderLogic {})
- val context = SimResourceContextImpl(interpreter, consumer, logic)
- context.capacity = 1.0
-
- context.start()
- delay(500)
- context.invalidate()
- delay(500)
- context.invalidate()
-
- assertAll(
- { verify(exactly = 2) { logic.onConsume(any(), any(), any(), any(), any()) } },
- { verify(exactly = 1) { logic.onFinish(any(), any(), any()) } }
- )
- }
-
- @Test
- fun testDoubleStart() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- return if (now == 0L) {
- ctx.push(0.0)
- 1000
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
- }
-
- val logic = object : SimResourceProviderLogic {}
- val context = SimResourceContextImpl(interpreter, consumer, logic)
-
- context.start()
-
- assertThrows<IllegalStateException> {
- context.start()
- }
- }
-
- @Test
- fun testIdempotentCapacityChange() = runBlockingSimulation {
- val interpreter = SimResourceInterpreterImpl(coroutineContext, clock)
- val consumer = spyk(object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- return if (now == 0L) {
- ctx.push(1.0)
- 1000
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
- })
-
- val logic = object : SimResourceProviderLogic {}
- val context = SimResourceContextImpl(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 = spyk(object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- ctx.close()
- return Long.MAX_VALUE
- }
-
- override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
- if (event == SimResourceEvent.Exit) throw IllegalStateException("onEvent")
- }
-
- override fun onFailure(ctx: SimResourceContext, cause: Throwable) {
- throw IllegalStateException("onFailure")
- }
- })
-
- val logic = object : SimResourceProviderLogic {}
-
- val context = SimResourceContextImpl(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/SimResourceForwarderTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceForwarderTest.kt
deleted file mode 100644
index 49e60f68..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceForwarderTest.kt
+++ /dev/null
@@ -1,220 +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.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 [SimResourceForwarder] class.
- */
-internal class SimResourceForwarderTest {
- @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, now: Long, delta: Long): Long {
- ctx.close()
- return Long.MAX_VALUE
- }
- })
-
- 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, now: Long, delta: Long): Long {
- return if (isFirst) {
- isFirst = false
- ctx.push(1.0)
- 10 * 1000
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
- })
-
- forwarder.close()
- source.cancel()
- }
-
- @Test
- fun testState() = runBlockingSimulation {
- val forwarder = SimResourceForwarder()
- val consumer = object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- ctx.close()
- return Long.MAX_VALUE
- }
- }
-
- 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 = spyk(object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- ctx.close()
- return Long.MAX_VALUE
- }
- })
-
- 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 = spyk(SimWorkConsumer(2000.0, 1.0))
-
- 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 = spyk(SimWorkConsumer(2000.0, 1.0))
-
- 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 = object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- ctx.close()
- return Long.MAX_VALUE
- }
- }
-
- 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 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)
-
- yield()
-
- assertEquals(2.0, source.counters.actual)
- 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/SimResourceSourceTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSourceTest.kt
deleted file mode 100644
index e055daf7..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSourceTest.kt
+++ /dev/null
@@ -1,240 +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.
- */
-internal class SimResourceSourceTest {
- @Test
- fun testSpeed() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
- val capacity = 4200.0
- val provider = SimResourceSource(capacity, scheduler)
-
- val consumer = SimWorkConsumer(4200.0, 1.0)
-
- 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 = SimWorkConsumer(capacity, 2.0)
-
- 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, now: Long, delta: Long): Long {
- ctx.close()
- return Long.MAX_VALUE
- }
-
- 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, now: Long, delta: Long): Long {
- return if (isFirst) {
- isFirst = false
- ctx.push(1.0)
- 4000
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
- }
-
- 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 = object : SimResourceConsumer {
- var isFirst = true
-
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long {
- return if (isFirst) {
- isFirst = false
- ctx.push(1.0)
- 1000
- } else {
- throw 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 = SimWorkConsumer(capacity, 1.0)
-
- 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 = SimWorkConsumer(capacity, 1.0)
-
- launch { provider.consume(consumer) }
- delay(500)
- provider.cancel()
-
- yield()
-
- 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 = object : SimResourceConsumer {
- override fun onNext(ctx: SimResourceContext, now: Long, delta: Long): Long = Long.MAX_VALUE
- }
-
- 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 49f2da5f..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchExclusiveTest.kt
+++ /dev/null
@@ -1,156 +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.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.consumer.SimWorkConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * Test suite for the [SimResourceSwitchExclusive] 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()
- provider.consume(workload)
- yield()
-
- 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 = SimWorkConsumer(duration * 3.2, 1.0)
-
- val switch = SimResourceSwitchExclusive()
- val source = SimResourceSource(3200.0, scheduler)
-
- switch.addInput(source)
-
- val provider = switch.newOutput()
- provider.consume(workload)
- yield()
-
- 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, now: Long, delta: Long): Long {
- return if (isFirst) {
- isFirst = false
- ctx.push(1.0)
- duration
- } else {
- ctx.close()
- Long.MAX_VALUE
- }
- }
- }
-
- val switch = SimResourceSwitchExclusive()
- val source = SimResourceSource(3200.0, scheduler)
-
- switch.addInput(source)
-
- val provider = switch.newOutput()
- provider.consume(workload)
- yield()
- provider.consume(workload)
- assertEquals(duration * 2, clock.millis()) { "Took enough time" }
- }
-
- /**
- * Test concurrent workloads on the machine.
- */
- @Test
- fun testConcurrentWorkloadFails() = runBlockingSimulation {
- val scheduler = SimResourceInterpreterImpl(coroutineContext, clock)
-
- 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 03f90e21..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimResourceSwitchMaxMinTest.kt
+++ /dev/null
@@ -1,145 +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.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.consumer.SimWorkConsumer
-import org.opendc.simulator.resources.impl.SimResourceInterpreterImpl
-
-/**
- * Test suite for the [SimResourceSwitch] implementations
- */
-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 = SimWorkConsumer(2000.0, 1.0)
-
- try {
- provider.consume(consumer)
- yield()
- } finally {
- switch.clear()
- }
- }
-
- /**
- * 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.clear()
- }
-
- 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.clear()
- }
- 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/SimWorkConsumerTest.kt b/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimWorkConsumerTest.kt
deleted file mode 100644
index 830f16d3..00000000
--- a/opendc-simulator/opendc-simulator-resources/src/test/kotlin/org/opendc/simulator/resources/SimWorkConsumerTest.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
-
-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.
- */
-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())
- }
-}