summaryrefslogtreecommitdiff
path: root/opendc-core/src/main
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2017-09-06 15:05:59 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2017-09-08 11:47:25 +0200
commit1a9cb7cfd2a67c32fd89d490f1462c59fa0d33b9 (patch)
tree93e6dfdb74399b9bbbd259ac32be9ad4fb7d7366 /opendc-core/src/main
parent823bb2d217e6b35b1811b5f52016d8d9de09435d (diff)
Refactor default Simulator implementation
This change refactors the default Simulator implementation, reformatting the code, adding input validation and extracting common code.
Diffstat (limited to 'opendc-core/src/main')
-rw-r--r--opendc-core/src/main/kotlin/nl/atlarge/opendc/simulator/omega/OmegaSimulator.kt119
-rw-r--r--opendc-core/src/main/kotlin/nl/atlarge/opendc/topology/machine/Machine.kt2
2 files changed, 54 insertions, 67 deletions
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<Unit> {
+class OmegaSimulator(override val topology: Topology) : Simulator, Iterator<Unit> {
/**
* The logger instance to use for the simulator.
*/
@@ -93,7 +93,7 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator<Unit>
* @param component The component to resolve.
* @return The [Kernel] that simulates that [Component].
*/
- fun <T: Component<*>> resolve(component: T): Context<T>? {
+ fun <T : Component<*>> resolve(component: T): Context<T>? {
@Suppress("UNCHECKED_CAST")
return registry.computeIfAbsent(component, {
if (component.label !is Kernel<*>)
@@ -138,7 +138,7 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator<Unit>
/**
* The co-routine which runs a simulation kernel.
*/
- private class KernelCoroutine: Continuation<Unit> {
+ private class KernelCoroutine : Continuation<Unit> {
override val context: CoroutineContext = EmptyCoroutineContext
override fun resume(value: Unit) {}
@@ -149,76 +149,38 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator<Unit>
}
/**
- * 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<out T: Entity<*>>(override val component: Node<T>): EntityContext<T> {
- /**
- * 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 <T> 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 <S> Entity<S>.state: S
- get() = states.computeIfAbsent(this, { initialState }) as S
+ private inner class OmegaClock : Clock {
+ override var tick: Tick = 0
+ internal val queue: PriorityQueue<Pair<Tick, () -> Unit>> = PriorityQueue(Comparator.comparingLong { it.first })
- /**
- * Update the state of the entity being simulated.
- *
- * <p>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 <C: EntityContext<E>, E: Entity<S>, 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 <code>n</code> 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<out T>(override val component: Edge<T>): ChannelContext<T> {
+ private abstract inner class OmegaAbstractContext<out T : Component<*>> : Context<T> {
/**
* 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 <T> 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 <T> 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 <S> Entity<S>.state: S
@@ -227,20 +189,45 @@ class OmegaSimulator(override val topology: Topology): Simulator, Iterator<Unit>
/**
* Suspend the simulation kernel for <code>n</code> 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 <code>n > 0</code>
*/
- 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<Pair<Tick, () -> Unit>> = PriorityQueue(Comparator.comparingLong { it.first })
+ private inner class OmegaEntityContext<out T : Entity<*>>(override val component: Node<T>) : OmegaAbstractContext<Node<T>>(), EntityContext<T> {
+ /**
+ * Update the state of the entity being simulated.
+ *
+ * <p>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 <C : EntityContext<E>, E : Entity<S>, 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<out T>(override val component: Edge<T>) : OmegaAbstractContext<Edge<T>>(), ChannelContext<T> {
+ /**
+ * 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<Machine.State>, Kernel<EntityContext<Machine>> {
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) {