From 1a9cb7cfd2a67c32fd89d490f1462c59fa0d33b9 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 6 Sep 2017 15:05:59 +0200 Subject: Refactor default Simulator implementation This change refactors the default Simulator implementation, reformatting the code, adding input validation and extracting common code. --- .../opendc/simulator/omega/OmegaSimulator.kt | 119 +++++++++------------ .../nl/atlarge/opendc/topology/machine/Machine.kt | 2 +- 2 files changed, 54 insertions(+), 67 deletions(-) (limited to 'opendc-core') diff --git a/opendc-core/src/main/kotlin/nl/atlarge/opendc/simulator/omega/OmegaSimulator.kt b/opendc-core/src/main/kotlin/nl/atlarge/opendc/simulator/omega/OmegaSimulator.kt index 764134e5..c5740210 100644 --- a/opendc-core/src/main/kotlin/nl/atlarge/opendc/simulator/omega/OmegaSimulator.kt +++ b/opendc-core/src/main/kotlin/nl/atlarge/opendc/simulator/omega/OmegaSimulator.kt @@ -45,7 +45,7 @@ import kotlin.coroutines.experimental.* * @param topology The topology to run the simulation over. * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ -class OmegaSimulator(override val topology: Topology): Simulator, Iterator { +class OmegaSimulator(override val topology: Topology) : Simulator, Iterator { /** * The logger instance to use for the simulator. */ @@ -93,7 +93,7 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator * @param component The component to resolve. * @return The [Kernel] that simulates that [Component]. */ - fun > resolve(component: T): Context? { + fun > resolve(component: T): Context? { @Suppress("UNCHECKED_CAST") return registry.computeIfAbsent(component, { if (component.label !is Kernel<*>) @@ -138,7 +138,7 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator /** * The co-routine which runs a simulation kernel. */ - private class KernelCoroutine: Continuation { + private class KernelCoroutine : Continuation { override val context: CoroutineContext = EmptyCoroutineContext override fun resume(value: Unit) {} @@ -149,76 +149,38 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator } /** - * The [Context] for an entity within the simulation. + * The [Clock] for this [OmegaSimulator] that keeps track of the simulation time in ticks. */ - private inner class OmegaEntityContext>(override val component: Node): EntityContext { - /** - * The [Topology] over which the simulation is run. - */ - override val topology: Topology = this@OmegaSimulator.topology - - /** - * Retrieves and removes a single message from this channel suspending the caller while the channel is empty. - * - * @param block The block to process the message with. - * @return The processed message. - */ - suspend override fun receive(block: Envelope<*>.(Any?) -> T): T = suspendCoroutine {} - - /** - * The observable state of an [Entity] within the simulation is provided by context. - */ - @Suppress("UNCHECKED_CAST") - override val Entity.state: S - get() = states.computeIfAbsent(this, { initialState }) as S + private inner class OmegaClock : Clock { + override var tick: Tick = 0 + internal val queue: PriorityQueue Unit>> = PriorityQueue(Comparator.comparingLong { it.first }) - /** - * Update the state of the entity being simulated. - * - *

Instead of directly mutating the entity, we create a new instance of the entity to prevent other objects - * referencing the old entity having their data changed. - * - * @param next The next state of the entity. - */ - suspend override fun , E: Entity, S> C.update(next: S) { - states.put(component.entity as Entity<*>, next) + override fun scheduleAt(tick: Tick, block: () -> Unit) { + queue.add(Pair(tick, block)) } - - /** - * Suspend the simulation kernel for n ticks before resuming the execution. - * - * @param n The amount of ticks to suspend the simulation kernel. - */ - suspend override fun wait(n: Int): Unit = suspendCoroutine { cont -> clock.scheduleAfter(n, { cont.resume(Unit) }) } } /** - * The [Context] for an edge within the simulation. + * This internal class provides the default implementation for the [Context] interface for this simulator. */ - private inner class OmegaChannelContext(override val component: Edge): ChannelContext { + private abstract inner class OmegaAbstractContext> : Context { /** * The [Topology] over which the simulation is run. */ override val topology: Topology = this@OmegaSimulator.topology /** - * Retrieves and removes a single message from this channel suspending the caller while the channel is empty. - * - * @param block The block to process the message with. - * @return The processed message. - */ - suspend override fun receive(block: Envelope<*>.(Any?) -> T): T = suspendCoroutine {} - - /** - * Send the given message downstream. - * - * @param msg The message to send. - * @param sender The sender of the message. - */ - suspend override fun send(msg: Any?, sender: Node<*>): Unit = suspendCoroutine {} + * Retrieves and removes a single message from this channel suspending the caller while the channel is empty. + * + * @param block The block to process the message with. + * @return The processed message. + */ + suspend override fun receive(block: Envelope<*>.(Any?) -> T): T { + TODO("not implemented") + } /** - * The observable state of an [Entity] within the simulation is provided by context. + * The observable state of an [Entity] within the simulation is provided by the context of the simulation. */ @Suppress("UNCHECKED_CAST") override val Entity.state: S @@ -227,20 +189,45 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator /** * Suspend the simulation kernel for n ticks before resuming the execution. * - * @param n The amount of ticks to suspend the simulation kernel. + * @param n The amount of ticks to suspend the simulation kernel, with n > 0 */ - suspend override fun wait(n: Int): Unit = suspendCoroutine { cont -> clock.scheduleAfter(n, { cont.resume(Unit) }) } + suspend override fun wait(n: Int) { + require(n > 0) { "The amount of ticks to suspend must be a non-zero positive number" } + return suspendCoroutine { cont -> + clock.scheduleAfter(n, { cont.resume(Unit) }) + } + } } /** - * The [Clock] for this [OmegaSimulator] that keeps track of the simulation time in ticks. + * An internal class to provide [Context] for an entity within the simulation. */ - private inner class OmegaClock : Clock { - override var tick: Tick = 0 - internal val queue: PriorityQueue Unit>> = PriorityQueue(Comparator.comparingLong { it.first }) + private inner class OmegaEntityContext>(override val component: Node) : OmegaAbstractContext>(), EntityContext { + /** + * Update the state of the entity being simulated. + * + *

Instead of directly mutating the entity, we create a new instance of the entity to prevent other objects + * referencing the old entity having their data changed. + * + * @param next The next state of the entity. + */ + suspend override fun , E : Entity, S> C.update(next: S) { + states.put(component.entity as Entity<*>, next) + } + } - override fun scheduleAt(tick: Tick, block: () -> Unit) { - queue.add(Pair(tick, block)) + /** + * An internal class to provide the [Context] for an edge kernel within the simulation. + */ + private inner class OmegaChannelContext(override val component: Edge) : OmegaAbstractContext>(), ChannelContext { + /** + * Send the given message downstream. + * + * @param msg The message to send. + * @param sender The sender of the message. + */ + suspend override fun send(msg: Any?, sender: Node<*>) { + TODO("not implemented") } } } diff --git a/opendc-core/src/main/kotlin/nl/atlarge/opendc/topology/machine/Machine.kt b/opendc-core/src/main/kotlin/nl/atlarge/opendc/topology/machine/Machine.kt index 95594e27..b313b78b 100644 --- a/opendc-core/src/main/kotlin/nl/atlarge/opendc/topology/machine/Machine.kt +++ b/opendc-core/src/main/kotlin/nl/atlarge/opendc/topology/machine/Machine.kt @@ -65,7 +65,7 @@ class Machine: Entity, Kernel> { val speed = cpus.fold(0, { acc, (speed, cores) -> acc + speed * cores }) val task: Task - val delay = Random().nextInt(1000) + val delay = Random().nextInt(1000) + 1 wait(delay) loop@while (true) { -- cgit v1.2.3