diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-10-08 12:23:48 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-10-08 17:11:53 +0200 |
| commit | f9483bc5782d86637777c0d21c383ce3e2c0851b (patch) | |
| tree | c3c5af29adfc82f56a172d1de728c936d3cb87da | |
| parent | 4623316cb23ce95cb8ce8db0987f948a8dc1a349 (diff) | |
perf(simulator): Optimize clock storage
2 files changed, 37 insertions, 20 deletions
diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt index e2f7874c..908e902a 100644 --- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt +++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt @@ -37,11 +37,6 @@ import kotlin.coroutines.CoroutineContext @OptIn(InternalCoroutinesApi::class) public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationController, Delay { /** - * The virtual clock of this dispatcher. - */ - override val clock: Clock = VirtualClock() - - /** * Queue of ordered tasks to run. */ private val queue = PriorityQueue<TimedRunnable>() @@ -54,7 +49,12 @@ public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationCo /** * The current virtual time of simulation */ - private var _time = 0L + private var _clock = SimClock() + + /** + * The virtual clock of this dispatcher. + */ + override val clock: Clock = ClockAdapter(_clock) override fun dispatch(context: CoroutineContext, block: Runnable) { block.run() @@ -79,14 +79,14 @@ public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationCo } override fun toString(): String { - return "SimulationCoroutineDispatcher[time=${_time}ms, queued=${queue.size}]" + return "SimulationCoroutineDispatcher[time=${_clock.time}ms, queued=${queue.size}]" } private fun post(block: Runnable) = queue.add(TimedRunnable(block, _counter++)) private fun postDelayed(block: Runnable, delayTime: Long) = - TimedRunnable(block, _counter++, safePlus(_time, delayTime)) + TimedRunnable(block, _counter++, safePlus(_clock.time, delayTime)) .also { queue.add(it) } @@ -100,31 +100,41 @@ public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationCo override fun advanceUntilIdle(): Long { val queue = queue - val oldTime = _time - while (queue.isNotEmpty()) { - val current = queue.poll() + val clock = _clock + val oldTime = clock.time + + while (true) { + val current = queue.poll() ?: break // If the scheduled time is 0 (immediate) use current virtual time if (current.time != 0L) { - _time = current.time + clock.time = current.time } current.run() } - return _time - oldTime + return clock.time - oldTime } - private inner class VirtualClock(private val zone: ZoneId = ZoneId.systemDefault()) : Clock() { + /** + * A helper class that holds the time of the simulation. + */ + private class SimClock(@JvmField var time: Long = 0) + + /** + * A helper class to expose a [Clock] instance for this dispatcher. + */ + private class ClockAdapter(private val clock: SimClock, private val zone: ZoneId = ZoneId.systemDefault()) : Clock() { override fun getZone(): ZoneId = zone - override fun withZone(zone: ZoneId): Clock = VirtualClock(zone) + override fun withZone(zone: ZoneId): Clock = ClockAdapter(clock, zone) override fun instant(): Instant = Instant.ofEpochMilli(millis()) - override fun millis(): Long = _time + override fun millis(): Long = clock.time - override fun toString(): String = "SimulationCoroutineDispatcher.VirtualClock[time=$_time]" + override fun toString(): String = "SimulationCoroutineDispatcher.ClockAdapter[time=${clock.time}]" } /** diff --git a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt index a9234abf..450556f8 100644 --- a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt +++ b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt @@ -38,7 +38,7 @@ import kotlin.coroutines.CoroutineContext * @param context The coroutine context to use. * @param clock The virtual simulation clock. */ -internal class FlowEngineImpl(private val context: CoroutineContext, override val clock: Clock) : FlowEngine, Runnable { +internal class FlowEngineImpl(private val context: CoroutineContext, clock: Clock) : FlowEngine, Runnable { /** * The [Delay] instance that provides scheduled execution of [Runnable]s. */ @@ -71,6 +71,13 @@ internal class FlowEngineImpl(private val context: CoroutineContext, override va private var batchIndex = 0 /** + * The virtual [Clock] of this engine. + */ + override val clock: Clock + get() = _clock + private val _clock: Clock = clock + + /** * Update the specified [ctx] synchronously. */ fun scheduleSync(now: Long, ctx: FlowConsumerContextImpl) { @@ -113,7 +120,7 @@ internal class FlowEngineImpl(private val context: CoroutineContext, override va try { // Flush the work if the engine is not already running if (batchIndex == 1 && queue.isNotEmpty()) { - doRunEngine(clock.millis()) + doRunEngine(_clock.millis()) } } finally { batchIndex-- @@ -122,7 +129,7 @@ internal class FlowEngineImpl(private val context: CoroutineContext, override va /* Runnable */ override fun run() { - val now = clock.millis() + val now = _clock.millis() val invocation = futureInvocations.poll() // Clear invocation from future invocation queue assert(now >= invocation.timestamp) { "Future invocations invariant violated" } |
