diff options
71 files changed, 2389 insertions, 2390 deletions
diff --git a/.editorconfig b/.editorconfig index 29e7b14b..4b0abe4d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,7 +4,7 @@ root = true [*] -indent_style = tab +indent_style = space indent_size = 4 end_of_line = lf diff --git a/opendc-core/build.gradle b/opendc-core/build.gradle index 4a45b911..223e73f9 100644 --- a/opendc-core/build.gradle +++ b/opendc-core/build.gradle @@ -24,19 +24,19 @@ /* Build configuration */ buildscript { - ext.kotlin_version = '1.2.21' - ext.dokka_version = '0.9.15' + ext.kotlin_version = '1.2.21' + ext.dokka_version = '0.9.15' - repositories { - mavenCentral() - jcenter() - } + repositories { + mavenCentral() + jcenter() + } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' - } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' + } } apply plugin: 'java' @@ -45,26 +45,26 @@ apply plugin: 'org.jetbrains.dokka' apply plugin: 'org.junit.platform.gradle.plugin' compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } kotlin { - experimental { - coroutines 'enable' - } + experimental { + coroutines 'enable' + } } dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/javadoc" + outputFormat = 'html' + outputDirectory = "$buildDir/javadoc" } /* Project configuration */ @@ -72,13 +72,13 @@ group 'com.atlarge.opendc' version '1.1' repositories { - jcenter() + jcenter() } dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" - testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" - testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" + testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" + testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" + testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" } diff --git a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Bootstrap.kt b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Bootstrap.kt index 199e1701..10a89704 100644 --- a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Bootstrap.kt +++ b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Bootstrap.kt @@ -8,57 +8,57 @@ package com.atlarge.opendc.simulator * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Bootstrap<M> { - /** - * Bootstrap a model `M` for a kernel in the given context. - * - * @param context The context to bootstrap to model in. - * @return The initialised model for the simulation. - */ - fun bootstrap(context: Context<M>): M + /** + * Bootstrap a model `M` for a kernel in the given context. + * + * @param context The context to bootstrap to model in. + * @return The initialised model for the simulation. + */ + fun bootstrap(context: Context<M>): M - /** - * A context for the bootstrap of some model type `M` that allows the model to register the entities of the model to - * the simulation kernel. - * - * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) - */ - interface Context<out M> { - /** - * Register the given entity to the simulation kernel. - * - * @param entity The entity to register. - * @return `true` if the entity had not yet been registered, `false` otherwise. - */ - fun register(entity: Entity<*, M>): Boolean + /** + * A context for the bootstrap of some model type `M` that allows the model to register the entities of the model to + * the simulation kernel. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ + interface Context<out M> { + /** + * Register the given entity to the simulation kernel. + * + * @param entity The entity to register. + * @return `true` if the entity had not yet been registered, `false` otherwise. + */ + fun register(entity: Entity<*, M>): Boolean - /** - * Deregister the given entity from the simulation kernel. - * - * @param entity The entity to deregister. - * @return `true` if the entity had not yet been unregistered, `false` otherwise. - */ - fun deregister(entity: Entity<*, M>): Boolean + /** + * Deregister the given entity from the simulation kernel. + * + * @param entity The entity to deregister. + * @return `true` if the entity had not yet been unregistered, `false` otherwise. + */ + fun deregister(entity: Entity<*, M>): Boolean - /** - * Schedule a message for processing by a [Context]. - * - * @param message The message to schedule. - * @param destination The destination of the message. - * @param sender The sender of the message. - * @param delay The amount of time to wait before processing the message. - */ - fun schedule(message: Any, destination: Entity<*, *>, sender: Entity<*, *>? = null, delay: Duration = 0) - } + /** + * Schedule a message for processing by a [Context]. + * + * @param message The message to schedule. + * @param destination The destination of the message. + * @param sender The sender of the message. + * @param delay The amount of time to wait before processing the message. + */ + fun schedule(message: Any, destination: Entity<*, *>, sender: Entity<*, *>? = null, delay: Duration = 0) + } - companion object { - /** - * Create a [Bootstrap] procedure using the given block to produce a bootstrap for a model of type `M`. - * - * @param block The block to produce the bootstrap. - * @return The bootstrap procedure that has been built. - */ - fun <M> create(block: (Context<M>) -> M): Bootstrap<M> = object : Bootstrap<M> { - override fun bootstrap(context: Context<M>) = block(context) - } - } + companion object { + /** + * Create a [Bootstrap] procedure using the given block to produce a bootstrap for a model of type `M`. + * + * @param block The block to produce the bootstrap. + * @return The bootstrap procedure that has been built. + */ + fun <M> create(block: (Context<M>) -> M): Bootstrap<M> = object : Bootstrap<M> { + override fun bootstrap(context: Context<M>) = block(context) + } + } } diff --git a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Context.kt b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Context.kt index c4e906dd..c89bdb59 100644 --- a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Context.kt +++ b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Context.kt @@ -24,7 +24,7 @@ package com.atlarge.opendc.simulator -import java.util.Queue +import java.util.* /** * This interface provides a context for simulation of [Entity] instances, by defining the environment in which the @@ -34,123 +34,123 @@ import java.util.Queue * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Context<S, out M> { - /** - * The model of simulation in which the entity exists. - */ - val model: M - - /** - * The current point in simulation time. - */ - val time: Instant - - /** - * The duration between the current point in simulation time and the last point in simulation time where the - * [Entity] has done some work. This means the `run()` co-routine has been resumed. - */ - val delta: Duration - - /** - * The observable state of the entity bound to this scope. - */ - var state: S - - /** - * The observable state of an [Entity] in simulation, which is provided by the simulation context. - */ - val <E : Entity<S, *>, S> E.state: S - - /** - * Interrupt an [Entity] process in simulation. - * - * If an [Entity] process has been suspended, the suspending call will throw an [Interrupt] object as a result of - * this call. - * Make sure the [Entity] process actually has error handling in place, so it won't take down the whole [Entity] - * process as result of the interrupt. - */ - suspend fun Entity<*, *>.interrupt() - - /** - * Suspend the [Context] of the [Entity] in simulation for the given duration of simulation time before resuming - * execution and drop all messages that are received during this period. - * - * A call to this method will not make the [Context] sleep for the actual duration of time, but instead suspend - * the process until the no more messages at an earlier point in time have to be processed. - * - * @param duration The duration of simulation time to hold before resuming execution. - */ - suspend fun hold(duration: Duration) - - /** - * Suspend the [Context] of the [Entity] in simulation for the given duration of simulation time before resuming - * execution and push all messages that are received during this period to the given queue. - * - * A call to this method will not make the [Context] sleep for the actual duration of time, but instead suspend - * the process until the no more messages at an earlier point in time have to be processed. - * - * @param duration The duration of simulation time to wait before resuming execution. - * @param queue The mutable queue to push the messages to. - */ - suspend fun hold(duration: Duration, queue: Queue<Any>) - - /** - * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is - * empty. The execution is resumed after the head of the mailbox is removed after which the message [Envelope] is - * transformed through `transform` to return the transformed result. - * - * @param transform The block to transform the message with in an envelope context, providing access to the sender - * of the message. - * @return The transformed message. - */ - suspend fun <T> receive(transform: suspend Envelope<*>.(Any) -> T): T - - /** - * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is - * empty. The execution is either resumed after the head of the mailbox is removed after which the message - * [Envelope] is transformed through `transform` to return the transformed result or the timeout has been reached. - * - * @param timeout The duration to wait before resuming execution. - * @param transform The block to transform the message with in an envelope context, providing access to the sender - * of the message. - * @return The processed message or `null` if the timeout was reached. - */ - suspend fun <T> receive(timeout: Duration, transform: suspend Envelope<*>.(Any) -> T): T? - - /** - * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is - * empty. The execution is resumed after the head of the mailbox is removed and returned. - * - * @return The received message. - */ - suspend fun receive(): Any = receive { it } - - /** - * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is - * empty. The execution is either resumed after the head of the mailbox is removed and returned or when the timeout - * has been reached. - * - * @return The received message or `null` if the timeout was reached. - */ - suspend fun receive(timeout: Duration): Any? = receive(timeout) { it } - - /** - * Send the given message to the specified entity, without providing any guarantees about the actual delivery of - * the message. - * - * @param msg The message to send. - * @param delay The amount of time to wait before the message should be received by the entity. - */ - suspend fun Entity<*, *>.send(msg: Any, delay: Duration = 0) - - /** - * Send the given message to the specified entity, without providing any guarantees about the actual delivery of - * the message. - * - * @param msg The message to send. - * @param sender The sender of the message. - * @param delay The amount of time to wait before the message should be received by the entity. - */ - suspend fun Entity<*, *>.send(msg: Any, sender: Entity<*, *>, delay: Duration = 0) + /** + * The model of simulation in which the entity exists. + */ + val model: M + + /** + * The current point in simulation time. + */ + val time: Instant + + /** + * The duration between the current point in simulation time and the last point in simulation time where the + * [Entity] has done some work. This means the `run()` co-routine has been resumed. + */ + val delta: Duration + + /** + * The observable state of the entity bound to this scope. + */ + var state: S + + /** + * The observable state of an [Entity] in simulation, which is provided by the simulation context. + */ + val <E : Entity<S, *>, S> E.state: S + + /** + * Interrupt an [Entity] process in simulation. + * + * If an [Entity] process has been suspended, the suspending call will throw an [Interrupt] object as a result of + * this call. + * Make sure the [Entity] process actually has error handling in place, so it won't take down the whole [Entity] + * process as result of the interrupt. + */ + suspend fun Entity<*, *>.interrupt() + + /** + * Suspend the [Context] of the [Entity] in simulation for the given duration of simulation time before resuming + * execution and drop all messages that are received during this period. + * + * A call to this method will not make the [Context] sleep for the actual duration of time, but instead suspend + * the process until the no more messages at an earlier point in time have to be processed. + * + * @param duration The duration of simulation time to hold before resuming execution. + */ + suspend fun hold(duration: Duration) + + /** + * Suspend the [Context] of the [Entity] in simulation for the given duration of simulation time before resuming + * execution and push all messages that are received during this period to the given queue. + * + * A call to this method will not make the [Context] sleep for the actual duration of time, but instead suspend + * the process until the no more messages at an earlier point in time have to be processed. + * + * @param duration The duration of simulation time to wait before resuming execution. + * @param queue The mutable queue to push the messages to. + */ + suspend fun hold(duration: Duration, queue: Queue<Any>) + + /** + * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is + * empty. The execution is resumed after the head of the mailbox is removed after which the message [Envelope] is + * transformed through `transform` to return the transformed result. + * + * @param transform The block to transform the message with in an envelope context, providing access to the sender + * of the message. + * @return The transformed message. + */ + suspend fun <T> receive(transform: suspend Envelope<*>.(Any) -> T): T + + /** + * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is + * empty. The execution is either resumed after the head of the mailbox is removed after which the message + * [Envelope] is transformed through `transform` to return the transformed result or the timeout has been reached. + * + * @param timeout The duration to wait before resuming execution. + * @param transform The block to transform the message with in an envelope context, providing access to the sender + * of the message. + * @return The processed message or `null` if the timeout was reached. + */ + suspend fun <T> receive(timeout: Duration, transform: suspend Envelope<*>.(Any) -> T): T? + + /** + * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is + * empty. The execution is resumed after the head of the mailbox is removed and returned. + * + * @return The received message. + */ + suspend fun receive(): Any = receive { it } + + /** + * Retrieve and remove a single message from the instance's mailbox, suspending the function if the mailbox is + * empty. The execution is either resumed after the head of the mailbox is removed and returned or when the timeout + * has been reached. + * + * @return The received message or `null` if the timeout was reached. + */ + suspend fun receive(timeout: Duration): Any? = receive(timeout) { it } + + /** + * Send the given message to the specified entity, without providing any guarantees about the actual delivery of + * the message. + * + * @param msg The message to send. + * @param delay The amount of time to wait before the message should be received by the entity. + */ + suspend fun Entity<*, *>.send(msg: Any, delay: Duration = 0) + + /** + * Send the given message to the specified entity, without providing any guarantees about the actual delivery of + * the message. + * + * @param msg The message to send. + * @param sender The sender of the message. + * @param delay The amount of time to wait before the message should be received by the entity. + */ + suspend fun Entity<*, *>.send(msg: Any, sender: Entity<*, *>, delay: Duration = 0) } /** @@ -159,21 +159,21 @@ interface Context<S, out M> { * @param T The shape of the message inside the envelope. * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ -interface Envelope<out T: Any> { - /** - * The message in this envelope. - */ - val message: T - - /** - * The sender of the message. - */ - val sender: Entity<*, *>? - - /** - * The destination of the message. - */ - val destination: Entity<*, *> +interface Envelope<out T : Any> { + /** + * The message in this envelope. + */ + val message: T + + /** + * The sender of the message. + */ + val sender: Entity<*, *>? + + /** + * The destination of the message. + */ + val destination: Entity<*, *> } /** @@ -181,4 +181,4 @@ interface Envelope<out T: Any> { * * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ -object Interrupt: Throwable("The entity process has been interrupted by another entity") +object Interrupt : Throwable("The entity process has been interrupted by another entity") diff --git a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Entity.kt b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Entity.kt index 800f2f1d..56704c5d 100644 --- a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Entity.kt +++ b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Entity.kt @@ -37,8 +37,8 @@ package com.atlarge.opendc.simulator * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Entity<out S, in M> { - /** - * The initial state of the entity. - */ - val initialState: S + /** + * The initial state of the entity. + */ + val initialState: S } diff --git a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Process.kt b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Process.kt index 30280657..e8b4d988 100644 --- a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Process.kt +++ b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/Process.kt @@ -8,20 +8,20 @@ package com.atlarge.opendc.simulator * @param M The shape of the model in which the process exists. * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ -interface Process<S, in M>: Entity<S, M> { - /** - * This method is invoked to start the simulation a process. - * - * This method is assumed to be running during a simulation, but should hand back control to the simulator at - * some point by suspending the process. This allows other processes to do work at the current point in time of the - * simulation. - * Suspending the process can be achieved by calling suspending method in the context: - * - [Context.hold] - Hold for `n` units of time before resuming execution. - * - [Context.receive] - Wait for a message to be received in the mailbox of the [Entity] before resuming - * execution. - * - * If this method exits early, before the simulation has finished, the entity is assumed to be shutdown and its - * simulation will not run any further. - */ - suspend fun Context<S, M>.run() +interface Process<S, in M> : Entity<S, M> { + /** + * This method is invoked to start the simulation a process. + * + * This method is assumed to be running during a simulation, but should hand back control to the simulator at + * some point by suspending the process. This allows other processes to do work at the current point in time of the + * simulation. + * Suspending the process can be achieved by calling suspending method in the context: + * - [Context.hold] - Hold for `n` units of time before resuming execution. + * - [Context.receive] - Wait for a message to be received in the mailbox of the [Entity] before resuming + * execution. + * + * If this method exits early, before the simulation has finished, the entity is assumed to be shutdown and its + * simulation will not run any further. + */ + suspend fun Context<S, M>.run() } diff --git a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/Kernel.kt b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/Kernel.kt index 3eee0f67..29b3bdee 100644 --- a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/Kernel.kt +++ b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/Kernel.kt @@ -25,8 +25,8 @@ package com.atlarge.opendc.simulator.kernel import com.atlarge.opendc.simulator.Bootstrap -import com.atlarge.opendc.simulator.Instant import com.atlarge.opendc.simulator.Entity +import com.atlarge.opendc.simulator.Instant /** * A message based discrete event simulation kernel. @@ -41,39 +41,39 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Kernel<out M> { - /** - * The model in which the simulation runs. - */ - val model: M + /** + * The model in which the simulation runs. + */ + val model: M - /** - * The simulation time. - */ - var time: Instant + /** + * The simulation time. + */ + var time: Instant - /** - * The observable state of an [Entity] in simulation, which is provided by the simulation context. - */ - val <E : Entity<S, *>, S> E.state: S + /** + * The observable state of an [Entity] in simulation, which is provided by the simulation context. + */ + val <E : Entity<S, *>, S> E.state: S - /** - * Step through one cycle in the simulation. This method will process all events in a single tick, update the - * internal clock and then return the control to the user. - */ - fun step() + /** + * Step through one cycle in the simulation. This method will process all events in a single tick, update the + * internal clock and then return the control to the user. + */ + fun step() - /** - * Run a simulation over the specified model. - * This method will step through multiple cycles in the simulation until no more message exist in the queue. - */ - fun run() + /** + * Run a simulation over the specified model. + * This method will step through multiple cycles in the simulation until no more message exist in the queue. + */ + fun run() - /** - * Run a simulation over the specified model, stepping through cycles until the specified clock tick has - * occurred. The control is then handed back to the user. - * - * @param until The point in simulation time at which the simulation should be paused and the control is handed - * back to the user. - */ - fun run(until: Instant) + /** + * Run a simulation over the specified model, stepping through cycles until the specified clock tick has + * occurred. The control is then handed back to the user. + * + * @param until The point in simulation time at which the simulation should be paused and the control is handed + * back to the user. + */ + fun run(until: Instant) } diff --git a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/KernelFactory.kt b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/KernelFactory.kt index 93667eb8..30abb7ca 100644 --- a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/KernelFactory.kt +++ b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/kernel/KernelFactory.kt @@ -32,11 +32,11 @@ import com.atlarge.opendc.simulator.Bootstrap * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface KernelFactory { - /** - * Create a simulation over the given model facilitated by this simulation kernel. - * - * @param bootstrap The bootstrap procedure to bootstrap the simulation with. - * @return A [Kernel] instance to control the simulation. - */ - fun <M> create(bootstrap: Bootstrap<M>): Kernel<M> + /** + * Create a simulation over the given model facilitated by this simulation kernel. + * + * @param bootstrap The bootstrap procedure to bootstrap the simulation with. + * @return A [Kernel] instance to control the simulation. + */ + fun <M> create(bootstrap: Bootstrap<M>): Kernel<M> } diff --git a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/platform/Experiment.kt b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/platform/Experiment.kt index 88b606fd..92d56be1 100644 --- a/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/platform/Experiment.kt +++ b/opendc-core/src/main/kotlin/com/atlarge/opendc/simulator/platform/Experiment.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.simulator.platform -import com.atlarge.opendc.simulator.kernel.KernelFactory import com.atlarge.opendc.simulator.Duration +import com.atlarge.opendc.simulator.kernel.KernelFactory /** * A blueprint for a reproducible simulation in a pre-defined setting. @@ -33,20 +33,20 @@ import com.atlarge.opendc.simulator.Duration * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Experiment<out T> { - /** - * Run the experiment on the specified kernel implementation. - * - * @param factory The factory to create the simulation kernel with. - * @return The result of the experiment. - */ - fun run(factory: KernelFactory): T + /** + * Run the experiment on the specified kernel implementation. + * + * @param factory The factory to create the simulation kernel with. + * @return The result of the experiment. + */ + fun run(factory: KernelFactory): T - /** - * Run the experiment on the specified kernel implementation. - * - * @param factory The factory to create the simulation kernel with. - * @param timeout The maximum duration of the experiment before returning to the caller. - * @return The result of the experiment or `null`. - */ - fun run(factory: KernelFactory, timeout: Duration): T? + /** + * Run the experiment on the specified kernel implementation. + * + * @param factory The factory to create the simulation kernel with. + * @param timeout The maximum duration of the experiment before returning to the caller. + * @return The result of the experiment or `null`. + */ + fun run(factory: KernelFactory, timeout: Duration): T? } diff --git a/opendc-kernel-omega/build.gradle b/opendc-kernel-omega/build.gradle index 1ca00aa6..e02da931 100644 --- a/opendc-kernel-omega/build.gradle +++ b/opendc-kernel-omega/build.gradle @@ -24,19 +24,19 @@ /* Build configuration */ buildscript { - ext.kotlin_version = '1.2.21' - ext.dokka_version = '0.9.15' + ext.kotlin_version = '1.2.21' + ext.dokka_version = '0.9.15' - repositories { - mavenCentral() - jcenter() - } + repositories { + mavenCentral() + jcenter() + } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' - } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' + } } apply plugin: 'java' @@ -45,26 +45,26 @@ apply plugin: 'org.jetbrains.dokka' apply plugin: 'org.junit.platform.gradle.plugin' compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } kotlin { - experimental { - coroutines 'enable' - } + experimental { + coroutines 'enable' + } } dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/javadoc" + outputFormat = 'html' + outputDirectory = "$buildDir/javadoc" } /* Project configuration */ @@ -72,17 +72,17 @@ group 'com.atlarge.opendc' version '1.1' repositories { - jcenter() + jcenter() } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.2" compile project(':opendc-core') - compile "io.github.microutils:kotlin-logging:1.4.6" + compile "io.github.microutils:kotlin-logging:1.4.6" - testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" - testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" - testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" - testCompile "org.slf4j:slf4j-simple:1.7.25" + testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" + testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" + testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" + testCompile "org.slf4j:slf4j-simple:1.7.25" } diff --git a/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/MessageContainer.kt b/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/MessageContainer.kt index af13d1fd..32f27111 100644 --- a/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/MessageContainer.kt +++ b/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/MessageContainer.kt @@ -24,9 +24,9 @@ package com.atlarge.opendc.omega -import com.atlarge.opendc.simulator.Instant import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.simulator.Envelope +import com.atlarge.opendc.simulator.Instant /** * A wrapper around a message that has been scheduled for processing. @@ -38,11 +38,11 @@ import com.atlarge.opendc.simulator.Envelope * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ internal data class MessageContainer(override val message: Any, - val time: Instant, - override val sender: Entity<*, *>?, - override val destination: Entity<*, *>) : Envelope<Any> { - /** - * A flag to indicate the message has been canceled. - */ - internal var canceled: Boolean = false + val time: Instant, + override val sender: Entity<*, *>?, + override val destination: Entity<*, *>) : Envelope<Any> { + /** + * A flag to indicate the message has been canceled. + */ + internal var canceled: Boolean = false } diff --git a/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernel.kt b/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernel.kt index fb5ce24b..c729a63d 100644 --- a/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernel.kt +++ b/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernel.kt @@ -26,7 +26,6 @@ package com.atlarge.opendc.omega import com.atlarge.opendc.simulator.* import com.atlarge.opendc.simulator.kernel.Kernel -import com.atlarge.opendc.simulator.Bootstrap import mu.KotlinLogging import java.util.* import kotlin.coroutines.experimental.* @@ -41,275 +40,275 @@ import kotlin.coroutines.experimental.* * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ internal class OmegaKernel<M>(bootstrap: Bootstrap<M>) : Kernel<M>, Bootstrap.Context<M> { - /** - * The logger instance to use for the simulator. - */ - private val logger = KotlinLogging.logger {} - - /** - * The registry of the simulation kernels used in the experiment. - */ - private val registry: MutableMap<Entity<*, *>, OmegaContext<*>> = HashMap() - - /** - * The message queue. - */ - private val queue: Queue<MessageContainer> = PriorityQueue(Comparator.comparingLong(MessageContainer::time)) - - /** - * The simulation time. - */ - override var time: Instant = 0 - - /** - * The model of simulation. - */ - override val model: M = bootstrap.bootstrap(this) - - override val <E : Entity<S, *>, S> E.state: S - get() = context?.state ?: initialState - - /** - * The context associated with an [Entity]. - */ - @Suppress("UNCHECKED_CAST") - private val <E : Entity<S, M>, S, M> E.context: OmegaContext<S>? - get() = registry[this] as? OmegaContext<S> - - override fun register(entity: Entity<*, M>): Boolean { - if (!registry.containsKey(entity) && entity !is Process) { - return false - } - - @Suppress("UNCHECKED_CAST") - val process = entity as Process<Any, M> - val context = OmegaContext(entity).also { registry.put(entity, it) } - - // Bootstrap the process coroutine - val block: suspend () -> Unit = { process.run { context.run() } } - block.startCoroutine(context) - - return true - } - - override fun deregister(entity: Entity<*, M>): Boolean { - val context = entity.context ?: return false - context.resume(Unit) - return true - } - - override fun schedule(message: Any, destination: Entity<*, *>, sender: Entity<*, *>?, delay: Duration) = - schedule(prepare(message, destination, sender, delay)) - - override fun step() { - while (true) { - val envelope = queue.peek() ?: return - val delivery = envelope.time - - if (delivery > time) { - // Tick has yet to occur - // Jump in time to next event - time = delivery - break - } else if (delivery < time) { - // Tick has already occurred - logger.warn { "message processed out of order" } - } - - queue.poll() - - // If the sender has canceled the message, we move on to the next message - if (envelope.canceled) { - continue - } - - val context = envelope.destination.context ?: continue - - if (envelope.message !is Interrupt) { - context.continuation.resume(envelope) - } else { - context.continuation.resumeWithException(envelope.message) - } - - context.last = time - } - } - - - override fun run() { - while (queue.isNotEmpty()) { - step() - } - } - - override fun run(until: Instant) { - require(until > 0) { "The given instant must be a non-zero positive number" } - - if (time >= until) { - return - } - - while (time < until && queue.isNotEmpty()) { - step() - } - - // Fix clock if step() jumped too far in time to give the impression to the user that simulation stopped at - // exactly the tick it gave. This has not effect on the actual simulation results as the next call to run() will - // just jump forward again. - if (time > until) { - time = until - } - } - - private fun schedule(envelope: MessageContainer) { - queue.add(envelope) - } - - private fun prepare(message: Any, destination: Entity<*, *>, sender: Entity<*, *>? = null, - delay: Duration): MessageContainer { - require(delay >= 0) { "The amount of time to delay the message must be a positive number" } - return MessageContainer(message, time + delay, sender, destination) - } - - /** - * This internal class provides the default implementation for the [Context] interface for this simulator. - */ - private inner class OmegaContext<S>(val process: Process<S, M>) : Context<S, M>, Continuation<Unit> { - /** - * The continuation to resume the execution of the process. - */ - lateinit var continuation: Continuation<Envelope<*>> - - /** - * The last point in time the process has done some work. - */ - var last: Instant = -1 - - /** - * The model in which the process exists. - */ - override val model: M - get() = this@OmegaKernel.model - - /** - * The state of the entity. - */ - override var state: S = process.initialState - - /** - * The current point in simulation time. - */ - override val time: Instant - get() = this@OmegaKernel.time - - /** - * The duration between the current point in simulation time and the last point in simulation time where the - * [Context] has executed some work. - */ - override val delta: Duration - get() = maxOf(time - last, 0) - - /** - * The [CoroutineContext] for a [Context]. - */ - override val context: CoroutineContext = EmptyCoroutineContext - - /** - * The observable state of an [Entity] within the simulation is provided by the context of the simulation. - */ - override val <T : Entity<S, *>, S> T.state: S - get() = context?.state ?: initialState - - /** - * Retrieve and remove and single message from the mailbox of the [Entity] and suspend the [Context] until the - * message has been received. - * - * @return The envelope containing the message. - */ - suspend fun receiveEnvelope(): Envelope<*> = suspendCoroutine { continuation = it } - - suspend override fun <T> receive(transform: suspend Envelope<*>.(Any) -> T): T { - val envelope = receiveEnvelope() - return transform(envelope, envelope.message) - } - - - suspend override fun <T> receive(timeout: Duration, transform: suspend Envelope<*>.(Any) -> T): T? { - val send = prepare(Timeout, process, process, timeout).also { schedule(it) } - - try { - val received = receiveEnvelope() - - if (received.message !is Timeout) { - send.canceled = true - return transform(received, received.message) - } - - return null - } finally { - send.canceled = true - } - } - - suspend override fun Entity<*, *>.send(msg: Any, delay: Duration) = send(msg, process, delay) - - suspend override fun Entity<*, *>.send(msg: Any, sender: Entity<*, *>, delay: Duration) = - schedule(prepare(msg, sender, delay = delay)) - - suspend override fun Entity<*, *>.interrupt() = send(Interrupt) - - suspend override fun hold(duration: Duration) { - require(duration >= 0) { "The amount of time to hold must be a positive number" } - val envelope = prepare(Resume, process, process, duration).also { schedule(it) } - - try { - while (true) { - if (receive() is Resume) - return - } - } finally { - envelope.canceled = true - } - } - - suspend override fun hold(duration: Duration, queue: Queue<Any>) { - require(duration >= 0) { "The amount of time to hold must be a positive number" } - val envelope = prepare(Resume, process, process, duration).also { schedule(it) } - - try { - while (true) { - val msg = receive() - if (msg is Resume) - return - queue.add(msg) - } - } finally { - envelope.canceled = true - } - } - - - // Completion continuation implementation - /** - * Resume the execution of this continuation with the given value. - * - * @param value The value to resume with. - */ - override fun resume(value: Unit) { - // Deregister process from registry in order to have the GC collect this context - registry.remove(process) - } - - /** - * Resume the execution of this continuation with an exception. - * - * @param exception The exception to resume with. - */ - override fun resumeWithException(exception: Throwable) { - // Deregister process from registry in order to have the GC collect this context:w - registry.remove(process) - - logger.error(exception) { "An exception occurred during the execution of a process" } - } - } + /** + * The logger instance to use for the simulator. + */ + private val logger = KotlinLogging.logger {} + + /** + * The registry of the simulation kernels used in the experiment. + */ + private val registry: MutableMap<Entity<*, *>, OmegaContext<*>> = HashMap() + + /** + * The message queue. + */ + private val queue: Queue<MessageContainer> = PriorityQueue(Comparator.comparingLong(MessageContainer::time)) + + /** + * The simulation time. + */ + override var time: Instant = 0 + + /** + * The model of simulation. + */ + override val model: M = bootstrap.bootstrap(this) + + override val <E : Entity<S, *>, S> E.state: S + get() = context?.state ?: initialState + + /** + * The context associated with an [Entity]. + */ + @Suppress("UNCHECKED_CAST") + private val <E : Entity<S, M>, S, M> E.context: OmegaContext<S>? + get() = registry[this] as? OmegaContext<S> + + override fun register(entity: Entity<*, M>): Boolean { + if (!registry.containsKey(entity) && entity !is Process) { + return false + } + + @Suppress("UNCHECKED_CAST") + val process = entity as Process<Any, M> + val context = OmegaContext(entity).also { registry[entity] = it } + + // Bootstrap the process coroutine + val block: suspend () -> Unit = { process.run { context.run() } } + block.startCoroutine(context) + + return true + } + + override fun deregister(entity: Entity<*, M>): Boolean { + val context = entity.context ?: return false + context.resume(Unit) + return true + } + + override fun schedule(message: Any, destination: Entity<*, *>, sender: Entity<*, *>?, delay: Duration) = + schedule(prepare(message, destination, sender, delay)) + + override fun step() { + while (true) { + val envelope = queue.peek() ?: return + val delivery = envelope.time + + if (delivery > time) { + // Tick has yet to occur + // Jump in time to next event + time = delivery + break + } else if (delivery < time) { + // Tick has already occurred + logger.warn { "message processed out of order" } + } + + queue.poll() + + // If the sender has canceled the message, we move on to the next message + if (envelope.canceled) { + continue + } + + val context = envelope.destination.context ?: continue + + if (envelope.message !is Interrupt) { + context.continuation.resume(envelope) + } else { + context.continuation.resumeWithException(envelope.message) + } + + context.last = time + } + } + + + override fun run() { + while (queue.isNotEmpty()) { + step() + } + } + + override fun run(until: Instant) { + require(until > 0) { "The given instant must be a non-zero positive number" } + + if (time >= until) { + return + } + + while (time < until && queue.isNotEmpty()) { + step() + } + + // Fix clock if step() jumped too far in time to give the impression to the user that simulation stopped at + // exactly the tick it gave. This has not effect on the actual simulation results as the next call to run() will + // just jump forward again. + if (time > until) { + time = until + } + } + + private fun schedule(envelope: MessageContainer) { + queue.add(envelope) + } + + private fun prepare(message: Any, destination: Entity<*, *>, sender: Entity<*, *>? = null, + delay: Duration): MessageContainer { + require(delay >= 0) { "The amount of time to delay the message must be a positive number" } + return MessageContainer(message, time + delay, sender, destination) + } + + /** + * This internal class provides the default implementation for the [Context] interface for this simulator. + */ + private inner class OmegaContext<S>(val process: Process<S, M>) : Context<S, M>, Continuation<Unit> { + /** + * The continuation to resume the execution of the process. + */ + lateinit var continuation: Continuation<Envelope<*>> + + /** + * The last point in time the process has done some work. + */ + var last: Instant = -1 + + /** + * The model in which the process exists. + */ + override val model: M + get() = this@OmegaKernel.model + + /** + * The state of the entity. + */ + override var state: S = process.initialState + + /** + * The current point in simulation time. + */ + override val time: Instant + get() = this@OmegaKernel.time + + /** + * The duration between the current point in simulation time and the last point in simulation time where the + * [Context] has executed some work. + */ + override val delta: Duration + get() = maxOf(time - last, 0) + + /** + * The [CoroutineContext] for a [Context]. + */ + override val context: CoroutineContext = EmptyCoroutineContext + + /** + * The observable state of an [Entity] within the simulation is provided by the context of the simulation. + */ + override val <T : Entity<S, *>, S> T.state: S + get() = context?.state ?: initialState + + /** + * Retrieve and remove and single message from the mailbox of the [Entity] and suspend the [Context] until the + * message has been received. + * + * @return The envelope containing the message. + */ + suspend fun receiveEnvelope(): Envelope<*> = suspendCoroutine { continuation = it } + + override suspend fun <T> receive(transform: suspend Envelope<*>.(Any) -> T): T { + val envelope = receiveEnvelope() + return transform(envelope, envelope.message) + } + + + override suspend fun <T> receive(timeout: Duration, transform: suspend Envelope<*>.(Any) -> T): T? { + val send = prepare(Timeout, process, process, timeout).also { schedule(it) } + + try { + val received = receiveEnvelope() + + if (received.message == Timeout) { + send.canceled = true + return transform(received, received.message) + } + + return null + } finally { + send.canceled = true + } + } + + override suspend fun Entity<*, *>.send(msg: Any, delay: Duration) = send(msg, process, delay) + + override suspend fun Entity<*, *>.send(msg: Any, sender: Entity<*, *>, delay: Duration) = + schedule(prepare(msg, sender, delay = delay)) + + override suspend fun Entity<*, *>.interrupt() = send(Interrupt) + + override suspend fun hold(duration: Duration) { + require(duration >= 0) { "The amount of time to hold must be a positive number" } + val envelope = prepare(Resume, process, process, duration).also { schedule(it) } + + try { + while (true) { + if (receive() == Resume) + return + } + } finally { + envelope.canceled = true + } + } + + override suspend fun hold(duration: Duration, queue: Queue<Any>) { + require(duration >= 0) { "The amount of time to hold must be a positive number" } + val envelope = prepare(Resume, process, process, duration).also { schedule(it) } + + try { + while (true) { + val msg = receive() + if (msg == Resume) + return + queue.add(msg) + } + } finally { + envelope.canceled = true + } + } + + + // Completion continuation implementation + /** + * Resume the execution of this continuation with the given value. + * + * @param value The value to resume with. + */ + override fun resume(value: Unit) { + // Deregister process from registry in order to have the GC collect this context + registry.remove(process) + } + + /** + * Resume the execution of this continuation with an exception. + * + * @param exception The exception to resume with. + */ + override fun resumeWithException(exception: Throwable) { + // Deregister process from registry in order to have the GC collect this context:w + registry.remove(process) + + logger.error(exception) { "An exception occurred during the execution of a process" } + } + } } diff --git a/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernelFactory.kt b/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernelFactory.kt index dcad4dce..139cbd19 100644 --- a/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernelFactory.kt +++ b/opendc-kernel-omega/src/main/kotlin/com/atlarge/opendc/omega/OmegaKernelFactory.kt @@ -24,9 +24,9 @@ package com.atlarge.opendc.omega -import com.atlarge.opendc.simulator.kernel.KernelFactory -import com.atlarge.opendc.simulator.kernel.Kernel import com.atlarge.opendc.simulator.Bootstrap +import com.atlarge.opendc.simulator.kernel.Kernel +import com.atlarge.opendc.simulator.kernel.KernelFactory /** * The Omega simulation kernel is the reference simulation kernel implementation for the OpenDC Simulator core. @@ -37,11 +37,11 @@ import com.atlarge.opendc.simulator.Bootstrap * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ object OmegaKernelFactory : KernelFactory { - /** - * Create a simulation over the given model facilitated by this simulation kernel. - * - * @param bootstrap The bootstrap procedure to bootstrap the simulation with. - * @return A [Kernel] instance to control the simulation. - */ - override fun <M> create(bootstrap: Bootstrap<M>): Kernel<M> = OmegaKernel(bootstrap) + /** + * Create a simulation over the given model facilitated by this simulation kernel. + * + * @param bootstrap The bootstrap procedure to bootstrap the simulation with. + * @return A [Kernel] instance to control the simulation. + */ + override fun <M> create(bootstrap: Bootstrap<M>): Kernel<M> = OmegaKernel(bootstrap) } diff --git a/opendc-kernel-omega/src/test/kotlin/com/atlarge/opendc/omega/SmokeTest.kt b/opendc-kernel-omega/src/test/kotlin/com/atlarge/opendc/omega/SmokeTest.kt index b358d618..a1ec8e88 100644 --- a/opendc-kernel-omega/src/test/kotlin/com/atlarge/opendc/omega/SmokeTest.kt +++ b/opendc-kernel-omega/src/test/kotlin/com/atlarge/opendc/omega/SmokeTest.kt @@ -24,9 +24,9 @@ package com.atlarge.opendc.omega +import com.atlarge.opendc.simulator.Bootstrap import com.atlarge.opendc.simulator.Context import com.atlarge.opendc.simulator.Process -import com.atlarge.opendc.simulator.Bootstrap import org.junit.jupiter.api.Test /** @@ -35,82 +35,82 @@ import org.junit.jupiter.api.Test * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ internal class SmokeTest { - class EchoProcess : Process<Unit, Unit> { - override val initialState = Unit - suspend override fun Context<Unit, Unit>.run() { - while (true) { - receive { - sender?.send(message) - } - } - } - } + class EchoProcess : Process<Unit, Unit> { + override val initialState = Unit + override suspend fun Context<Unit, Unit>.run() { + while (true) { + receive { + sender?.send(message) + } + } + } + } - /** - * Run a large amount of simulations and test if any exceptions occur. - */ - @Test - fun smoke() { - val n = 1000 - val messages = 100 - val bootstrap: Bootstrap<Unit> = Bootstrap.create { ctx -> - repeat(n) { - EchoProcess().also { - ctx.register(it) + /** + * Run a large amount of simulations and test if any exceptions occur. + */ + @Test + fun smoke() { + val n = 1000 + val messages = 100 + val bootstrap: Bootstrap<Unit> = Bootstrap.create { ctx -> + repeat(n) { + EchoProcess().also { + ctx.register(it) - for (i in 1 until messages) { - ctx.schedule(i, it, delay = i.toLong()) - } - } - } - } - val kernel = OmegaKernelFactory.create(bootstrap) - kernel.run() - } + for (i in 1 until messages) { + ctx.schedule(i, it, delay = i.toLong()) + } + } + } + } + val kernel = OmegaKernelFactory.create(bootstrap) + kernel.run() + } - class NullProcess : Process<Unit, Unit> { - override val initialState = Unit - suspend override fun Context<Unit, Unit>.run() {} - } + class NullProcess : Process<Unit, Unit> { + override val initialState = Unit + override suspend fun Context<Unit, Unit>.run() {} + } - /** - * Test if the kernel allows sending messages to [Context] instances that have already stopped. - */ - @Test - fun `sending message to process that has gracefully stopped`() { - val process = NullProcess() - val bootstrap: Bootstrap<Unit> = Bootstrap.create { ctx -> - process.also { - ctx.register(it) - ctx.schedule(0, it) - } - } + /** + * Test if the kernel allows sending messages to [Context] instances that have already stopped. + */ + @Test + fun `sending message to process that has gracefully stopped`() { + val process = NullProcess() + val bootstrap: Bootstrap<Unit> = Bootstrap.create { ctx -> + process.also { + ctx.register(it) + ctx.schedule(0, it) + } + } - val kernel = OmegaKernelFactory.create(bootstrap) - kernel.run() - } + val kernel = OmegaKernelFactory.create(bootstrap) + kernel.run() + } - class CrashProcess : Process<Unit, Unit> { - override val initialState = Unit - suspend override fun Context<Unit, Unit>.run() { - TODO("This process should crash") - } - } + class CrashProcess : Process<Unit, Unit> { + override val initialState = Unit + override suspend fun Context<Unit, Unit>.run() { + TODO("This process should crash") + } + } - /** - * Test if the kernel allows sending messages to [Context] instances that have crashed. - */ - @Test - fun `sending message to process that has crashed`() { - val process = CrashProcess() - val bootstrap: Bootstrap<Unit> = Bootstrap.create { ctx -> - process.also { - ctx.register(it) - ctx.schedule(0, it) - } - } + /** + * Test if the kernel allows sending messages to [Context] instances that have crashed. + */ + @Test + fun `sending message to process that has crashed`() { + val process = CrashProcess() + val bootstrap: Bootstrap<Unit> = Bootstrap.create { ctx -> + process.also { + ctx.register(it) + ctx.schedule(0, it) + } + } - val kernel = OmegaKernelFactory.create(bootstrap) - kernel.run() - } + val kernel = OmegaKernelFactory.create(bootstrap) + kernel.run() + } } diff --git a/opendc-model-odc/core/build.gradle b/opendc-model-odc/core/build.gradle index ffd37db6..e423da50 100644 --- a/opendc-model-odc/core/build.gradle +++ b/opendc-model-odc/core/build.gradle @@ -24,19 +24,19 @@ /* Build configuration */ buildscript { - ext.kotlin_version = '1.2.21' - ext.dokka_version = '0.9.15' + ext.kotlin_version = '1.2.21' + ext.dokka_version = '0.9.15' - repositories { - mavenCentral() - jcenter() - } + repositories { + mavenCentral() + jcenter() + } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' - } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' + } } apply plugin: 'java' @@ -45,26 +45,26 @@ apply plugin: 'org.jetbrains.dokka' apply plugin: 'org.junit.platform.gradle.plugin' compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } kotlin { - experimental { - coroutines 'enable' - } + experimental { + coroutines 'enable' + } } dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/javadoc" + outputFormat = 'html' + outputDirectory = "$buildDir/javadoc" } /* Project configuration */ @@ -72,18 +72,18 @@ group 'com.atlarge.opendc' version '1.1' repositories { - jcenter() + jcenter() } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - compile project(':opendc-core') - compile project(':opendc-stdlib') - compile "io.github.microutils:kotlin-logging:1.4.6" + compile project(':opendc-core') + compile project(':opendc-stdlib') + compile "io.github.microutils:kotlin-logging:1.4.6" - testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" - testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" - testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" - testCompile "org.slf4j:slf4j-simple:1.7.25" + testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" + testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" + testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" + testCompile "org.slf4j:slf4j-simple:1.7.25" } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/OdcModel.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/OdcModel.kt index 01ffbd2c..298a14cf 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/OdcModel.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/OdcModel.kt @@ -7,4 +7,4 @@ import com.atlarge.opendc.model.topology.MutableTopology * * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ -interface OdcModel: MutableTopology +interface OdcModel : MutableTopology diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/FifoScheduler.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/FifoScheduler.kt index d2cbcdfe..e743586c 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/FifoScheduler.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/FifoScheduler.kt @@ -24,9 +24,9 @@ package com.atlarge.opendc.model.odc.platform.scheduler -import com.atlarge.opendc.simulator.Context import com.atlarge.opendc.model.odc.platform.workload.Task import com.atlarge.opendc.model.odc.topology.machine.Machine +import com.atlarge.opendc.simulator.Context import java.util.* /** @@ -35,84 +35,84 @@ import java.util.* * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ class FifoScheduler : Scheduler { - /** - * The name of this scheduler. - */ - override val name: String = "FIFO" + /** + * The name of this scheduler. + */ + override val name: String = "FIFO" - /** - * The set of machines the scheduler knows of. - */ - val machines: MutableSet<Machine> = HashSet() + /** + * The set of machines the scheduler knows of. + */ + private val machines: MutableSet<Machine> = HashSet() - /** - * The queue of [Task]s that need to be scheduled. - */ - val queue: Queue<Task> = ArrayDeque() + /** + * The queue of [Task]s that need to be scheduled. + */ + private val queue: Queue<Task> = ArrayDeque() - /** - * (Re)schedule the tasks submitted to the scheduler over the specified set of machines. - */ - override suspend fun <S, M> Context<S, M>.schedule() { - if (queue.isEmpty()) { - return - } + /** + * (Re)schedule the tasks submitted to the scheduler over the specified set of machines. + */ + override suspend fun <S, M> Context<S, M>.schedule() { + if (queue.isEmpty()) { + return + } - // The tasks that need to be rescheduled - val rescheduled = ArrayDeque<Task>() - val iterator = queue.iterator() + // The tasks that need to be rescheduled + val rescheduled = ArrayDeque<Task>() + val iterator = queue.iterator() - machines - .filter { it.state.status != Machine.Status.HALT } - .forEach { machine -> - while (iterator.hasNext()) { - val task = iterator.next() + machines + .filter { it.state.status != Machine.Status.HALT } + .forEach { machine -> + while (iterator.hasNext()) { + val task = iterator.next() - // TODO What to do with tasks that are not ready yet to be processed - if (!task.ready) { - iterator.remove() - rescheduled.add(task) - continue - } else if (task.finished) { - iterator.remove() - continue - } + // TODO What to do with tasks that are not ready yet to be processed + if (!task.ready) { + iterator.remove() + rescheduled.add(task) + continue + } else if (task.finished) { + iterator.remove() + continue + } - machine.send(task) - break - } - } + machine.send(task) + break + } + } - // Reschedule all tasks that are not ready yet - while (!rescheduled.isEmpty()) { - queue.add(rescheduled.poll()) - } - } + // Reschedule all tasks that are not ready yet + while (!rescheduled.isEmpty()) { + queue.add(rescheduled.poll()) + } + } - /** - * Submit a [Task] to this scheduler. - * - * @param task The task to submit to the scheduler. - */ - override fun submit(task: Task) { - queue.add(task) - } + /** + * Submit a [Task] to this scheduler. + * + * @param task The task to submit to the scheduler. + */ + override fun submit(task: Task) { + queue.add(task) + } - /** - * Register a [Machine] to this scheduler. - * - * @param machine The machine to register. - */ - override fun register(machine: Machine) { - machines.add(machine) - } + /** + * Register a [Machine] to this scheduler. + * + * @param machine The machine to register. + */ + override fun register(machine: Machine) { + machines.add(machine) + } - /** - * Deregister a [Machine] from this scheduler. - * - * @param machine The machine to deregister. - */ - override fun deregister(machine: Machine) { - machines.remove(machine) - } + /** + * Deregister a [Machine] from this scheduler. + * + * @param machine The machine to deregister. + */ + override fun deregister(machine: Machine) { + machines.remove(machine) + } } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/Scheduler.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/Scheduler.kt index ee965af9..79486ee6 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/Scheduler.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/Scheduler.kt @@ -24,10 +24,10 @@ package com.atlarge.opendc.model.odc.platform.scheduler -import com.atlarge.opendc.simulator.Context -import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.model.odc.platform.workload.Task import com.atlarge.opendc.model.odc.topology.machine.Machine +import com.atlarge.opendc.simulator.Context +import com.atlarge.opendc.simulator.Entity /** * A task scheduler that is coupled to an [Entity] in the topology of the cloud network. @@ -35,37 +35,37 @@ import com.atlarge.opendc.model.odc.topology.machine.Machine * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Scheduler { - /** - * The name of this scheduler. - */ - val name: String + /** + * The name of this scheduler. + */ + val name: String - /** - * (Re)schedule the tasks submitted to the scheduler over the specified set of machines. - * - * This method should be invoked at some interval to allow the scheduler to reschedule existing tasks and schedule - * new tasks. - */ - suspend fun <S, M> Context<S, M>.schedule() + /** + * (Re)schedule the tasks submitted to the scheduler over the specified set of machines. + * + * This method should be invoked at some interval to allow the scheduler to reschedule existing tasks and schedule + * new tasks. + */ + suspend fun <S, M> Context<S, M>.schedule() - /** - * Submit a [Task] to this scheduler. - * - * @param task The task to submit to the scheduler. - */ - fun submit(task: Task) + /** + * Submit a [Task] to this scheduler. + * + * @param task The task to submit to the scheduler. + */ + fun submit(task: Task) - /** - * Register a [Machine] to this scheduler. - * - * @param machine The machine to register. - */ - fun register(machine: Machine) + /** + * Register a [Machine] to this scheduler. + * + * @param machine The machine to register. + */ + fun register(machine: Machine) - /** - * Deregister a [Machine] from this scheduler. - * - * @param machine The machine to deregister. - */ - fun deregister(machine: Machine) + /** + * Deregister a [Machine] from this scheduler. + * + * @param machine The machine to deregister. + */ + fun deregister(machine: Machine) } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/SrtfScheduler.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/SrtfScheduler.kt index 0e497b56..d3f067df 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/SrtfScheduler.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/scheduler/SrtfScheduler.kt @@ -24,9 +24,9 @@ package com.atlarge.opendc.model.odc.platform.scheduler -import com.atlarge.opendc.simulator.Context import com.atlarge.opendc.model.odc.platform.workload.Task import com.atlarge.opendc.model.odc.topology.machine.Machine +import com.atlarge.opendc.simulator.Context import java.util.* /** @@ -35,76 +35,76 @@ import java.util.* * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ class SrtfScheduler : Scheduler { - /** - * The name of this scheduler. - */ - override val name: String = "SRTF" + /** + * The name of this scheduler. + */ + override val name: String = "SRTF" - /** - * The set of machines the scheduler knows of. - */ - val machines: MutableSet<Machine> = HashSet() + /** + * The set of machines the scheduler knows of. + */ + private val machines: MutableSet<Machine> = HashSet() - /** - * The set of [Task]s that need to be scheduled. - */ - val tasks: MutableSet<Task> = HashSet() + /** + * The set of [Task]s that need to be scheduled. + */ + private val tasks: MutableSet<Task> = HashSet() - /** - * (Re)schedule the tasks submitted to the scheduler over the specified set of machines. - */ - override suspend fun <S, M> Context<S, M>.schedule() { - if (tasks.isEmpty()) { - return - } + /** + * (Re)schedule the tasks submitted to the scheduler over the specified set of machines. + */ + override suspend fun <S, M> Context<S, M>.schedule() { + if (tasks.isEmpty()) { + return + } - val iterator = tasks.sortedBy { it.remaining }.iterator() + val iterator = tasks.sortedBy { it.remaining }.iterator() - machines - .filter { it.state.status != Machine.Status.HALT } - .forEach { machine -> - while (iterator.hasNext()) { - val task = iterator.next() + machines + .filter { it.state.status != Machine.Status.HALT } + .forEach { machine -> + while (iterator.hasNext()) { + val task = iterator.next() - // TODO What to do with tasks that are not ready yet to be processed - if (!task.ready) { - tasks.add(task) - continue - } else if (task.finished) { - tasks.remove(task) - continue - } + // TODO What to do with tasks that are not ready yet to be processed + if (!task.ready) { + tasks.add(task) + continue + } else if (task.finished) { + tasks.remove(task) + continue + } - machine.send(task) - break - } - } - } + machine.send(task) + break + } + } + } - /** - * Submit a [Task] to this scheduler. - * - * @param task The task to submit to the scheduler. - */ - override fun submit(task: Task) { - tasks.add(task) - } + /** + * Submit a [Task] to this scheduler. + * + * @param task The task to submit to the scheduler. + */ + override fun submit(task: Task) { + tasks.add(task) + } - /** - * Register a [Machine] to this scheduler. - * - * @param machine The machine to register. - */ - override fun register(machine: Machine) { - machines.add(machine) - } + /** + * Register a [Machine] to this scheduler. + * + * @param machine The machine to register. + */ + override fun register(machine: Machine) { + machines.add(machine) + } - /** - * Deregister a [Machine] from this scheduler. - * - * @param machine The machine to deregister. - */ - override fun deregister(machine: Machine) { - machines.remove(machine) - } + /** + * Deregister a [Machine] from this scheduler. + * + * @param machine The machine to deregister. + */ + override fun deregister(machine: Machine) { + machines.remove(machine) + } } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Job.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Job.kt index c42bb667..3e6c6821 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Job.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Job.kt @@ -30,24 +30,24 @@ package com.atlarge.opendc.model.odc.platform.workload * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Job { - /** - * A unique identifier of the job. - */ - val id: Int + /** + * A unique identifier of the job. + */ + val id: Int - /** - * The owner of this job. - */ - val owner: User + /** + * The owner of this job. + */ + val owner: User - /** - * The tasks this job consists of. - */ - val tasks: Set<Task> + /** + * The tasks this job consists of. + */ + val tasks: Set<Task> - /** - * A flag to indicate the job has finished. - */ - val finished: Boolean - get() = !tasks.any { !it.finished } + /** + * A flag to indicate the job has finished. + */ + val finished: Boolean + get() = !tasks.any { !it.finished } } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Task.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Task.kt index f7b9d60f..d68cceba 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Task.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Task.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.platform.workload -import com.atlarge.opendc.simulator.Instant import com.atlarge.opendc.model.odc.topology.machine.Machine +import com.atlarge.opendc.simulator.Instant /** * A task that runs as part of a [Job] on a [Machine]. @@ -33,60 +33,60 @@ import com.atlarge.opendc.model.odc.topology.machine.Machine * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Task { - /** - * The unique identifier of the task. - */ - val id: Int + /** + * The unique identifier of the task. + */ + val id: Int - /** - * The amount of flops for this task. - */ - val flops: Long + /** + * The amount of flops for this task. + */ + val flops: Long - /** - * The dependencies of the task. - */ - val dependencies: Set<Task> + /** + * The dependencies of the task. + */ + val dependencies: Set<Task> - /** - * A flag to indicate the task is parallelizable. - */ - val parallelizable: Boolean + /** + * A flag to indicate the task is parallelizable. + */ + val parallelizable: Boolean - /** - * The remaining flops for this task. - */ - val remaining: Long + /** + * The remaining flops for this task. + */ + val remaining: Long - /** - * The state of the task. - */ - val state: TaskState + /** + * The state of the task. + */ + val state: TaskState - /** - * A flag to indicate whether the task is ready to be started. - */ - val ready: Boolean - get() = !dependencies.any { !it.finished } + /** + * A flag to indicate whether the task is ready to be started. + */ + val ready: Boolean + get() = !dependencies.any { !it.finished } - /** - * A flag to indicate whether the task has finished. - */ - val finished: Boolean - get() = state is TaskState.Finished + /** + * A flag to indicate whether the task has finished. + */ + val finished: Boolean + get() = state is TaskState.Finished - /** - * This method is invoked when a task has arrived at a datacenter. - * - * @param time The moment in time the task has arrived at the datacenter. - */ - fun arrive(time: Instant) + /** + * This method is invoked when a task has arrived at a datacenter. + * + * @param time The moment in time the task has arrived at the datacenter. + */ + fun arrive(time: Instant) - /** - * Consume the given amount of flops of this task. - * - * @param time The current moment in time of the consumption. - * @param flops The total amount of flops to consume. - */ - fun consume(time: Instant, flops: Long) + /** + * Consume the given amount of flops of this task. + * + * @param time The current moment in time of the consumption. + * @param flops The total amount of flops to consume. + */ + fun consume(time: Instant, flops: Long) } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/TaskState.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/TaskState.kt index 2fb3acd9..78963ca3 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/TaskState.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/TaskState.kt @@ -33,40 +33,40 @@ import com.atlarge.opendc.simulator.Instant * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ sealed class TaskState { - /** - * A state to indicate the task has not yet arrived at the [Datacenter]. - */ - object Underway : TaskState() + /** + * A state to indicate the task has not yet arrived at the [Datacenter]. + */ + object Underway : TaskState() - /** - * A state to indicate the task has arrived at the [Datacenter]. - * - * @property at The moment in time the task has arrived. - */ - data class Queued(val at: Instant) : TaskState() + /** + * A state to indicate the task has arrived at the [Datacenter]. + * + * @property at The moment in time the task has arrived. + */ + data class Queued(val at: Instant) : TaskState() - /** - * A state to indicate the task has started running on a machine. - * - * @property previous The previous state of the task. - * @property at The moment in time the task started. - */ - data class Running(val previous: Queued, val at: Instant) : TaskState() + /** + * A state to indicate the task has started running on a machine. + * + * @property previous The previous state of the task. + * @property at The moment in time the task started. + */ + data class Running(val previous: Queued, val at: Instant) : TaskState() - /** - * A state to indicate the task has finished. - * - * @property previous The previous state of the task. - * @property at The moment in time the task finished. - */ - data class Finished(val previous: Running, val at: Instant) : TaskState() + /** + * A state to indicate the task has finished. + * + * @property previous The previous state of the task. + * @property at The moment in time the task finished. + */ + data class Finished(val previous: Running, val at: Instant) : TaskState() - /** - * A state to indicate the task has failed. - * - * @property previous The previous state of the task. - * @property at The moment in time the task failed. - * @property reason The reason of the failure. - */ - data class Failed(val previous: Running, val at: Instant, val reason: String) : TaskState() + /** + * A state to indicate the task has failed. + * + * @property previous The previous state of the task. + * @property at The moment in time the task failed. + * @property reason The reason of the failure. + */ + data class Failed(val previous: Running, val at: Instant, val reason: String) : TaskState() } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Trace.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Trace.kt index b2d65277..25bcad83 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Trace.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/Trace.kt @@ -30,8 +30,8 @@ package com.atlarge.opendc.model.odc.platform.workload * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Trace { - /** - * The [Job]s in the trace. - */ - val jobs: Set<Job> + /** + * The [Job]s in the trace. + */ + val jobs: Set<Job> } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/User.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/User.kt index 6099db3e..da696d88 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/User.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/platform/workload/User.kt @@ -33,13 +33,13 @@ package com.atlarge.opendc.model.odc.platform.workload * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface User { - /** - * The unique identifier of the user. - */ - val id: Int + /** + * The unique identifier of the user. + */ + val id: Int - /** - * The name of this user. - */ - val name: String + /** + * The name of this user. + */ + val name: String } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Datacenter.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Datacenter.kt index 2b682410..b9b804d3 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Datacenter.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Datacenter.kt @@ -24,16 +24,16 @@ package com.atlarge.opendc.model.odc.topology.container -import mu.KotlinLogging -import com.atlarge.opendc.simulator.Context -import com.atlarge.opendc.simulator.Duration -import com.atlarge.opendc.simulator.Entity -import com.atlarge.opendc.simulator.Process import com.atlarge.opendc.model.odc.platform.scheduler.Scheduler import com.atlarge.opendc.model.odc.platform.workload.Task import com.atlarge.opendc.model.odc.topology.machine.Machine import com.atlarge.opendc.model.topology.Topology import com.atlarge.opendc.model.topology.destinations +import com.atlarge.opendc.simulator.Context +import com.atlarge.opendc.simulator.Duration +import com.atlarge.opendc.simulator.Entity +import com.atlarge.opendc.simulator.Process +import mu.KotlinLogging import java.util.* /** @@ -44,59 +44,59 @@ import java.util.* * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Datacenter : Process<Unit, Topology> { - /** - * The task scheduler the datacenter uses. - */ - val scheduler: Scheduler + /** + * The task scheduler the datacenter uses. + */ + val scheduler: Scheduler - /** - * The interval at which task will be (re)scheduled. - */ - val interval: Duration + /** + * The interval at which task will be (re)scheduled. + */ + val interval: Duration - /** - * This method is invoked to start the simulation an [Entity] associated with this [Context]. - * - * This method is assumed to be running during a simulation, but should hand back control to the simulator at - * some point by suspending the process. This allows other processes to do work in the current tick of the - * simulation. - * Suspending the process can be achieved by calling suspending method in the context: - * - [Context.hold] - Wait for `n` amount of ticks before resuming execution. - * - [Context.receive] - Wait for a message to be received in the mailbox of the [Entity] before resuming - * execution. - * - * If this method exits early, before the simulation has finished, the entity is assumed to be shutdown and its - * simulation will not run any further. - */ - suspend override fun Context<Unit, Topology>.run() = model.run { - val logger = KotlinLogging.logger {} + /** + * This method is invoked to start the simulation an [Entity] associated with this [Context]. + * + * This method is assumed to be running during a simulation, but should hand back control to the simulator at + * some point by suspending the process. This allows other processes to do work in the current tick of the + * simulation. + * Suspending the process can be achieved by calling suspending method in the context: + * - [Context.hold] - Wait for `n` amount of ticks before resuming execution. + * - [Context.receive] - Wait for a message to be received in the mailbox of the [Entity] before resuming + * execution. + * + * If this method exits early, before the simulation has finished, the entity is assumed to be shutdown and its + * simulation will not run any further. + */ + override suspend fun Context<Unit, Topology>.run() = model.run { + val logger = KotlinLogging.logger {} - // The queue of messages to be processed after a cycle - val queue: Queue<Any> = ArrayDeque() - // Find all machines in the datacenter - val machines = outgoingEdges.destinations<Room>("room").asSequence() - .flatMap { it.outgoingEdges.destinations<Rack>("rack").asSequence() } - .flatMap { it.outgoingEdges.destinations<Machine>("machine").asSequence() }.toList() + // The queue of messages to be processed after a cycle + val queue: Queue<Any> = ArrayDeque() + // Find all machines in the datacenter + val machines = outgoingEdges.destinations<Room>("room").asSequence() + .flatMap { it.outgoingEdges.destinations<Rack>("rack").asSequence() } + .flatMap { it.outgoingEdges.destinations<Machine>("machine").asSequence() }.toList() - logger.info { "Initialising datacenter with ${machines.size} machines" } + logger.info { "Initialising datacenter with ${machines.size} machines" } - // Register all machines to the scheduler - machines.forEach(scheduler::register) + // Register all machines to the scheduler + machines.forEach(scheduler::register) - while (true) { - // Context all messages in the queue - while (queue.isNotEmpty()) { - val msg = queue.poll() - if (msg is Task) { - msg.arrive(time) - scheduler.submit(msg) - } - } - // (Re)schedule the tasks - scheduler.run { schedule() } + while (true) { + // Context all messages in the queue + while (queue.isNotEmpty()) { + val msg = queue.poll() + if (msg is Task) { + msg.arrive(time) + scheduler.submit(msg) + } + } + // (Re)schedule the tasks + scheduler.run { schedule() } - // Sleep a time quantum - hold(interval, queue) - } - } + // Sleep a time quantum + hold(interval, queue) + } + } } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Rack.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Rack.kt index 0ec43f9a..42fdc9cf 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Rack.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Rack.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.topology.container -import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.model.topology.Topology +import com.atlarge.opendc.simulator.Entity /** * A type of physical steel and electronic framework that is designed to house servers, networking devices, cables and diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Room.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Room.kt index 50cfc3e6..5e07b0ce 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Room.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/container/Room.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.topology.container -import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.model.topology.Topology +import com.atlarge.opendc.simulator.Entity /** * A physical room in a datacenter with relationships to the entities within the room. diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/Machine.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/Machine.kt index 4f4ce645..642723f5 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/Machine.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/Machine.kt @@ -24,12 +24,12 @@ package com.atlarge.opendc.model.odc.topology.machine -import com.atlarge.opendc.simulator.Context -import com.atlarge.opendc.simulator.Process import com.atlarge.opendc.model.odc.platform.workload.Task import com.atlarge.opendc.model.topology.Topology import com.atlarge.opendc.model.topology.destinations +import com.atlarge.opendc.simulator.Context import com.atlarge.opendc.simulator.Duration +import com.atlarge.opendc.simulator.Process import mu.KotlinLogging /** @@ -39,85 +39,85 @@ import mu.KotlinLogging * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ open class Machine : Process<Machine.State, Topology> { - /** - * The logger instance to use for the simulator. - */ - private val logger = KotlinLogging.logger {} + /** + * The logger instance to use for the simulator. + */ + private val logger = KotlinLogging.logger {} - /** - * The status of a machine. - */ - enum class Status { - HALT, IDLE, RUNNING - } + /** + * The status of a machine. + */ + enum class Status { + HALT, IDLE, RUNNING + } - /** - * The shape of the state of a [Machine] entity. - * - * @property status The status of the machine. - * @property task The task assign to the machine. - * @property memory The memory usage of the machine (defaults to 50mb for the kernel) - * @property load The load on the machine (defaults to 0.0) - * @property temperature The temperature of the machine (defaults to 23 degrees Celcius) - */ - data class State(val status: Status, - val task: Task? = null, - val memory: Int = 50, - val load: Double = 0.0, - val temperature: Double = 23.0) + /** + * The shape of the state of a [Machine] entity. + * + * @property status The status of the machine. + * @property task The task assign to the machine. + * @property memory The memory usage of the machine (defaults to 50mb for the kernel) + * @property load The load on the machine (defaults to 0.0) + * @property temperature The temperature of the machine (defaults to 23 degrees Celcius) + */ + data class State(val status: Status, + val task: Task? = null, + val memory: Int = 50, + val load: Double = 0.0, + val temperature: Double = 23.0) - /** - * The initial state of a [Machine] entity. - */ - override val initialState = State(Status.HALT) + /** + * The initial state of a [Machine] entity. + */ + override val initialState = State(Status.HALT) - /** - * Run the simulation kernel for this entity. - */ - override suspend fun Context<State, Topology>.run() = model.run { - state = State(Status.IDLE) + /** + * Run the simulation kernel for this entity. + */ + override suspend fun Context<State, Topology>.run() = model.run { + state = State(Status.IDLE) - val interval: Duration = 10 - val cpus = outgoingEdges.destinations<Cpu>("cpu") - val speed = cpus.fold(0, { acc, cpu -> acc + cpu.clockRate * cpu.cores }) + val interval: Duration = 10 + val cpus = outgoingEdges.destinations<Cpu>("cpu") + val speed = cpus.fold(0, { acc, cpu -> acc + cpu.clockRate * cpu.cores }) - // Halt the machine if it has not processing units (see bug #4) - if (cpus.isEmpty()) { - state = State(Status.HALT) - return - } + // Halt the machine if it has not processing units (see bug #4) + if (cpus.isEmpty()) { + state = State(Status.HALT) + return + } - var task: Task = receiveTask() - state = State(Status.RUNNING, task, load = 1.0, memory = state.memory + 50, temperature = 30.0) + var task: Task = receiveTask() + state = State(Status.RUNNING, task, load = 1.0, memory = state.memory + 50, temperature = 30.0) - while (true) { - if (task.finished) { - logger.info { "$id: Task ${task.id} finished. Machine idle at $time" } - state = State(Status.IDLE) - task = receiveTask() - } else { - task.consume(time, speed * delta) - } + while (true) { + if (task.finished) { + logger.info { "$id: Task ${task.id} finished. Machine idle at $time" } + state = State(Status.IDLE) + task = receiveTask() + } else { + task.consume(time, speed * delta) + } - // Check if we have received a new order in the meantime. - val msg = receive(interval) - if (msg is Task) { - task = msg - state = State(Status.RUNNING, task, load = 1.0, memory = state.memory + 50, temperature = 30.0) - } - } - } + // Check if we have received a new order in the meantime. + val msg = receive(interval) + if (msg is Task) { + task = msg + state = State(Status.RUNNING, task, load = 1.0, memory = state.memory + 50, temperature = 30.0) + } + } + } - /** - * Wait for a [Task] to be received by the [Context] and discard all other messages received in the meantime. - * - * @return The task that has been received. - */ - private suspend fun Context<State, Topology>.receiveTask(): Task { - while (true) { - val msg = receive() - if (msg is Task) - return msg - } - } + /** + * Wait for a [Task] to be received by the [Context] and discard all other messages received in the meantime. + * + * @return The task that has been received. + */ + private suspend fun Context<State, Topology>.receiveTask(): Task { + while (true) { + val msg = receive() + if (msg is Task) + return msg + } + } } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/ProcessingUnit.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/ProcessingUnit.kt index 0b8989de..e5d30173 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/ProcessingUnit.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/machine/ProcessingUnit.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.topology.machine -import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.model.topology.Topology +import com.atlarge.opendc.simulator.Entity /** * An interface representing a generic processing unit which is placed into a [Machine]. @@ -33,18 +33,18 @@ import com.atlarge.opendc.model.topology.Topology * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface ProcessingUnit : Entity<Unit, Topology> { - /** - * The speed of this [ProcessingUnit] per core in MHz. - */ - val clockRate: Int + /** + * The speed of this [ProcessingUnit] per core in MHz. + */ + val clockRate: Int - /** - * The amount of cores within this [ProcessingUnit]. - */ - val cores: Int + /** + * The amount of cores within this [ProcessingUnit]. + */ + val cores: Int - /** - * The energy consumption of this [ProcessingUnit] in Watt. - */ - val energyConsumption: Double + /** + * The energy consumption of this [ProcessingUnit] in Watt. + */ + val energyConsumption: Double } diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/network/NetworkUnit.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/network/NetworkUnit.kt index a41a8326..5ffc19bf 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/network/NetworkUnit.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/network/NetworkUnit.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.topology.network -import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.model.topology.Topology +import com.atlarge.opendc.simulator.Entity /** * A generic interface for a network unit in a cloud network. diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/power/PowerUnit.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/power/PowerUnit.kt index 8650b5dc..3e9248c4 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/power/PowerUnit.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/power/PowerUnit.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.topology.power -import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.model.topology.Topology +import com.atlarge.opendc.simulator.Entity /** * An [Entity] which provides power for other entities a cloud network to run. diff --git a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/storage/StorageUnit.kt b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/storage/StorageUnit.kt index b5bb4dfb..eb622f2c 100644 --- a/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/storage/StorageUnit.kt +++ b/opendc-model-odc/core/src/main/kotlin/com/atlarge/opendc/model/odc/topology/storage/StorageUnit.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.topology.storage -import com.atlarge.opendc.simulator.Entity import com.atlarge.opendc.model.topology.Topology +import com.atlarge.opendc.simulator.Entity /** * A generic interface for a storage unit in a cloud network. diff --git a/opendc-model-odc/jpa/build.gradle b/opendc-model-odc/jpa/build.gradle index d312f89d..191ca787 100644 --- a/opendc-model-odc/jpa/build.gradle +++ b/opendc-model-odc/jpa/build.gradle @@ -24,20 +24,20 @@ /* Build configuration */ buildscript { - ext.kotlin_version = '1.2.21' - ext.dokka_version = '0.9.15' + ext.kotlin_version = '1.2.21' + ext.dokka_version = '0.9.15' - repositories { - mavenCentral() - jcenter() - } + repositories { + mavenCentral() + jcenter() + } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-RC3' - } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-RC3' + } } apply plugin: 'java' @@ -47,26 +47,26 @@ apply plugin: 'org.jetbrains.dokka' apply plugin: 'org.junit.platform.gradle.plugin' compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } kotlin { - experimental { - coroutines 'enable' - } + experimental { + coroutines 'enable' + } } dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/javadoc" + outputFormat = 'html' + outputDirectory = "$buildDir/javadoc" } /* Project configuration */ @@ -74,18 +74,18 @@ group 'com.atlarge.opendc' version '1.1' repositories { - jcenter() + jcenter() } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - compile project(':opendc-core') - compile project(':opendc-stdlib') - compile project(':opendc-model-odc:core') - compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final' + compile project(':opendc-core') + compile project(':opendc-stdlib') + compile project(':opendc-model-odc:core') + compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final' - testCompile 'org.junit.jupiter:junit-jupiter-api:5.0.0-RC3' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3' - testCompile 'org.junit.platform:junit-platform-launcher:1.0.0-RC3' + testCompile 'org.junit.jupiter:junit-jupiter-api:5.0.0-RC3' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3' + testCompile 'org.junit.platform:junit-platform-launcher:1.0.0-RC3' } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaBootstrap.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaBootstrap.kt index 10fc54b5..09d8f4b3 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaBootstrap.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaBootstrap.kt @@ -1,10 +1,10 @@ package com.atlarge.opendc.model.odc -import com.atlarge.opendc.simulator.Bootstrap import com.atlarge.opendc.model.odc.integration.jpa.schema.Experiment import com.atlarge.opendc.model.odc.integration.jpa.schema.Task import com.atlarge.opendc.model.odc.topology.JpaTopologyFactory import com.atlarge.opendc.model.topology.bootstrap +import com.atlarge.opendc.simulator.Bootstrap /** * A [Bootstrap] procedure for experiments retrieved from a JPA data store. @@ -12,33 +12,33 @@ import com.atlarge.opendc.model.topology.bootstrap * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ class JpaBootstrap(val experiment: Experiment) : Bootstrap<JpaModel> { - /** - * Bootstrap a model `M` for a kernel in the given context. - * - * @param context The context to bootstrap to model in. - * @return The initialised model for the simulation. - */ - override fun bootstrap(context: Bootstrap.Context<JpaModel>): JpaModel { - val section = experiment.path.sections.first() + /** + * Bootstrap a model `M` for a kernel in the given context. + * + * @param context The context to bootstrap to model in. + * @return The initialised model for the simulation. + */ + override fun bootstrap(context: Bootstrap.Context<JpaModel>): JpaModel { + val section = experiment.path.sections.first() - // TODO We should not modify parts of the experiment in a bootstrap as the bootstrap should be reproducible. - // Important: initialise the scheduler of the datacenter - section.datacenter.scheduler = experiment.scheduler + // TODO We should not modify parts of the experiment in a bootstrap as the bootstrap should be reproducible. + // Important: initialise the scheduler of the datacenter + section.datacenter.scheduler = experiment.scheduler - val topology = JpaTopologyFactory(section) - .create() - .bootstrap() - .bootstrap(context) - val trace = experiment.trace - val tasks = trace.jobs.flatMap { it.tasks } + val topology = JpaTopologyFactory(section) + .create() + .bootstrap() + .bootstrap(context) + val trace = experiment.trace + val tasks = trace.jobs.flatMap { it.tasks } - // Schedule all messages in the trace - tasks.forEach { task -> - if (task is Task) { - context.schedule(task, section.datacenter, delay = task.startTime) - } - } + // Schedule all messages in the trace + tasks.forEach { task -> + if (task is Task) { + context.schedule(task, section.datacenter, delay = task.startTime) + } + } - return JpaModel(experiment, topology) - } + return JpaModel(experiment, topology) + } } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaModel.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaModel.kt index 6b12a68a..44c1fb69 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaModel.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/JpaModel.kt @@ -10,5 +10,5 @@ import com.atlarge.opendc.model.topology.MutableTopology * @property topology The topology the simulation runs on. * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ -data class JpaModel(val experiment: Experiment, val topology: MutableTopology): OdcModel, MutableTopology by topology +data class JpaModel(val experiment: Experiment, val topology: MutableTopology) : OdcModel, MutableTopology by topology diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/Jpa.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/Jpa.kt index 4f683f65..cb3181f8 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/Jpa.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/Jpa.kt @@ -32,7 +32,7 @@ import javax.persistence.EntityManager * @param block The block to execute in the transaction. */ inline fun EntityManager.transaction(block: () -> Unit) { - transaction.begin() - block() - transaction.commit() + transaction.begin() + block() + transaction.commit() } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/ParallelizableConverter.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/ParallelizableConverter.kt index c1123490..e9635b2e 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/ParallelizableConverter.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/ParallelizableConverter.kt @@ -33,30 +33,30 @@ import javax.persistence.AttributeConverter * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ class ParallelizableConverter : AttributeConverter<Boolean, String> { - /** - * Converts the data stored in the database column into the - * value to be stored in the entity attribute. - * Note that it is the responsibility of the converter writer to - * specify the correct dbData type for the corresponding column - * for use by the JDBC driver: i.e., persistence providers are - * not expected to do such type conversion. - * - * @param dbData the data from the database column to be converted - * @return the converted value to be stored in the entity attribute - */ - override fun convertToEntityAttribute(dbData: String?): Boolean = when(dbData?.toUpperCase()) { - "SEQUENTIAL" -> false - "PARALLEL" -> true - else -> false - } + /** + * Converts the data stored in the database column into the + * value to be stored in the entity attribute. + * Note that it is the responsibility of the converter writer to + * specify the correct dbData type for the corresponding column + * for use by the JDBC driver: i.e., persistence providers are + * not expected to do such type conversion. + * + * @param dbData the data from the database column to be converted + * @return the converted value to be stored in the entity attribute + */ + override fun convertToEntityAttribute(dbData: String?): Boolean = when (dbData?.toUpperCase()) { + "SEQUENTIAL" -> false + "PARALLEL" -> true + else -> false + } - /** - * Converts the value stored in the entity attribute into the - * data representation to be stored in the database. - * - * @param attribute the entity attribute value to be converted - * @return the converted data to be stored in the database column - */ - override fun convertToDatabaseColumn(attribute: Boolean?): String = - if (attribute == true) "PARALLEL" else "SEQUENTIAL" + /** + * Converts the value stored in the entity attribute into the + * data representation to be stored in the database. + * + * @param attribute the entity attribute value to be converted + * @return the converted data to be stored in the database column + */ + override fun convertToDatabaseColumn(attribute: Boolean?): String = + if (attribute == true) "PARALLEL" else "SEQUENTIAL" } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/SchedulerConverter.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/SchedulerConverter.kt index 7c793cba..15f6a905 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/SchedulerConverter.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/converter/SchedulerConverter.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.integration.jpa.converter -import com.atlarge.opendc.model.odc.platform.scheduler.Scheduler import com.atlarge.opendc.model.odc.platform.scheduler.FifoScheduler +import com.atlarge.opendc.model.odc.platform.scheduler.Scheduler import com.atlarge.opendc.model.odc.platform.scheduler.SrtfScheduler import javax.persistence.AttributeConverter @@ -38,29 +38,29 @@ import javax.persistence.AttributeConverter * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ class SchedulerConverter : AttributeConverter<Scheduler, String> { - /** - * Converts the data stored in the database column into the - * value to be stored in the entity attribute. - * Note that it is the responsibility of the converter writer to - * specify the correct dbData type for the corresponding column - * for use by the JDBC driver: i.e., persistence providers are - * not expected to do such type conversion. - * - * @param dbData the data from the database column to be converted - * @return the converted value to be stored in the entity attribute - */ - override fun convertToEntityAttribute(dbData: String?): Scheduler = when(dbData?.toUpperCase()) { - "SRTF" -> SrtfScheduler() - else -> FifoScheduler() - } + /** + * Converts the data stored in the database column into the + * value to be stored in the entity attribute. + * Note that it is the responsibility of the converter writer to + * specify the correct dbData type for the corresponding column + * for use by the JDBC driver: i.e., persistence providers are + * not expected to do such type conversion. + * + * @param dbData the data from the database column to be converted + * @return the converted value to be stored in the entity attribute + */ + override fun convertToEntityAttribute(dbData: String?): Scheduler = when (dbData?.toUpperCase()) { + "SRTF" -> SrtfScheduler() + else -> FifoScheduler() + } - /** - * Converts the value stored in the entity attribute into the - * data representation to be stored in the database. - * - * @param attribute the entity attribute value to be converted - * @return the converted data to be stored in the database column - */ - override fun convertToDatabaseColumn(attribute: Scheduler?): String = - attribute?.name?.toUpperCase() ?: "FIFO" + /** + * Converts the value stored in the entity attribute into the + * data representation to be stored in the database. + * + * @param attribute the entity attribute value to be converted + * @return the converted data to be stored in the database column + */ + override fun convertToDatabaseColumn(attribute: Scheduler?): String = + attribute?.name?.toUpperCase() ?: "FIFO" } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Cpu.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Cpu.kt index 98a51401..11553477 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Cpu.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Cpu.kt @@ -42,17 +42,17 @@ import javax.persistence.Entity */ @Entity data class Cpu( - val id: Int, - val manufacturer: String, - val family: String, - val generation: String, - val model: String, - override val clockRate: Int, - override val cores: Int, - override val energyConsumption: Double + val id: Int, + val manufacturer: String, + val family: String, + val generation: String, + val model: String, + override val clockRate: Int, + override val cores: Int, + override val energyConsumption: Double ) : Cpu { - /** - * The initial state of the entity. - */ - override val initialState = Unit + /** + * The initial state of the entity. + */ + override val initialState = Unit } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Datacenter.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Datacenter.kt index 8dcc1fc5..e65eef8b 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Datacenter.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Datacenter.kt @@ -24,9 +24,9 @@ package com.atlarge.opendc.model.odc.integration.jpa.schema -import com.atlarge.opendc.simulator.Duration import com.atlarge.opendc.model.odc.platform.scheduler.Scheduler import com.atlarge.opendc.model.odc.topology.container.Datacenter +import com.atlarge.opendc.simulator.Duration import javax.persistence.Entity /** @@ -38,29 +38,29 @@ import javax.persistence.Entity */ @Entity data class Datacenter( - val id: Int, - val rooms: Set<Room> -): Datacenter { - /** - * Construct a datacenter. We need this useless constructor in order for Kotlin correctly initialise the - * constant fields of the class. - */ - private constructor() : this(-1, emptySet()) + val id: Int, + val rooms: Set<Room> +) : Datacenter { + /** + * Construct a datacenter. We need this useless constructor in order for Kotlin correctly initialise the + * constant fields of the class. + */ + private constructor() : this(-1, emptySet()) - /** - * The task scheduler the datacenter uses. - */ - override lateinit var scheduler: Scheduler - internal set + /** + * The task scheduler the datacenter uses. + */ + override lateinit var scheduler: Scheduler + internal set - /** - * The interval at which task will be (re)scheduled. - * We set this to a fixed constant since the database provides no way of configuring this. - */ - override val interval: Duration = 10 + /** + * The interval at which task will be (re)scheduled. + * We set this to a fixed constant since the database provides no way of configuring this. + */ + override val interval: Duration = 10 - /** - * The initial state of the datacenter. - */ - override val initialState = Unit + /** + * The initial state of the datacenter. + */ + override val initialState = Unit } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Experiment.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Experiment.kt index 62a56bab..ce489b1f 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Experiment.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Experiment.kt @@ -24,8 +24,8 @@ package com.atlarge.opendc.model.odc.integration.jpa.schema -import com.atlarge.opendc.simulator.Instant import com.atlarge.opendc.model.odc.platform.scheduler.Scheduler +import com.atlarge.opendc.simulator.Instant import javax.persistence.Entity /** @@ -40,19 +40,19 @@ import javax.persistence.Entity */ @Entity data class Experiment( - val id: Int, - val name: String, - val scheduler: Scheduler, - val trace: Trace, - val path: Path + val id: Int, + val name: String, + val scheduler: Scheduler, + val trace: Trace, + val path: Path ) { - /** - * The state of the experiment. - */ - var state: ExperimentState = ExperimentState.QUEUED + /** + * The state of the experiment. + */ + var state: ExperimentState = ExperimentState.QUEUED - /** - * The last tick that has been simulated. - */ - var last: Instant = 0 + /** + * The last tick that has been simulated. + */ + var last: Instant = 0 } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/ExperimentState.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/ExperimentState.kt index 3e84707f..fecfe060 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/ExperimentState.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/ExperimentState.kt @@ -30,24 +30,24 @@ package com.atlarge.opendc.model.odc.integration.jpa.schema * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ enum class ExperimentState { - /** - * This state indicates the experiment has been queued for simulation, but has not yet started. - */ - QUEUED, + /** + * This state indicates the experiment has been queued for simulation, but has not yet started. + */ + QUEUED, - /** - * This state indicates the experiment has been claimed by a simulator for simulation, but - * not yet started. - */ - CLAIMED, + /** + * This state indicates the experiment has been claimed by a simulator for simulation, but + * not yet started. + */ + CLAIMED, - /** - * This state indicates the experiment is currently in simulation. - */ - SIMULATING, + /** + * This state indicates the experiment is currently in simulation. + */ + SIMULATING, - /** - * This state indicates the experiment has finished simulating. - */ - FINISHED, + /** + * This state indicates the experiment has finished simulating. + */ + FINISHED, } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Gpu.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Gpu.kt index 6b4f77a5..c04262cc 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Gpu.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Gpu.kt @@ -42,17 +42,17 @@ import javax.persistence.Entity */ @Entity data class Gpu( - val id: Int, - val manufacturer: String, - val family: String, - val generation: String, - val model: String, - override val clockRate: Int, - override val cores: Int, - override val energyConsumption: Double + val id: Int, + val manufacturer: String, + val family: String, + val generation: String, + val model: String, + override val clockRate: Int, + override val cores: Int, + override val energyConsumption: Double ) : Gpu { - /** - * The initial state of the entity. - */ - override val initialState = Unit + /** + * The initial state of the entity. + */ + override val initialState = Unit } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Job.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Job.kt index 192e345c..67ffba32 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Job.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Job.kt @@ -26,7 +26,7 @@ package com.atlarge.opendc.model.odc.integration.jpa.schema import com.atlarge.opendc.model.odc.platform.workload.Job import com.atlarge.opendc.model.odc.platform.workload.User -import javax.persistence.* +import javax.persistence.Entity /** * A [Job] backed by the JPA API and an underlying database connection. @@ -37,22 +37,22 @@ import javax.persistence.* */ @Entity data class Job( - override val id: Int, - override val tasks: Set<Task> + override val id: Int, + override val tasks: Set<Task> ) : Job { - /** - * The owner of the job, which is a singleton, since the database has no - * concept of ownership yet. - */ - override val owner: User = object : User { - /** + /** + * The owner of the job, which is a singleton, since the database has no + * concept of ownership yet. + */ + override val owner: User = object : User { + /** * The unique identifier of the user. */ - override val id: Int = 0 + override val id: Int = 0 - /** + /** * The name of this user. */ - override val name: String = "admin" - } + override val name: String = "admin" + } } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Machine.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Machine.kt index b1a2e428..925ab1d2 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Machine.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Machine.kt @@ -38,8 +38,8 @@ import javax.persistence.Entity */ @Entity data class Machine( - val id: Int, - val position: Int, - val cpus: Set<Cpu>, - val gpus: Set<Gpu> -): Machine() + val id: Int, + val position: Int, + val cpus: Set<Cpu>, + val gpus: Set<Gpu> +) : Machine() diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/MachineState.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/MachineState.kt index 3bd017bc..f3149adb 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/MachineState.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/MachineState.kt @@ -42,12 +42,12 @@ import javax.persistence.Entity */ @Entity data class MachineState( - val id: Int, - val machine: Machine, - val task: Task?, - val experiment: Experiment, - val time: Instant, - val temperature: Double, - val memoryUsage: Int, - val load: Double + val id: Int, + val machine: Machine, + val task: Task?, + val experiment: Experiment, + val time: Instant, + val temperature: Double, + val memoryUsage: Int, + val load: Double ) diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Path.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Path.kt index f24cf6a0..a6e915f3 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Path.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Path.kt @@ -35,6 +35,6 @@ import javax.persistence.Entity */ @Entity open class Path( - val id: Int, - val sections: List<Section> + val id: Int, + val sections: List<Section> ) diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Rack.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Rack.kt index 571c6e88..dd48480d 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Rack.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Rack.kt @@ -39,14 +39,14 @@ import javax.persistence.Entity */ @Entity class Rack( - id: Int, - val name: String, - val capacity: Int, - val powerCapacity: Int, - val machines: List<Machine> -): RoomObject(id), Rack { - /** - * The initial state of the entity. - */ - override val initialState = Unit + id: Int, + val name: String, + val capacity: Int, + val powerCapacity: Int, + val machines: List<Machine> +) : RoomObject(id), Rack { + /** + * The initial state of the entity. + */ + override val initialState = Unit } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Room.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Room.kt index 70f326c2..1a1c721f 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Room.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Room.kt @@ -38,13 +38,13 @@ import javax.persistence.Entity */ @Entity data class Room( - val id: Int, - val name: String, - val type: RoomType, - val objects: Set<RoomObject> -): Room { - /** - * The initial state of the entity. - */ - override val initialState = Unit + val id: Int, + val name: String, + val type: RoomType, + val objects: Set<RoomObject> +) : Room { + /** + * The initial state of the entity. + */ + override val initialState = Unit } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/RoomType.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/RoomType.kt index 574677da..ed0f89d3 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/RoomType.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/RoomType.kt @@ -30,5 +30,5 @@ package com.atlarge.opendc.model.odc.integration.jpa.schema * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ enum class RoomType { - COOLING, HALLWAY, OFFICE, POWER, SERVER + COOLING, HALLWAY, OFFICE, POWER, SERVER } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Section.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Section.kt index 79b2d74d..c6de2e50 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Section.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Section.kt @@ -39,7 +39,7 @@ import javax.persistence.Entity */ @Entity data class Section( - val id: Int, - val datacenter: Datacenter, - val startTime: Instant + val id: Int, + val datacenter: Datacenter, + val startTime: Instant ) diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Task.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Task.kt index 9379478f..4a296255 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Task.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Task.kt @@ -24,10 +24,11 @@ package com.atlarge.opendc.model.odc.integration.jpa.schema -import com.atlarge.opendc.simulator.Instant import com.atlarge.opendc.model.odc.platform.workload.Task import com.atlarge.opendc.model.odc.platform.workload.TaskState -import javax.persistence.* +import com.atlarge.opendc.simulator.Instant +import javax.persistence.Entity +import javax.persistence.PostLoad /** * A [Task] backed by the JPA API and an underlying database connection. @@ -41,77 +42,77 @@ import javax.persistence.* */ @Entity data class Task( - override val id: Int, - override val flops: Long, - private val dependency: Task?, - override val parallelizable: Boolean, - val startTime: Instant + override val id: Int, + override val flops: Long, + private val dependency: Task?, + override val parallelizable: Boolean, + val startTime: Instant ) : Task { - /** - * The dependencies of the task. - */ - override lateinit var dependencies: Set<Task> - private set + /** + * The dependencies of the task. + */ + override lateinit var dependencies: Set<Task> + private set - /** - * The remaining flops for this task. - */ - override var remaining: Long = 0 - private set + /** + * The remaining flops for this task. + */ + override var remaining: Long = 0 + private set - /** - * A flag to indicate whether the task has finished. - */ - override var finished: Boolean = false - private set + /** + * A flag to indicate whether the task has finished. + */ + override var finished: Boolean = false + private set - /** - * The state of the task. - */ - override lateinit var state: TaskState - private set + /** + * The state of the task. + */ + override lateinit var state: TaskState + private set - /** - * This method initialises the task object after it has been created by the JPA implementation. We use this - * initialisation method because JPA implementations only call the default constructor - */ - @PostLoad - internal fun init() { - remaining = flops - dependencies = dependency?.let(::setOf) ?: emptySet() - state = TaskState.Underway - } + /** + * This method initialises the task object after it has been created by the JPA implementation. We use this + * initialisation method because JPA implementations only call the default constructor + */ + @PostLoad + internal fun init() { + remaining = flops + dependencies = dependency?.let(::setOf) ?: emptySet() + state = TaskState.Underway + } - /** - * This method is invoked when a task has arrived at a datacenter. - * - * @param time The moment in time the task has arrived at the datacenter. - */ - override fun arrive(time: Instant) { - if (state !is TaskState.Underway) { - throw IllegalStateException("The task has already been submitted to a datacenter") - } - remaining = flops - state = TaskState.Queued(time) - } + /** + * This method is invoked when a task has arrived at a datacenter. + * + * @param time The moment in time the task has arrived at the datacenter. + */ + override fun arrive(time: Instant) { + if (state !is TaskState.Underway) { + throw IllegalStateException("The task has already been submitted to a datacenter") + } + remaining = flops + state = TaskState.Queued(time) + } - /** - * Consume the given amount of flops of this task. - * - * @param time The current moment in time of the consumption. - * @param flops The total amount of flops to consume. - */ - override fun consume(time: Instant, flops: Long) { - if (state is TaskState.Queued) { - state = TaskState.Running(state as TaskState.Queued, time) - } else if (finished) { - return - } - remaining -= flops - if (remaining <= 0) { - remaining = 0 - finished = true - state = TaskState.Finished(state as TaskState.Running, time) - } - } + /** + * Consume the given amount of flops of this task. + * + * @param time The current moment in time of the consumption. + * @param flops The total amount of flops to consume. + */ + override fun consume(time: Instant, flops: Long) { + if (state is TaskState.Queued) { + state = TaskState.Running(state as TaskState.Queued, time) + } else if (finished) { + return + } + remaining -= flops + if (remaining <= 0) { + remaining = 0 + finished = true + state = TaskState.Finished(state as TaskState.Running, time) + } + } } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/TaskState.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/TaskState.kt index dab8b345..6ab43b93 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/TaskState.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/TaskState.kt @@ -40,10 +40,10 @@ import javax.persistence.Entity */ @Entity data class TaskState( - val id: Int, - val task: Task, - val experiment: Experiment, - val time: Instant, - val remaining: Int, - val cores: Int + val id: Int, + val task: Task, + val experiment: Experiment, + val time: Instant, + val remaining: Int, + val cores: Int ) diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Trace.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Trace.kt index eddc1a03..e2ed78a2 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Trace.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/integration/jpa/schema/Trace.kt @@ -38,7 +38,7 @@ import javax.persistence.Entity */ @Entity data class Trace( - val id: Int, - val name: String, - override val jobs: Set<Job> + val id: Int, + val name: String, + override val jobs: Set<Job> ) : Trace diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperiment.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperiment.kt index 08e89c59..6c3ad5e8 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperiment.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperiment.kt @@ -24,24 +24,25 @@ package com.atlarge.opendc.model.odc.platform -import mu.KotlinLogging +import com.atlarge.opendc.model.odc.JpaBootstrap import com.atlarge.opendc.model.odc.integration.jpa.schema.ExperimentState import com.atlarge.opendc.model.odc.integration.jpa.schema.MachineState -import com.atlarge.opendc.model.odc.integration.jpa.schema.TaskState as InternalTaskState -import com.atlarge.opendc.model.odc.integration.jpa.schema.Trace as InternalTrace import com.atlarge.opendc.model.odc.integration.jpa.transaction -import com.atlarge.opendc.model.odc.integration.jpa.schema.Experiment as InternalExperiment -import com.atlarge.opendc.model.odc.integration.jpa.schema.Task as InternalTask -import com.atlarge.opendc.simulator.kernel.KernelFactory -import com.atlarge.opendc.simulator.Duration -import com.atlarge.opendc.model.odc.JpaBootstrap import com.atlarge.opendc.model.odc.platform.workload.TaskState import com.atlarge.opendc.model.odc.topology.container.Rack import com.atlarge.opendc.model.odc.topology.container.Room import com.atlarge.opendc.model.odc.topology.machine.Machine -import com.atlarge.opendc.simulator.platform.Experiment import com.atlarge.opendc.model.topology.destinations +import com.atlarge.opendc.simulator.Duration +import com.atlarge.opendc.simulator.kernel.KernelFactory +import com.atlarge.opendc.simulator.platform.Experiment +import mu.KotlinLogging +import java.io.Closeable import javax.persistence.EntityManager +import com.atlarge.opendc.model.odc.integration.jpa.schema.Experiment as InternalExperiment +import com.atlarge.opendc.model.odc.integration.jpa.schema.Task as InternalTask +import com.atlarge.opendc.model.odc.integration.jpa.schema.TaskState as InternalTaskState +import com.atlarge.opendc.model.odc.integration.jpa.schema.Trace as InternalTrace /** * An [Experiment] backed by the JPA API and an underlying database connection. @@ -51,129 +52,129 @@ import javax.persistence.EntityManager * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ class JpaExperiment(private val manager: EntityManager, - private val experiment: InternalExperiment): Experiment<Unit>, AutoCloseable { - /** - * The logging instance. - */ - private val logger = KotlinLogging.logger {} - - /** - * Run the experiment using the specified simulation kernel implementation. - * - * @param factory The simulation kernel implementation to use. - * @param timeout The maximum duration of the experiment before returning to the caller. - * @return The result of the experiment or `null`. - */ - override fun run(factory: KernelFactory, timeout: Duration): Unit? { - if (experiment.state != ExperimentState.CLAIMED) { - throw IllegalStateException("The experiment is in illegal state ${experiment.state}") - } - - // Set the simulation state - manager.transaction { - experiment.state = ExperimentState.SIMULATING - } - - val bootstrap = JpaBootstrap(experiment) - val simulation = factory.create(bootstrap) - val topology = simulation.model - - val section = experiment.path.sections.first() - val trace = experiment.trace - val tasks = trace.jobs.flatMap { it.tasks } - - // Find all machines in the datacenter - val machines = topology.run { - section.datacenter.outgoingEdges.destinations<Room>("room").asSequence() - .flatMap { it.outgoingEdges.destinations<Rack>("rack").asSequence() } - .flatMap { it.outgoingEdges.destinations<Machine>("machine").asSequence() }.toList() - } - - logger.info { "Starting simulation" } - - while (trace.jobs.any { !it.finished }) { - // If we have reached a timeout, return - if (simulation.time >= timeout) - return null - - // Collect data of simulation cycle - manager.transaction { - experiment.last = simulation.time - - machines.forEach { machine -> - val state = simulation.run { machine.state } - val wrapped = MachineState(0, - machine as com.atlarge.opendc.model.odc.integration.jpa.schema.Machine, - state.task as com.atlarge.opendc.model.odc.integration.jpa.schema.Task?, - experiment, - simulation.time, - state.temperature, - state.memory, - state.load - ) - manager.persist(wrapped) - } - - trace.jobs.asSequence() - .flatMap { it.tasks.asSequence() } - .forEach { task -> - val state = InternalTaskState(0, - task as com.atlarge.opendc.model.odc.integration.jpa.schema.Task, - experiment, - simulation.time, - task.remaining.toInt(), - 1 - ) - manager.persist(state) - } - } - - // Run next simulation cycle - simulation.run(simulation.time + 1) - } - - // Set the experiment state - manager.transaction { - experiment.state = ExperimentState.FINISHED - } - - logger.info { "Kernel done" } - val waiting: Long = tasks.fold(0.toLong()) { acc, task -> - val finished = task.state as TaskState.Finished - acc + (finished.previous.at - finished.previous.previous.at) - } / tasks.size - - val execution: Long = tasks.fold(0.toLong()) { acc, task -> - val finished = task.state as TaskState.Finished - acc + (finished.at - finished.previous.at) - } / tasks.size - - val turnaround: Long = tasks.fold(0.toLong()) { acc, task -> - val finished = task.state as TaskState.Finished - acc + (finished.at - finished.previous.previous.at) - } / tasks.size - - logger.info { "Average waiting time: $waiting seconds" } - logger.info { "Average execution time: $execution seconds" } - logger.info { "Average turnaround time: $turnaround seconds" } - - return Unit - } - - /** - * Run the experiment on the specified simulation kernel implementation. - * - * @param factory The factory to create the simulation kernel with. - * @throws IllegalStateException if the simulation is already running or finished. - */ - override fun run(factory: KernelFactory) = run(factory, -1)!! - - /** - * Closes this resource, relinquishing any underlying resources. - * This method is invoked automatically on objects managed by the - * `try`-with-resources statement. - * - * @throws Exception if this resource cannot be closed - */ - override fun close() = manager.close() + private val experiment: InternalExperiment) : Experiment<Unit>, Closeable { + /** + * The logging instance. + */ + private val logger = KotlinLogging.logger {} + + /** + * Run the experiment using the specified simulation kernel implementation. + * + * @param factory The simulation kernel implementation to use. + * @param timeout The maximum duration of the experiment before returning to the caller. + * @return The result of the experiment or `null`. + */ + override fun run(factory: KernelFactory, timeout: Duration): Unit? { + if (experiment.state != ExperimentState.CLAIMED) { + throw IllegalStateException("The experiment is in illegal state ${experiment.state}") + } + + // Set the simulation state + manager.transaction { + experiment.state = ExperimentState.SIMULATING + } + + val bootstrap = JpaBootstrap(experiment) + val simulation = factory.create(bootstrap) + val topology = simulation.model + + val section = experiment.path.sections.first() + val trace = experiment.trace + val tasks = trace.jobs.flatMap { it.tasks } + + // Find all machines in the datacenter + val machines = topology.run { + section.datacenter.outgoingEdges.destinations<Room>("room").asSequence() + .flatMap { it.outgoingEdges.destinations<Rack>("rack").asSequence() } + .flatMap { it.outgoingEdges.destinations<Machine>("machine").asSequence() }.toList() + } + + logger.info { "Starting simulation" } + + while (trace.jobs.any { !it.finished }) { + // If we have reached a timeout, return + if (simulation.time >= timeout) + return null + + // Collect data of simulation cycle + manager.transaction { + experiment.last = simulation.time + + machines.forEach { machine -> + val state = simulation.run { machine.state } + val wrapped = MachineState(0, + machine as com.atlarge.opendc.model.odc.integration.jpa.schema.Machine, + state.task as com.atlarge.opendc.model.odc.integration.jpa.schema.Task?, + experiment, + simulation.time, + state.temperature, + state.memory, + state.load + ) + manager.persist(wrapped) + } + + trace.jobs.asSequence() + .flatMap { it.tasks.asSequence() } + .forEach { task -> + val state = InternalTaskState(0, + task as com.atlarge.opendc.model.odc.integration.jpa.schema.Task, + experiment, + simulation.time, + task.remaining.toInt(), + 1 + ) + manager.persist(state) + } + } + + // Run next simulation cycle + simulation.run(simulation.time + 1) + } + + // Set the experiment state + manager.transaction { + experiment.state = ExperimentState.FINISHED + } + + logger.info { "Kernel done" } + val waiting: Long = tasks.fold(0.toLong()) { acc, task -> + val finished = task.state as TaskState.Finished + acc + (finished.previous.at - finished.previous.previous.at) + } / tasks.size + + val execution: Long = tasks.fold(0.toLong()) { acc, task -> + val finished = task.state as TaskState.Finished + acc + (finished.at - finished.previous.at) + } / tasks.size + + val turnaround: Long = tasks.fold(0.toLong()) { acc, task -> + val finished = task.state as TaskState.Finished + acc + (finished.at - finished.previous.previous.at) + } / tasks.size + + logger.info { "Average waiting time: $waiting seconds" } + logger.info { "Average execution time: $execution seconds" } + logger.info { "Average turnaround time: $turnaround seconds" } + + return Unit + } + + /** + * Run the experiment on the specified simulation kernel implementation. + * + * @param factory The factory to create the simulation kernel with. + * @throws IllegalStateException if the simulation is already running or finished. + */ + override fun run(factory: KernelFactory) = run(factory, -1)!! + + /** + * Closes this resource, relinquishing any underlying resources. + * This method is invoked automatically on objects managed by the + * `try`-with-resources statement. + * + * @throws Exception if this resource cannot be closed + */ + override fun close() = manager.close() } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperimentManager.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperimentManager.kt index 698a1129..5dbb9a8b 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperimentManager.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/platform/JpaExperimentManager.kt @@ -24,12 +24,12 @@ package com.atlarge.opendc.model.odc.platform -import com.atlarge.opendc.simulator.platform.Experiment -import com.atlarge.opendc.model.odc.integration.jpa.transaction -import com.atlarge.opendc.model.odc.integration.jpa.schema.Experiment as InternalExperiment import com.atlarge.opendc.model.odc.integration.jpa.schema.ExperimentState +import com.atlarge.opendc.model.odc.integration.jpa.transaction +import com.atlarge.opendc.simulator.platform.Experiment import javax.persistence.EntityManager import javax.persistence.EntityManagerFactory +import com.atlarge.opendc.model.odc.integration.jpa.schema.Experiment as InternalExperiment /** * A manager for [Experiment]s received from a JPA database. @@ -38,56 +38,56 @@ import javax.persistence.EntityManagerFactory * from. * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ -class JpaExperimentManager(private val factory: EntityManagerFactory): AutoCloseable { - /** - * The entity manager for this experiment. - */ - private var manager: EntityManager = factory.createEntityManager() +class JpaExperimentManager(private val factory: EntityManagerFactory) : AutoCloseable { + /** + * The entity manager for this experiment. + */ + private var manager: EntityManager = factory.createEntityManager() - /** - * The amount of experiments in the queue. This property is not guaranteed to run in constant time. - */ - val size: Int - get() { - return manager.createQuery("SELECT COUNT(e.id) FROM experiments e WHERE e.state = :s", - java.lang.Long::class.java) - .setParameter("s", ExperimentState.QUEUED) - .singleResult.toInt() - } + /** + * The amount of experiments in the queue. This property is not guaranteed to run in constant time. + */ + val size: Int + get() { + return manager.createQuery("SELECT COUNT(e.id) FROM experiments e WHERE e.state = :s", + java.lang.Long::class.java) + .setParameter("s", ExperimentState.QUEUED) + .singleResult.toInt() + } - /** - * Poll an [Experiment] from the database and claim it. - * - * @return The experiment that has been polled from the database or `null` if there are no experiments in the - * queue. - */ - fun poll(): JpaExperiment? { - var result: JpaExperiment? = null - manager.transaction { - var experiment: InternalExperiment? = null - val results = manager.createQuery("SELECT e FROM experiments e WHERE e.state = :s", - InternalExperiment::class.java) - .setParameter("s", ExperimentState.QUEUED) - .setMaxResults(1) - .resultList + /** + * Poll an [Experiment] from the database and claim it. + * + * @return The experiment that has been polled from the database or `null` if there are no experiments in the + * queue. + */ + fun poll(): JpaExperiment? { + var result: JpaExperiment? = null + manager.transaction { + var experiment: InternalExperiment? = null + val results = manager.createQuery("SELECT e FROM experiments e WHERE e.state = :s", + InternalExperiment::class.java) + .setParameter("s", ExperimentState.QUEUED) + .setMaxResults(1) + .resultList - if (!results.isEmpty()) { - experiment = results.first() - experiment!!.state = ExperimentState.CLAIMED - } - result = experiment?.let { JpaExperiment(manager, it) } - } - manager = factory.createEntityManager() - return result - } + if (!results.isEmpty()) { + experiment = results.first() + experiment!!.state = ExperimentState.CLAIMED + } + result = experiment?.let { JpaExperiment(manager, it) } + } + manager = factory.createEntityManager() + return result + } - /** - * Close this resource, relinquishing any underlying resources. - * This method is invoked automatically on objects managed by the - * `try`-with-resources statement.* - * - * @throws Exception if this resource cannot be closed - */ - override fun close() = manager.close() + /** + * Close this resource, relinquishing any underlying resources. + * This method is invoked automatically on objects managed by the + * `try`-with-resources statement.* + * + * @throws Exception if this resource cannot be closed + */ + override fun close() = manager.close() } diff --git a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/topology/JpaTopologyFactory.kt b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/topology/JpaTopologyFactory.kt index 3f7c1b8e..65961413 100644 --- a/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/topology/JpaTopologyFactory.kt +++ b/opendc-model-odc/jpa/src/main/kotlin/com/atlarge/opendc/model/odc/topology/JpaTopologyFactory.kt @@ -28,11 +28,7 @@ import com.atlarge.opendc.model.odc.integration.jpa.schema.Rack import com.atlarge.opendc.model.odc.integration.jpa.schema.Room import com.atlarge.opendc.model.odc.integration.jpa.schema.RoomObject import com.atlarge.opendc.model.odc.integration.jpa.schema.Section -import com.atlarge.opendc.model.topology.AdjacencyList -import com.atlarge.opendc.model.topology.Topology -import com.atlarge.opendc.model.topology.MutableTopology -import com.atlarge.opendc.model.topology.TopologyBuilder -import com.atlarge.opendc.model.topology.TopologyFactory +import com.atlarge.opendc.model.topology.* /** * A [TopologyFactory] that converts a [Section] of an experiment as defined by the API, into a proper [Topology]. @@ -42,54 +38,54 @@ import com.atlarge.opendc.model.topology.TopologyFactory * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ class JpaTopologyFactory(val section: Section, val builder: TopologyBuilder = AdjacencyList.builder()) : TopologyFactory { - /** - * Create a [MutableTopology] instance. - * - * @return A mutable topology. - */ - override fun create(): MutableTopology = builder.construct { - val datacenter = section.datacenter - add(datacenter) - datacenter.rooms.forEach { room -> - add(room) - connect(datacenter, room, tag = "room") + /** + * Create a [MutableTopology] instance. + * + * @return A mutable topology. + */ + override fun create(): MutableTopology = builder.construct { + val datacenter = section.datacenter + add(datacenter) + datacenter.rooms.forEach { room -> + add(room) + connect(datacenter, room, tag = "room") - room.objects.forEach { roomObject(room, it) } - } - } + room.objects.forEach { roomObject(room, it) } + } + } - /** - * Handle the objects in a room. - * - * @param obj The obj to handle. - */ - private fun MutableTopology.roomObject(parent: Room, obj: RoomObject) = when(obj) { - is Rack -> rack(parent, obj) - else -> Unit - } + /** + * Handle the objects in a room. + * + * @param obj The obj to handle. + */ + private fun MutableTopology.roomObject(parent: Room, obj: RoomObject) = when (obj) { + is Rack -> rack(parent, obj) + else -> Unit + } - /** - * Handle a rack in a room. - * - * @param parent The parent of the rack. - * @param rack The rack to handle. - */ - private fun MutableTopology.rack(parent: Room, rack: Rack) { - add(rack) - connect(parent, rack, tag = "rack") - rack.machines.forEach { machine -> - add(machine) - connect(rack, machine, tag = "machine") + /** + * Handle a rack in a room. + * + * @param parent The parent of the rack. + * @param rack The rack to handle. + */ + private fun MutableTopology.rack(parent: Room, rack: Rack) { + add(rack) + connect(parent, rack, tag = "rack") + rack.machines.forEach { machine -> + add(machine) + connect(rack, machine, tag = "machine") - machine.cpus.forEach { cpu -> - add(cpu) - connect(machine, cpu, tag = "cpu") - } + machine.cpus.forEach { cpu -> + add(cpu) + connect(machine, cpu, tag = "cpu") + } - machine.gpus.forEach { gpu -> - add(gpu) - connect(machine, gpu, tag = "gpu") - } - } - } + machine.gpus.forEach { gpu -> + add(gpu) + connect(machine, gpu, tag = "gpu") + } + } + } } diff --git a/opendc-model-odc/jpa/src/main/resources/jpa/schema.xml b/opendc-model-odc/jpa/src/main/resources/jpa/schema.xml index 9c5e58bd..142c3ee8 100644 --- a/opendc-model-odc/jpa/src/main/resources/jpa/schema.xml +++ b/opendc-model-odc/jpa/src/main/resources/jpa/schema.xml @@ -22,303 +22,305 @@ ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ~ SOFTWARE. --> -<entity-mappings version="2.1" - xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd"> - - <package>com.atlarge.opendc.model.odc.integration.jpa.schema</package> - - <entity class="Experiment" access="FIELD" name="experiments"> - <convert converter="com.atlarge.opendc.model.odc.integration.jpa.converter.SchedulerConverter" attribute-name="scheduler" /> - <attributes> - <id name="id" /> - - <basic name="name"> - <column column-definition="text" /> - </basic> - - <basic name="state"> - <column column-definition="text" /> - <enumerated>STRING</enumerated> - </basic> - - <basic name="last"> - <column name="last_simulated_tick" column-definition="int(11)" /> - </basic> - - <basic name="scheduler"> - <column name="scheduler_name" /> - </basic> - - <many-to-one name="trace" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Trace"> - <join-column name="trace_id" /> - </many-to-one> - - <one-to-one name="path" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Path"> - <join-column name="path_id" /> - </one-to-one> - </attributes> - </entity> - - <entity class="Path" access="FIELD" name="paths"> - <attributes> - <id name="id" /> - - <one-to-many name="sections" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Section"> - <join-column name="path_id" /> - </one-to-many> - </attributes> - </entity> - - <entity class="Section" access="FIELD" name="sections"> - <attributes> - <id name="id" /> - - <basic name="startTime"> - <column name="start_tick" column-definition="int(11)" /> - </basic> - - <many-to-one name="datacenter"> - <join-column name="datacenter_id" /> - </many-to-one> - </attributes> - </entity> - - <entity class="Trace" access="FIELD" name="traces" cacheable="false"> - <attributes> - <id name="id" /> - <basic name="name"> - <column column-definition="text" /> - </basic> - <one-to-many name="jobs" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Job"> - <join-column name="trace_id" /> - </one-to-many> - </attributes> - </entity> - - <entity class="Job" access="FIELD" name="jobs" cacheable="false"> - <attributes> - <id name="id" /> - <one-to-many name="tasks" target-entity="Task"> - <join-column name="job_id" /> - </one-to-many> - <transient name="owner" /> - </attributes> - </entity> - - <entity class="Task" access="FIELD" name="tasks" cacheable="false"> - <convert converter="com.atlarge.opendc.model.odc.integration.jpa.converter.ParallelizableConverter" attribute-name="parallelizable" /> - <attributes> - <id name="id" /> - <basic name="flops"> - <column name="total_flop_count" column-definition="int(11)" /> - </basic> - <basic name="startTime"> - <column name="start_tick" column-definition="int(11)" /> - </basic> - <basic name="parallelizable"> - <column name="parallelizability" column-definition="text" /> - </basic> - - <one-to-one name="dependency" target-entity="Task"> - <join-column name="task_dependency_id" /> - </one-to-one> - <transient name="dependencies" /> - <transient name="state" /> - <transient name="remaining" /> - <transient name="finished" /> - </attributes> - </entity> - - <entity class="Datacenter" access="FIELD" name="datacenters"> - <attributes> - <id name="id" /> - - <one-to-many name="rooms" target-entity="Room"> - <join-column name="datacenter_id" /> - </one-to-many> - <transient name="scheduler" /> - <transient name="interval" /> - <transient name="initialState" /> - </attributes> - </entity> - - <entity class="Room" access="FIELD" name="rooms"> - <attributes> - <id name="id" /> - <basic name="name"> - <column column-definition="text" /> - </basic> - <basic name="type"> - <enumerated>STRING</enumerated> - </basic> - <one-to-many name="objects"> - <join-table name="tiles"> - <join-column name="room_id" /> - <inverse-join-column name="object_id" /> - </join-table> - </one-to-many> - <transient name="initialState" /> - </attributes> - </entity> - - <entity class="RoomObject" access="FIELD" name="objects"> - <inheritance strategy="JOINED" /> - <discriminator-column name="type" /> - <attributes> - <id name="id"/> - </attributes> - </entity> - - <entity class="Rack" access="FIELD" name="racks"> - <discriminator-value>RACK</discriminator-value> - <attributes> - <id name="id" /> - <basic name="name"> - <column column-definition="text" /> - </basic> - <basic name="capacity" /> - <basic name="powerCapacity"> - <column name="power_capacity_w" /> - </basic> - - <one-to-many name="machines"> - <join-column name="rack_id" /> - </one-to-many> - <transient name="initialState" /> - </attributes> - </entity> - - <entity class="Machine" access="FIELD" name="machines"> - <attributes> - <id name="id" /> - <basic name="position" /> - - <many-to-many name="cpus"> - <join-table name="machine_cpus"> - <join-column name="machine_id" /> - <inverse-join-column name="cpu_id" /> - </join-table> - </many-to-many> - - <many-to-many name="gpus"> - <join-table name="machine_gpus"> - <join-column name="machine_id" /> - <inverse-join-column name="gpu_id" /> - </join-table> - </many-to-many> - <transient name="initialState" /> - </attributes> - </entity> - - <entity class="Cpu" access="FIELD" name="cpus"> - <attributes> - <id name="id" /> - <basic name="manufacturer"> - <column column-definition="text" /> - </basic> - <basic name="family"> - <column column-definition="text" /> - </basic> - <basic name="generation"> - <column column-definition="text" /> - </basic> - <basic name="model"> - <column column-definition="text" /> - </basic> - <basic name="clockRate"> - <column name="clock_rate_mhz" /> - </basic> - <basic name="cores"> - <column name="number_of_cores" /> - </basic> - <basic name="energyConsumption"> - <column name="energy_consumption_w" /> - </basic> - <transient name="initialState" /> - </attributes> - </entity> - - <entity class="Gpu" access="FIELD" name="gpus"> - <attributes> - <id name="id" /> - <basic name="manufacturer"> - <column column-definition="text" /> - </basic> - <basic name="family"> - <column column-definition="text" /> - </basic> - <basic name="generation"> - <column column-definition="text" /> - </basic> - <basic name="model"> - <column column-definition="text" /> - </basic> - <basic name="clockRate"> - <column name="clock_rate_mhz" /> - </basic> - <basic name="cores"> - <column name="number_of_cores" /> - </basic> - <basic name="energyConsumption"> - <column name="energy_consumption_w" /> - </basic> - <transient name="initialState" /> - </attributes> - </entity> - - <entity class="MachineState" access="FIELD" name="machine_states"> - <attributes> - <id name="id"> - <generated-value strategy="IDENTITY" /> - </id> - <basic name="time"> - <column name="tick" column-definition="int(11)" /> - </basic> - <basic name="temperature"> - <column name="temperature_c" /> - </basic> - <basic name="memoryUsage"> - <column name="in_use_memory_mb" /> - </basic> - <basic name="load"> - <column name="load_fraction" /> - </basic> - - <many-to-one name="task"> - <join-column name="task_id" /> - </many-to-one> - <many-to-one name="machine"> - <join-column name="machine_id" /> - </many-to-one> - <many-to-one name="experiment"> - <join-column name="experiment_id" /> - </many-to-one> - </attributes> - </entity> - - <entity class="TaskState" access="FIELD" name="task_states"> - <attributes> - <id name="id"> - <generated-value strategy="IDENTITY" /> - </id> - <basic name="time"> - <column name="tick" column-definition="int(11)" /> - </basic> - <basic name="remaining"> - <column name="flops_left" /> - </basic> - <basic name="cores"> - <column name="cores_used" /> - </basic> - - <many-to-one name="task"> - <join-column name="task_id" /> - </many-to-one> - <many-to-one name="experiment"> - <join-column name="experiment_id" /> - </many-to-one> - </attributes> - </entity> +<entity-mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + version="2.1" + xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" +> + + <package>com.atlarge.opendc.model.odc.integration.jpa.schema</package> + + <entity class="Experiment" access="FIELD" name="experiments"> + <convert converter="com.atlarge.opendc.model.odc.integration.jpa.converter.SchedulerConverter" + attribute-name="scheduler"/> + <attributes> + <id name="id"/> + + <basic name="name"> + <column column-definition="text"/> + </basic> + + <basic name="state"> + <column column-definition="text"/> + <enumerated>STRING</enumerated> + </basic> + + <basic name="last"> + <column name="last_simulated_tick" column-definition="int(11)"/> + </basic> + + <basic name="scheduler"> + <column name="scheduler_name"/> + </basic> + + <many-to-one name="trace" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Trace"> + <join-column name="trace_id"/> + </many-to-one> + + <one-to-one name="path" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Path"> + <join-column name="path_id"/> + </one-to-one> + </attributes> + </entity> + + <entity class="Path" access="FIELD" name="paths"> + <attributes> + <id name="id"/> + + <one-to-many name="sections" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Section"> + <join-column name="path_id"/> + </one-to-many> + </attributes> + </entity> + + <entity class="Section" access="FIELD" name="sections"> + <attributes> + <id name="id"/> + + <basic name="startTime"> + <column name="start_tick" column-definition="int(11)"/> + </basic> + + <many-to-one name="datacenter"> + <join-column name="datacenter_id"/> + </many-to-one> + </attributes> + </entity> + + <entity class="Trace" access="FIELD" name="traces" cacheable="false"> + <attributes> + <id name="id"/> + <basic name="name"> + <column column-definition="text"/> + </basic> + <one-to-many name="jobs" target-entity="com.atlarge.opendc.model.odc.integration.jpa.schema.Job"> + <join-column name="trace_id"/> + </one-to-many> + </attributes> + </entity> + + <entity class="Job" access="FIELD" name="jobs" cacheable="false"> + <attributes> + <id name="id"/> + <one-to-many name="tasks" target-entity="Task"> + <join-column name="job_id"/> + </one-to-many> + <transient name="owner"/> + </attributes> + </entity> + + <entity class="Task" access="FIELD" name="tasks" cacheable="false"> + <convert converter="com.atlarge.opendc.model.odc.integration.jpa.converter.ParallelizableConverter" + attribute-name="parallelizable"/> + <attributes> + <id name="id"/> + <basic name="flops"> + <column name="total_flop_count" column-definition="int(11)"/> + </basic> + <basic name="startTime"> + <column name="start_tick" column-definition="int(11)"/> + </basic> + <basic name="parallelizable"> + <column name="parallelizability" column-definition="text"/> + </basic> + + <one-to-one name="dependency" target-entity="Task"> + <join-column name="task_dependency_id"/> + </one-to-one> + <transient name="dependencies"/> + <transient name="state"/> + <transient name="remaining"/> + <transient name="finished"/> + </attributes> + </entity> + + <entity class="Datacenter" access="FIELD" name="datacenters"> + <attributes> + <id name="id"/> + + <one-to-many name="rooms" target-entity="Room"> + <join-column name="datacenter_id"/> + </one-to-many> + <transient name="scheduler"/> + <transient name="interval"/> + <transient name="initialState"/> + </attributes> + </entity> + + <entity class="Room" access="FIELD" name="rooms"> + <attributes> + <id name="id"/> + <basic name="name"> + <column column-definition="text"/> + </basic> + <basic name="type"> + <enumerated>STRING</enumerated> + </basic> + <one-to-many name="objects"> + <join-table name="tiles"> + <join-column name="room_id"/> + <inverse-join-column name="object_id"/> + </join-table> + </one-to-many> + <transient name="initialState"/> + </attributes> + </entity> + + <entity class="RoomObject" access="FIELD" name="objects"> + <inheritance strategy="JOINED"/> + <discriminator-column name="type"/> + <attributes> + <id name="id"/> + </attributes> + </entity> + + <entity class="Rack" access="FIELD" name="racks"> + <discriminator-value>RACK</discriminator-value> + <attributes> + <id name="id"/> + <basic name="name"> + <column column-definition="text"/> + </basic> + <basic name="capacity"/> + <basic name="powerCapacity"> + <column name="power_capacity_w"/> + </basic> + + <one-to-many name="machines"> + <join-column name="rack_id"/> + </one-to-many> + <transient name="initialState"/> + </attributes> + </entity> + + <entity class="Machine" access="FIELD" name="machines"> + <attributes> + <id name="id"/> + <basic name="position"/> + + <many-to-many name="cpus"> + <join-table name="machine_cpus"> + <join-column name="machine_id"/> + <inverse-join-column name="cpu_id"/> + </join-table> + </many-to-many> + + <many-to-many name="gpus"> + <join-table name="machine_gpus"> + <join-column name="machine_id"/> + <inverse-join-column name="gpu_id"/> + </join-table> + </many-to-many> + <transient name="initialState"/> + </attributes> + </entity> + + <entity class="Cpu" access="FIELD" name="cpus"> + <attributes> + <id name="id"/> + <basic name="manufacturer"> + <column column-definition="text"/> + </basic> + <basic name="family"> + <column column-definition="text"/> + </basic> + <basic name="generation"> + <column column-definition="text"/> + </basic> + <basic name="model"> + <column column-definition="text"/> + </basic> + <basic name="clockRate"> + <column name="clock_rate_mhz"/> + </basic> + <basic name="cores"> + <column name="number_of_cores"/> + </basic> + <basic name="energyConsumption"> + <column name="energy_consumption_w"/> + </basic> + <transient name="initialState"/> + </attributes> + </entity> + + <entity class="Gpu" access="FIELD" name="gpus"> + <attributes> + <id name="id"/> + <basic name="manufacturer"> + <column column-definition="text"/> + </basic> + <basic name="family"> + <column column-definition="text"/> + </basic> + <basic name="generation"> + <column column-definition="text"/> + </basic> + <basic name="model"> + <column column-definition="text"/> + </basic> + <basic name="clockRate"> + <column name="clock_rate_mhz"/> + </basic> + <basic name="cores"> + <column name="number_of_cores"/> + </basic> + <basic name="energyConsumption"> + <column name="energy_consumption_w"/> + </basic> + <transient name="initialState"/> + </attributes> + </entity> + + <entity class="MachineState" access="FIELD" name="machine_states"> + <attributes> + <id name="id"> + <generated-value strategy="IDENTITY"/> + </id> + <basic name="time"> + <column name="tick" column-definition="int(11)"/> + </basic> + <basic name="temperature"> + <column name="temperature_c"/> + </basic> + <basic name="memoryUsage"> + <column name="in_use_memory_mb"/> + </basic> + <basic name="load"> + <column name="load_fraction"/> + </basic> + + <many-to-one name="task"> + <join-column name="task_id"/> + </many-to-one> + <many-to-one name="machine"> + <join-column name="machine_id"/> + </many-to-one> + <many-to-one name="experiment"> + <join-column name="experiment_id"/> + </many-to-one> + </attributes> + </entity> + + <entity class="TaskState" access="FIELD" name="task_states"> + <attributes> + <id name="id"> + <generated-value strategy="IDENTITY"/> + </id> + <basic name="time"> + <column name="tick" column-definition="int(11)"/> + </basic> + <basic name="remaining"> + <column name="flops_left"/> + </basic> + <basic name="cores"> + <column name="cores_used"/> + </basic> + + <many-to-one name="task"> + <join-column name="task_id"/> + </many-to-one> + <many-to-one name="experiment"> + <join-column name="experiment_id"/> + </many-to-one> + </attributes> + </entity> </entity-mappings> diff --git a/opendc-model-odc/setup/build.gradle b/opendc-model-odc/setup/build.gradle index 3962018e..ddb5860b 100644 --- a/opendc-model-odc/setup/build.gradle +++ b/opendc-model-odc/setup/build.gradle @@ -24,19 +24,19 @@ /* Build configuration */ buildscript { - ext.kotlin_version = '1.2.21' - ext.dokka_version = '0.9.15' + ext.kotlin_version = '1.2.21' + ext.dokka_version = '0.9.15' - repositories { - mavenCentral() - jcenter() - } + repositories { + mavenCentral() + jcenter() + } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" - } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + } } apply plugin: 'java' @@ -47,26 +47,26 @@ apply plugin: 'org.jetbrains.dokka' mainClassName = "nl.atlarge.opendc.model.odc.platform.JpaPlatformRunnerKt" compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } kotlin { - experimental { - coroutines 'enable' - } + experimental { + coroutines 'enable' + } } dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/javadoc" + outputFormat = 'html' + outputDirectory = "$buildDir/javadoc" } /* Project configuration */ @@ -74,14 +74,14 @@ group 'com.atlarge.opendc' version '1.1' repositories { - jcenter() + jcenter() } dependencies { - compile project(':opendc-model-odc:jpa') - compile project(':opendc-kernel-omega') + compile project(':opendc-model-odc:jpa') + compile project(':opendc-kernel-omega') - runtime 'org.slf4j:slf4j-simple:1.7.25' - runtime 'org.hibernate:hibernate-core:5.2.5.Final' - runtime 'mysql:mysql-connector-java:5.1.13' + runtime 'org.slf4j:slf4j-simple:1.7.25' + runtime 'org.hibernate:hibernate-core:5.2.5.Final' + runtime 'mysql:mysql-connector-java:5.1.13' } diff --git a/opendc-model-odc/setup/src/main/kotlin/platform/JpaPlatformRunner.kt b/opendc-model-odc/setup/src/main/kotlin/platform/JpaPlatformRunner.kt index 3f0fe589..8fe49844 100644 --- a/opendc-model-odc/setup/src/main/kotlin/platform/JpaPlatformRunner.kt +++ b/opendc-model-odc/setup/src/main/kotlin/platform/JpaPlatformRunner.kt @@ -39,28 +39,28 @@ val logger = KotlinLogging.logger {} * @param args The command line arguments of the program. */ fun main(args: Array<String>) { - val properties = HashMap<Any, Any>() - val env = System.getenv() - properties["javax.persistence.jdbc.url"] = env["PERSISTENCE_URL"] ?: "" - properties["javax.persistence.jdbc.user"] = env["PERSISTENCE_USER"] ?: "" - properties["javax.persistence.jdbc.password"] = env["PERSISTENCE_PASSWORD"] ?: "" - val factory = Persistence.createEntityManagerFactory("opendc-simulator", properties) + val properties = HashMap<Any, Any>() + val env = System.getenv() + properties["javax.persistence.jdbc.url"] = env["PERSISTENCE_URL"] ?: "" + properties["javax.persistence.jdbc.user"] = env["PERSISTENCE_USER"] ?: "" + properties["javax.persistence.jdbc.password"] = env["PERSISTENCE_PASSWORD"] ?: "" + val factory = Persistence.createEntityManagerFactory("opendc-simulator", properties) - val timeout = 10000L - val threads = 4 - val executorService = Executors.newFixedThreadPool(threads) - val experiments = JpaExperimentManager(factory) - val kernel = OmegaKernelFactory + val timeout = 10000L + val threads = 4 + val executorService = Executors.newFixedThreadPool(threads) + val experiments = JpaExperimentManager(factory) + val kernel = OmegaKernelFactory - logger.info { "Waiting for enqueued experiments..." } - while (true) { - experiments.poll()?.let { experiment -> - logger.info { "Found experiment. Submitting for simulation now..." } - executorService.submit { - experiment.use { it.run(kernel, timeout) } - } - } + logger.info { "Waiting for enqueued experiments..." } + while (true) { + experiments.poll()?.let { experiment -> + logger.info { "Found experiment. Submitting for simulation now..." } + executorService.submit { + experiment.use { it.run(kernel, timeout) } + } + } - Thread.sleep(500) - } + Thread.sleep(500) + } } diff --git a/opendc-model-odc/setup/src/main/resources/META-INF/persistence.xml b/opendc-model-odc/setup/src/main/resources/META-INF/persistence.xml index 0e40dc6e..4c4e6ac7 100644 --- a/opendc-model-odc/setup/src/main/resources/META-INF/persistence.xml +++ b/opendc-model-odc/setup/src/main/resources/META-INF/persistence.xml @@ -23,19 +23,19 @@ ~ SOFTWARE. --> -<persistence xmlns="http://java.sun.com/xml/ns/persistence" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" - version="2.0"> - <persistence-unit name="opendc-simulator"> - <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> - <mapping-file>jpa/schema.xml</mapping-file> - <properties> - <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> - <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> - <property name="hibernate.show_sql" value="false" /> - <property name="hibernate.hbm2ddl.auto" value="validate" /> - <property name="hibernate.jdbc.batch_size" value="50" /> - </properties> - </persistence-unit> +<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://java.sun.com/xml/ns/persistence" + xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" + version="2.0"> + <persistence-unit name="opendc-simulator"> + <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> + <mapping-file>jpa/schema.xml</mapping-file> + <properties> + <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> + <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> + <property name="hibernate.show_sql" value="false"/> + <property name="hibernate.hbm2ddl.auto" value="validate"/> + <property name="hibernate.jdbc.batch_size" value="50"/> + </properties> + </persistence-unit> </persistence> diff --git a/opendc-stdlib/build.gradle b/opendc-stdlib/build.gradle index 6dccaff0..e02da931 100644 --- a/opendc-stdlib/build.gradle +++ b/opendc-stdlib/build.gradle @@ -24,19 +24,19 @@ /* Build configuration */ buildscript { - ext.kotlin_version = '1.2.21' - ext.dokka_version = '0.9.15' + ext.kotlin_version = '1.2.21' + ext.dokka_version = '0.9.15' - repositories { - mavenCentral() - jcenter() - } + repositories { + mavenCentral() + jcenter() + } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' - } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3' + } } apply plugin: 'java' @@ -45,26 +45,26 @@ apply plugin: 'org.jetbrains.dokka' apply plugin: 'org.junit.platform.gradle.plugin' compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } + kotlinOptions { + jvmTarget = "1.8" + } } kotlin { - experimental { - coroutines 'enable' - } + experimental { + coroutines 'enable' + } } dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/javadoc" + outputFormat = 'html' + outputDirectory = "$buildDir/javadoc" } /* Project configuration */ @@ -72,17 +72,17 @@ group 'com.atlarge.opendc' version '1.1' repositories { - jcenter() + jcenter() } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.2" - compile project(':opendc-core') - compile "io.github.microutils:kotlin-logging:1.4.6" + compile project(':opendc-core') + compile "io.github.microutils:kotlin-logging:1.4.6" - testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" - testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" - testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" - testCompile "org.slf4j:slf4j-simple:1.7.25" + testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-RC3" + testRuntime "org.junit.jupiter:junit-jupiter-engine:5.0.0-RC3" + testCompile "org.junit.platform:junit-platform-launcher:1.0.0-RC3" + testCompile "org.slf4j:slf4j-simple:1.7.25" } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt index c042a2d5..db117917 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt @@ -25,8 +25,8 @@ package com.atlarge.opendc.model.topology import com.atlarge.opendc.simulator.Entity -import com.atlarge.opendc.model.topology.Edge as BaseEdge import java.util.concurrent.atomic.AtomicInteger +import com.atlarge.opendc.model.topology.Edge as BaseEdge /** * This module provides a [Topology] implementation backed internally by an adjacency list. @@ -37,12 +37,12 @@ import java.util.concurrent.atomic.AtomicInteger * *Note that this implementation is not synchronized.* */ object AdjacencyList { - /** - * Return a [TopologyBuilder] that constructs the topology represents as an adjacency list. - * - * @return A [TopologyBuilder] instance. - */ - fun builder(): TopologyBuilder = AdjacencyListTopologyBuilder() + /** + * Return a [TopologyBuilder] that constructs the topology represents as an adjacency list. + * + * @return A [TopologyBuilder] instance. + */ + fun builder(): TopologyBuilder = AdjacencyListTopologyBuilder() } /** @@ -51,210 +51,210 @@ object AdjacencyList { * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ internal class AdjacencyListTopologyBuilder : TopologyBuilder { - /** - * Build a [Topology] instance from the current state of this builder. - * - * @return The graph built from this builder. - */ - override fun create(): MutableTopology = AdjacencyListTopology() + /** + * Build a [Topology] instance from the current state of this builder. + * + * @return The graph built from this builder. + */ + override fun create(): MutableTopology = AdjacencyListTopology() } /** * A [Topology] whose graph is represented as adjacency list. */ internal class AdjacencyListTopology : MutableTopology { - /** - * The identifier for the next node in the graph. - */ - private var nextId: AtomicInteger = AtomicInteger(0) - - /** - * A mapping of nodes to their internal representation with the edges of the nodes. - */ - private var nodes: MutableMap<Entity<*, Topology>, Node> = HashMap() - - // Topology - - /** - * The listeners of this topology. - */ - override val listeners: MutableSet<TopologyListener> = HashSet() - - /** - * A unique identifier of this node within the topology. - */ - override val Entity<*, Topology>.id: Int - get() = nodes[this]!!.id - - /** - * The set of ingoing edges of this node. - */ - override val Entity<*, Topology>.ingoingEdges: MutableSet<BaseEdge<*>> - get() = nodes[this]!!.ingoingEdges - - /** - * The set of outgoing edges of this node. - */ - override val Entity<*, Topology>.outgoingEdges: MutableSet<BaseEdge<*>> - get() = nodes[this]!!.outgoingEdges - - // MutableTopology - - /** - * Create a directed edge between two [Node]s in the topology. - * - * @param from The source of the edge. - * @param to The destination of the edge. - * @param label The label of the edge. - * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. - * @return The edge that has been created. - */ - override fun <T> connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String?): BaseEdge<T> { - if (!contains(from) || !contains(to)) - throw IllegalArgumentException("One of the entities is not part of the topology") - val edge = Edge(label, tag, from, to) - from.outgoingEdges.add(edge) - to.ingoingEdges.add(edge) - listeners.forEach { it.run { this@AdjacencyListTopology.onEdgeAdded(edge) } } - return edge - } - - // Cloneable - - /** - * Create a copy of the graph. - * - * @return A new [Topology] instance with a copy of the graph. - */ - override fun clone(): Topology { - val copy = AdjacencyListTopology() - copy.nextId = AtomicInteger(nextId.get()) - copy.nodes = HashMap(nodes) - return copy - } - - // Set - - /** - * Returns the size of the collection. - */ - override val size: Int = nodes.size - - /** - * Checks if the specified element is contained in this collection. - */ - override fun contains(element: Entity<*, Topology>): Boolean = nodes.contains(element) - - /** - * Checks if all elements in the specified collection are contained in this collection. - */ - override fun containsAll(elements: Collection<Entity<*, Topology>>): Boolean = - elements.all { nodes.containsKey(it) } - - /** - * Returns `true` if the collection is empty (contains no elements), `false` otherwise. - */ - override fun isEmpty(): Boolean = nodes.isEmpty() - - // MutableSet - - /** - * Add a node to the graph. - * - * @param element The element to add to this graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun add(element: Entity<*, Topology>): Boolean { - if (nodes.putIfAbsent(element, Node(nextId.getAndIncrement())) == null) { - listeners.forEach { it.run { this@AdjacencyListTopology.onNodeAdded(element) } } - return true - } - return false - } - - /** - * Add all nodes in the specified collection to the graph. - * - * @param elements The nodes to add to this graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun addAll(elements: Collection<Entity<*, Topology>>): Boolean = elements.any { add(it) } - - /** - * Remove all nodes and their respective edges from the graph. - */ - override fun clear() = nodes.clear() - - /** - * Remove the given node and its edges from the graph. - * - * @param element The element to remove from the graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun remove(element: Entity<*, Topology>): Boolean { - nodes[element]?.ingoingEdges?.forEach { - it.from.outgoingEdges.remove(it) - } - nodes[element]?.outgoingEdges?.forEach { - it.to.ingoingEdges.remove(it) - } - if (nodes.keys.remove(element)) { - listeners.forEach { it.run { this@AdjacencyListTopology.onNodeRemoved(element) } } - return true - } - return false - } - - - /** - * Remove all nodes in the given collection from the graph. - * - * @param elements The elements to remove from the graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun removeAll(elements: Collection<Entity<*, Topology>>): Boolean = elements.any(this::remove) - - /** - * Remove all nodes in the graph, except those in the specified collection. - * - * Take note that this method currently only guarantees a maximum runtime complexity of O(n^2). - * - * @param elements The elements to retain in the graph. - */ - override fun retainAll(elements: Collection<Entity<*, Topology>>): Boolean { - val iterator = nodes.keys.iterator() - var changed = false - while (iterator.hasNext()) { - val entity = iterator.next() - - if (entity !in elements) { - iterator.remove() - changed = true - } - } - return changed - } - - /** - * Return a mutable iterator over the nodes of the graph. - * - * @return A [MutableIterator] over the nodes of the graph. - */ - override fun iterator(): MutableIterator<Entity<*, Topology>> = nodes.keys.iterator() - - /** - * The internal representation of a node within the graph. - */ - internal data class Node(val id: Int) { - val ingoingEdges: MutableSet<BaseEdge<*>> = HashSet() - val outgoingEdges: MutableSet<BaseEdge<*>> = HashSet() - } - - /** - * The internal representation of an edge within the graph. - */ - internal class Edge<out T>(override val label: T, - override val tag: String?, - override val from: Entity<*, Topology>, - override val to: Entity<*, Topology>) : BaseEdge<T> + /** + * The identifier for the next node in the graph. + */ + private var nextId: AtomicInteger = AtomicInteger(0) + + /** + * A mapping of nodes to their internal representation with the edges of the nodes. + */ + private var nodes: MutableMap<Entity<*, Topology>, Node> = HashMap() + + // Topology + + /** + * The listeners of this topology. + */ + override val listeners: MutableSet<TopologyListener> = HashSet() + + /** + * A unique identifier of this node within the topology. + */ + override val Entity<*, Topology>.id: Int + get() = nodes[this]!!.id + + /** + * The set of ingoing edges of this node. + */ + override val Entity<*, Topology>.ingoingEdges: MutableSet<BaseEdge<*>> + get() = nodes[this]!!.ingoingEdges + + /** + * The set of outgoing edges of this node. + */ + override val Entity<*, Topology>.outgoingEdges: MutableSet<BaseEdge<*>> + get() = nodes[this]!!.outgoingEdges + + // MutableTopology + + /** + * Create a directed edge between two [Node]s in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + override fun <T> connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String?): BaseEdge<T> { + if (!contains(from) || !contains(to)) + throw IllegalArgumentException("One of the entities is not part of the topology") + val edge = Edge(label, tag, from, to) + from.outgoingEdges.add(edge) + to.ingoingEdges.add(edge) + listeners.forEach { it.run { this@AdjacencyListTopology.onEdgeAdded(edge) } } + return edge + } + + // Cloneable + + /** + * Create a copy of the graph. + * + * @return A new [Topology] instance with a copy of the graph. + */ + override fun clone(): Topology { + val copy = AdjacencyListTopology() + copy.nextId = AtomicInteger(nextId.get()) + copy.nodes = HashMap(nodes) + return copy + } + + // Set + + /** + * Returns the size of the collection. + */ + override val size: Int = nodes.size + + /** + * Checks if the specified element is contained in this collection. + */ + override fun contains(element: Entity<*, Topology>): Boolean = nodes.contains(element) + + /** + * Checks if all elements in the specified collection are contained in this collection. + */ + override fun containsAll(elements: Collection<Entity<*, Topology>>): Boolean = + elements.all { nodes.containsKey(it) } + + /** + * Returns `true` if the collection is empty (contains no elements), `false` otherwise. + */ + override fun isEmpty(): Boolean = nodes.isEmpty() + + // MutableSet + + /** + * Add a node to the graph. + * + * @param element The element to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun add(element: Entity<*, Topology>): Boolean { + if (nodes.putIfAbsent(element, Node(nextId.getAndIncrement())) == null) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeAdded(element) } } + return true + } + return false + } + + /** + * Add all nodes in the specified collection to the graph. + * + * @param elements The nodes to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun addAll(elements: Collection<Entity<*, Topology>>): Boolean = elements.any { add(it) } + + /** + * Remove all nodes and their respective edges from the graph. + */ + override fun clear() = nodes.clear() + + /** + * Remove the given node and its edges from the graph. + * + * @param element The element to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun remove(element: Entity<*, Topology>): Boolean { + nodes[element]?.ingoingEdges?.forEach { + it.from.outgoingEdges.remove(it) + } + nodes[element]?.outgoingEdges?.forEach { + it.to.ingoingEdges.remove(it) + } + if (nodes.keys.remove(element)) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeRemoved(element) } } + return true + } + return false + } + + + /** + * Remove all nodes in the given collection from the graph. + * + * @param elements The elements to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun removeAll(elements: Collection<Entity<*, Topology>>): Boolean = elements.any(this::remove) + + /** + * Remove all nodes in the graph, except those in the specified collection. + * + * Take note that this method currently only guarantees a maximum runtime complexity of O(n^2). + * + * @param elements The elements to retain in the graph. + */ + override fun retainAll(elements: Collection<Entity<*, Topology>>): Boolean { + val iterator = nodes.keys.iterator() + var changed = false + while (iterator.hasNext()) { + val entity = iterator.next() + + if (entity !in elements) { + iterator.remove() + changed = true + } + } + return changed + } + + /** + * Return a mutable iterator over the nodes of the graph. + * + * @return A [MutableIterator] over the nodes of the graph. + */ + override fun iterator(): MutableIterator<Entity<*, Topology>> = nodes.keys.iterator() + + /** + * The internal representation of a node within the graph. + */ + internal data class Node(val id: Int) { + val ingoingEdges: MutableSet<BaseEdge<*>> = HashSet() + val outgoingEdges: MutableSet<BaseEdge<*>> = HashSet() + } + + /** + * The internal representation of an edge within the graph. + */ + internal class Edge<out T>(override val label: T, + override val tag: String?, + override val from: Entity<*, Topology>, + override val to: Entity<*, Topology>) : BaseEdge<T> } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt index de9a41d5..1a5bbcaf 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt @@ -8,16 +8,16 @@ import com.atlarge.opendc.simulator.Entity * * @return A bootstrap procedure for the topology. */ -fun <T: Topology> T.bootstrap(): Bootstrap<T> = Bootstrap.create { ctx -> - forEach { ctx.register(it) } - listeners += object : TopologyListener { - override fun Topology.onNodeAdded(node: Entity<*, Topology>) { - ctx.register(node) - } +fun <T : Topology> T.bootstrap(): Bootstrap<T> = Bootstrap.create { ctx -> + forEach { ctx.register(it) } + listeners += object : TopologyListener { + override fun Topology.onNodeAdded(node: Entity<*, Topology>) { + ctx.register(node) + } - override fun Topology.onNodeRemoved(node: Entity<*, Topology>) { - ctx.deregister(node) - } - } - this + override fun Topology.onNodeRemoved(node: Entity<*, Topology>) { + ctx.deregister(node) + } + } + this } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt index 3e507887..1963a056 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt @@ -33,29 +33,29 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Edge<out T> : Component { - /** - * The label of this edge. - */ - val label: T + /** + * The label of this edge. + */ + val label: T - /** - * A tag to uniquely identify the relationship this edge represents. - */ - val tag: String? + /** + * A tag to uniquely identify the relationship this edge represents. + */ + val tag: String? - /** - * The source of the edge. - * - * This property is not guaranteed to have a runtime complexity of <code>O(1)</code>, but must be at least - * <code>O(n)</code>, with respect to the size of the topology. - */ - val from: Entity<*, Topology> + /** + * The source of the edge. + * + * This property is not guaranteed to have a runtime complexity of <code>O(1)</code>, but must be at least + * <code>O(n)</code>, with respect to the size of the topology. + */ + val from: Entity<*, Topology> - /** - * The destination of the edge. - * - * This property is not guaranteed to have a runtime complexity of <code>O(1)</code>, but must be at least - * <code>O(n)</code>, with respect to the size of the topology. - */ - val to: Entity<*, Topology> + /** + * The destination of the edge. + * + * This property is not guaranteed to have a runtime complexity of <code>O(1)</code>, but must be at least + * <code>O(n)</code>, with respect to the size of the topology. + */ + val to: Entity<*, Topology> } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt index ac1b4ba5..7cf80702 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt @@ -33,33 +33,33 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface MutableTopology : Topology, MutableSet<Entity<*, Topology>> { - /** - * Create a directed, labeled edge between two nodes in the topology. - * - * @param from The source of the edge. - * @param to The destination of the edge. - * @param label The label of the edge. - * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. - * @return The edge that has been created. - */ - fun <T> connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String? = null): Edge<T> + /** + * Create a directed, labeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun <T> connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String? = null): Edge<T> - /** - * Create a directed, unlabeled edge between two nodes in the topology. - * - * @param from The source of the edge. - * @param to The destination of the edge. - * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. - * @return The edge that has been created. - */ - fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, tag: String? = null): Edge<Unit> = - connect(from, to, Unit, tag) + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, tag: String? = null): Edge<Unit> = + connect(from, to, Unit, tag) - /** - * Create a directed, unlabeled edge between two nodes in the topology. - * - * @param dest The destination of the edge. - * @return The edge that has been created. - */ - infix fun Entity<*, Topology>.to(dest: Entity<*, Topology>): Edge<Unit> = connect(this, dest) + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param dest The destination of the edge. + * @return The edge that has been created. + */ + infix fun Entity<*, Topology>.to(dest: Entity<*, Topology>): Edge<Unit> = connect(this, dest) } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt index 1e5a404f..e277bc9f 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt @@ -35,16 +35,16 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Topology : TopologyContext, Cloneable, Set<Entity<*, Topology>> { - /** - * The listeners of this topology. - */ - val listeners: MutableSet<TopologyListener> + /** + * The listeners of this topology. + */ + val listeners: MutableSet<TopologyListener> - /** - * Create a copy of the topology. - * - * @return A new [Topology] with a copy of the graph. - */ - public override fun clone(): Topology + /** + * Create a copy of the topology. + * + * @return A new [Topology] with a copy of the graph. + */ + public override fun clone(): Topology } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt index 44b1cb4e..8bdc37c0 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt @@ -30,11 +30,11 @@ package com.atlarge.opendc.model.topology * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyBuilder : TopologyFactory { - /** - * Construct a [Topology] from the given block and return it. - * - * @param block The block to construct the topology. - * @return The topology that has been built. - */ - fun construct(block: MutableTopology.() -> Unit): MutableTopology = create().apply(block) + /** + * Construct a [Topology] from the given block and return it. + * + * @param block The block to construct the topology. + * @return The topology that has been built. + */ + fun construct(block: MutableTopology.() -> Unit): MutableTopology = create().apply(block) } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt index 2bf87a39..9d78b5eb 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt @@ -33,18 +33,18 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyContext { - /** - * A unique identifier of an [Entity] within the topology. - */ - val Entity<*, Topology>.id: Int + /** + * A unique identifier of an [Entity] within the topology. + */ + val Entity<*, Topology>.id: Int - /** - * The set of ingoing edges of an [Entity]. - */ - val Entity<*, Topology>.ingoingEdges: Set<Edge<*>> + /** + * The set of ingoing edges of an [Entity]. + */ + val Entity<*, Topology>.ingoingEdges: Set<Edge<*>> - /** - * The set of outgoing edges of an [Entity]. - */ - val Entity<*, Topology>.outgoingEdges: Set<Edge<*>> + /** + * The set of outgoing edges of an [Entity]. + */ + val Entity<*, Topology>.outgoingEdges: Set<Edge<*>> } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt index 35cfa97a..ab2deeb7 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt @@ -31,10 +31,10 @@ package com.atlarge.opendc.model.topology * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyFactory { - /** - * Create a [MutableTopology] instance. - * - * @return A mutable topology. - */ - fun create(): MutableTopology + /** + * Create a [MutableTopology] instance. + * + * @return A mutable topology. + */ + fun create(): MutableTopology } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt index 93108cc0..0b4d43f7 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt @@ -33,31 +33,31 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyListener { - /** - * This method is invoked when an [Entity] is added to the [Topology]. - * - * @param node The entity that has been added to the [Topology]. - */ - fun Topology.onNodeAdded(node: Entity<*, Topology>) {} + /** + * This method is invoked when an [Entity] is added to the [Topology]. + * + * @param node The entity that has been added to the [Topology]. + */ + fun Topology.onNodeAdded(node: Entity<*, Topology>) {} - /** - * This method is invoked when an [Entity] is removed from the [Topology]. - * - * @param node The entity that has been removed from the [Topology]. - */ - fun Topology.onNodeRemoved(node: Entity<*, Topology>) {} + /** + * This method is invoked when an [Entity] is removed from the [Topology]. + * + * @param node The entity that has been removed from the [Topology]. + */ + fun Topology.onNodeRemoved(node: Entity<*, Topology>) {} - /** - * This method is invoked when an [Edge] is added to the [Topology]. - * - * @param edge The edge that has been added to the [Topology]. - */ - fun Topology.onEdgeAdded(edge: Edge<*>) {} + /** + * This method is invoked when an [Edge] is added to the [Topology]. + * + * @param edge The edge that has been added to the [Topology]. + */ + fun Topology.onEdgeAdded(edge: Edge<*>) {} - /** - * This method is invoked when an [Edge] is removed from the [Topology]. - * - * @param edge The entity that has been removed from the [Topology]. - */ - fun Topology.onEdgeRemoved(edge: Edge<*>) {} + /** + * This method is invoked when an [Edge] is removed from the [Topology]. + * + * @param edge The entity that has been removed from the [Topology]. + */ + fun Topology.onEdgeRemoved(edge: Edge<*>) {} } |
