summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-resources
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-06-21 11:36:25 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2021-06-21 12:19:43 +0200
commit966715d7df139a431293f5c2fc67916fbcc1ecfb (patch)
tree06bbb8161910a81b3dc1160b180650660bc50be4 /opendc-simulator/opendc-simulator-resources
parent629a8520c7611f61a513458961a08ae7494158ab (diff)
simulator: Reduce allocations in interpreter hot path
This change updates the resources module to reduce the number of object allocations in the interpreter's hot path. This in turn should reduce the GC pressure.
Diffstat (limited to 'opendc-simulator/opendc-simulator-resources')
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt2
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt77
-rw-r--r--opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt81
3 files changed, 79 insertions, 81 deletions
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt
index c39c1aca..991cda7a 100644
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt
+++ b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceAggregatorMaxMin.kt
@@ -45,7 +45,7 @@ public class SimResourceAggregatorMaxMin(
val command = if (grantedWork > 0.0 && grantedSpeed > 0.0)
SimResourceCommand.Consume(grantedWork, grantedSpeed, deadline)
else
- SimResourceCommand.Idle(deadline)
+ SimResourceCommand.Idle()
input.push(command)
}
}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt
index f7c5c5d7..d8fc8cb6 100644
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt
+++ b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/SimResourceDistributorMaxMin.kt
@@ -65,7 +65,7 @@ public class SimResourceDistributorMaxMin(
/* SimResourceConsumer */
override fun onNext(ctx: SimResourceContext): SimResourceCommand {
- return doNext(ctx.capacity)
+ return doNext(ctx)
}
override fun onEvent(ctx: SimResourceContext, event: SimResourceEvent) {
@@ -94,12 +94,13 @@ public class SimResourceDistributorMaxMin(
/**
* Schedule the work of the outputs.
*/
- private fun doNext(capacity: Double): SimResourceCommand {
+ private fun doNext(ctx: SimResourceContext): SimResourceCommand {
// If there is no work yet, mark the input as idle.
if (activeOutputs.isEmpty()) {
return SimResourceCommand.Idle()
}
+ val capacity = ctx.capacity
var duration: Double = Double.MAX_VALUE
var deadline: Long = Long.MAX_VALUE
var availableSpeed = capacity
@@ -112,7 +113,7 @@ public class SimResourceDistributorMaxMin(
output.pull()
// Remove outputs that have finished
- if (output.isFinished) {
+ if (!output.isActive) {
outputIterator.remove()
}
}
@@ -125,33 +126,23 @@ public class SimResourceDistributorMaxMin(
var remaining = activeOutputs.size
for (output in activeOutputs) {
val availableShare = availableSpeed / remaining--
+ val grantedSpeed = min(output.allowedSpeed, availableShare)
+ deadline = min(deadline, output.deadline)
- when (val command = output.activeCommand) {
- is SimResourceCommand.Idle -> {
- deadline = min(deadline, command.deadline)
- output.actualSpeed = 0.0
- }
- is SimResourceCommand.Consume -> {
- val grantedSpeed = min(output.allowedSpeed, availableShare)
- deadline = min(deadline, command.deadline)
-
- // Ignore idle computation
- if (grantedSpeed <= 0.0 || command.work <= 0.0) {
- output.actualSpeed = 0.0
- continue
- }
+ // Ignore idle computation
+ if (grantedSpeed <= 0.0 || output.work <= 0.0) {
+ output.actualSpeed = 0.0
+ continue
+ }
- totalRequestedSpeed += command.limit
- totalRequestedWork += command.work
+ totalRequestedSpeed += output.limit
+ totalRequestedWork += output.work
- output.actualSpeed = grantedSpeed
- availableSpeed -= grantedSpeed
+ output.actualSpeed = grantedSpeed
+ availableSpeed -= grantedSpeed
- // The duration that we want to run is that of the shortest request of an output
- duration = min(duration, command.work / grantedSpeed)
- }
- SimResourceCommand.Exit -> assert(false) { "Did not expect output to be stopped" }
- }
+ // The duration that we want to run is that of the shortest request of an output
+ duration = min(duration, output.work / grantedSpeed)
}
assert(deadline >= interpreter.clock.millis()) { "Deadline already passed" }
@@ -189,9 +180,19 @@ public class SimResourceDistributorMaxMin(
private var isClosed: Boolean = false
/**
- * The current command that is processed by the resource.
+ * The current requested work.
+ */
+ var work: Double = 0.0
+
+ /**
+ * The requested limit.
*/
- var activeCommand: SimResourceCommand = SimResourceCommand.Idle()
+ var limit: Double = 0.0
+
+ /**
+ * The current deadline.
+ */
+ var deadline: Long = Long.MAX_VALUE
/**
* The processing speed that is allowed by the model constraints.
@@ -204,12 +205,6 @@ public class SimResourceDistributorMaxMin(
var actualSpeed: Double = 0.0
/**
- * A flag to indicate that the output is finished.
- */
- val isFinished
- get() = activeCommand is SimResourceCommand.Exit
-
- /**
* The timestamp at which we received the last command.
*/
private var lastCommandTimestamp: Long = Long.MIN_VALUE
@@ -238,15 +233,19 @@ public class SimResourceDistributorMaxMin(
/* SimResourceProviderLogic */
override fun onIdle(ctx: SimResourceControllableContext, deadline: Long): Long {
allowedSpeed = 0.0
- activeCommand = SimResourceCommand.Idle(deadline)
+ this.deadline = deadline
+ work = 0.0
+ limit = 0.0
lastCommandTimestamp = ctx.clock.millis()
return Long.MAX_VALUE
}
override fun onConsume(ctx: SimResourceControllableContext, work: Double, limit: Double, deadline: Long): Long {
- allowedSpeed = ctx.speed
- activeCommand = SimResourceCommand.Consume(work, limit, deadline)
+ allowedSpeed = min(ctx.capacity, limit)
+ this.work = work
+ this.limit = limit
+ this.deadline = deadline
lastCommandTimestamp = ctx.clock.millis()
return Long.MAX_VALUE
@@ -257,7 +256,9 @@ public class SimResourceDistributorMaxMin(
}
override fun onFinish(ctx: SimResourceControllableContext) {
- activeCommand = SimResourceCommand.Exit
+ work = 0.0
+ limit = 0.0
+ deadline = Long.MAX_VALUE
lastCommandTimestamp = ctx.clock.millis()
}
diff --git a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt
index 5c3f95e8..90c7bc75 100644
--- a/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt
+++ b/opendc-simulator/opendc-simulator-resources/src/main/kotlin/org/opendc/simulator/resources/impl/SimResourceContextImpl.kt
@@ -212,11 +212,15 @@ internal class SimResourceContextImpl(
// 2. The resource capacity cannot satisfy the demand.
// 3. The resource consumer should be interrupted (e.g., someone called .interrupt())
if ((isConsume && remainingWork == 0.0) || _deadline <= timestamp || isInterrupted) {
- next(timestamp)
+ when (val command = consumer.onNext(this)) {
+ is SimResourceCommand.Idle -> interpretIdle(timestamp, command.deadline)
+ is SimResourceCommand.Consume -> interpretConsume(timestamp, command.work, command.limit, command.deadline)
+ is SimResourceCommand.Exit -> interpretExit()
+ }
} else if (isConsume) {
- interpret(SimResourceCommand.Consume(remainingWork, _limit, _deadline), timestamp)
+ interpretConsume(timestamp, remainingWork, _limit, _deadline)
} else {
- interpret(SimResourceCommand.Idle(_deadline), timestamp)
+ interpretIdle(timestamp, _deadline)
}
}
}
@@ -249,57 +253,50 @@ internal class SimResourceContextImpl(
}
/**
- * Interpret the specified [SimResourceCommand] that was submitted by the resource consumer.
+ * Interpret the [SimResourceCommand.Consume] command.
*/
- private fun interpret(command: SimResourceCommand, now: Long): SimResourceState {
- return when (command) {
- is SimResourceCommand.Idle -> {
- val deadline = command.deadline
-
- require(deadline >= now) { "Deadline already passed" }
-
- _speed = 0.0
- _work = 0.0
- _limit = 0.0
- _deadline = deadline
+ private fun interpretConsume(now: Long, work: Double, limit: Double, deadline: Long): SimResourceState {
+ require(deadline >= now) { "Deadline already passed" }
- val timestamp = logic.onIdle(this, deadline)
- scheduleUpdate(timestamp)
+ _speed = min(capacity, limit)
+ _work = work
+ _limit = limit
+ _deadline = deadline
- SimResourceState.Active
- }
- is SimResourceCommand.Consume -> {
- val work = command.work
- val limit = command.limit
- val deadline = command.deadline
+ val timestamp = logic.onConsume(this, work, limit, deadline)
+ scheduleUpdate(timestamp)
- require(deadline >= now) { "Deadline already passed" }
+ return SimResourceState.Active
+ }
- _speed = min(capacity, limit)
- _work = work
- _limit = limit
- _deadline = deadline
+ /**
+ * Interpret the [SimResourceCommand.Idle] command.
+ */
+ private fun interpretIdle(now: Long, deadline: Long): SimResourceState {
+ require(deadline >= now) { "Deadline already passed" }
- val timestamp = logic.onConsume(this, work, limit, deadline)
- scheduleUpdate(timestamp)
+ _speed = 0.0
+ _work = 0.0
+ _limit = 0.0
+ _deadline = deadline
- SimResourceState.Active
- }
- is SimResourceCommand.Exit -> {
- _speed = 0.0
- _work = 0.0
- _limit = 0.0
- _deadline = Long.MAX_VALUE
+ val timestamp = logic.onIdle(this, deadline)
+ scheduleUpdate(timestamp)
- SimResourceState.Stopped
- }
- }
+ return SimResourceState.Active
}
/**
- * Request the workload for more work.
+ * Interpret the [SimResourceCommand.Exit] command.
*/
- private fun next(now: Long): SimResourceState = interpret(consumer.onNext(this), now)
+ private fun interpretExit(): SimResourceState {
+ _speed = 0.0
+ _work = 0.0
+ _limit = 0.0
+ _deadline = Long.MAX_VALUE
+
+ return SimResourceState.Stopped
+ }
private var _remainingWork: Double = 0.0
private var _remainingWorkFlush: Long = Long.MIN_VALUE