summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt9
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt6
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt2
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt25
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorVirtDriver.kt33
5 files changed, 42 insertions, 33 deletions
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt
index 3a804f51..485fdcdf 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt
@@ -54,10 +54,15 @@ public interface ServerContext {
* Request the specified burst time from the processor cores and suspend execution until a processor core finishes
* processing a **non-zero** burst or until the deadline is reached.
*
+ * After the method returns, [burst] will contain the remaining burst length for each of the cores (which may be
+ * zero).
+ *
+ * Both [burst] and [maxUsage] must be of the same size and in any other case the method will throw an
+ * [IllegalArgumentException].
+ *
* @param burst The burst time to request from each of the processor cores.
* @param maxUsage The maximum usage in terms of MHz that the processing core may use while running the burst.
* @param deadline The instant at which this request needs to be fulfilled.
- * @return The remaining burst time of the processor cores.
*/
- public suspend fun run(burst: LongArray, maxUsage: DoubleArray, deadline: Long): LongArray
+ public suspend fun run(burst: LongArray, maxUsage: DoubleArray, deadline: Long)
}
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt
index d2d35db9..27d8091a 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt
@@ -42,7 +42,7 @@ import kotlin.math.min
* @property cores The number of cores that the image is able to utilize.
* @property utilization A model of the CPU utilization of the application.
*/
-class FlopsApplicationImage(
+data class FlopsApplicationImage(
public override val uid: UUID,
public override val name: String,
public override val tags: TagContainer,
@@ -61,7 +61,7 @@ class FlopsApplicationImage(
*/
override suspend fun invoke(ctx: ServerContext) {
val cores = min(this.cores, ctx.server.flavor.cpuCount)
- var burst = LongArray(cores) { flops / cores }
+ val burst = LongArray(cores) { flops / cores }
val maxUsage = DoubleArray(cores) { i -> ctx.cpus[i].frequency * utilization }
while (coroutineContext.isActive) {
@@ -69,7 +69,7 @@ class FlopsApplicationImage(
break
}
- burst = ctx.run(burst, maxUsage, Long.MAX_VALUE)
+ ctx.run(burst, maxUsage, Long.MAX_VALUE)
}
}
}
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt
index 7c4fe839..52f9068d 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt
@@ -33,4 +33,6 @@ class VmImage(
}
}
}
+
+ override fun toString(): String = "VmImage(uid=$uid, name=$name, cores=$cores, requiredMemory=$requiredMemory)"
}
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt
index d86e04ff..92338ca1 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt
@@ -167,15 +167,14 @@ public class SimpleBareMetalDriver(
domain.launch { monitor.onUpdate(server, previousState) }
}
- override suspend fun run(burst: LongArray, maxUsage: DoubleArray, deadline: Long): LongArray {
+ override suspend fun run(burst: LongArray, maxUsage: DoubleArray, deadline: Long) {
+ require(burst.size == maxUsage.size) { "Array dimensions do not match" }
+
val start = simulationContext.clock.millis()
var duration = max(0, deadline - start)
- for (i in 0..cpus.size) {
- if (i >= burst.size || i >= maxUsage.size) {
- continue
- }
-
+ // Determine the duration of the first CPU to finish
+ for (i in 0 until min(cpus.size, burst.size)) {
val cpu = cpus[i]
val usage = min(maxUsage[i], cpu.frequency) * 1_000_000 // Usage from MHz to Hz
val cpuDuration = ceil(burst[i] / usage * 1000).toLong() // Convert from seconds to milliseconds
@@ -192,14 +191,12 @@ public class SimpleBareMetalDriver(
}
val end = simulationContext.clock.millis()
- return LongArray(cpus.size) { i ->
- if (i < burst.size && i < maxUsage.size) {
- val usage = min(maxUsage[i], cpus[i].frequency) * 1_000_000
- val granted = ceil((end - start) / 1000.0 * usage).toLong()
- max(0, burst[i] - granted)
- } else {
- 0
- }
+
+ // Write back the remaining burst time
+ for (i in 0 until min(cpus.size, burst.size)) {
+ val usage = min(maxUsage[i], cpus[i].frequency) * 1_000_000
+ val granted = ceil((end - start) / 1000.0 * usage).toLong()
+ burst[i] = max(0, burst[i] - granted)
}
}
}
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorVirtDriver.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorVirtDriver.kt
index 87c4f073..2f1328ab 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorVirtDriver.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorVirtDriver.kt
@@ -105,6 +105,12 @@ class HypervisorVirtDriver(
*/
private suspend fun reschedule() {
flush()
+
+ // Do not schedule a call if there is no work to schedule
+ if (activeVms.isEmpty()) {
+ return
+ }
+
val call = simulationContext.domain.launch {
val start = simulationContext.clock.millis()
val vms = activeVms.toSet()
@@ -114,7 +120,7 @@ class HypervisorVirtDriver(
val usage = DoubleArray(hostContext.cpus.size)
for (vm in vms) {
- for (i in vm.cpus.indices) {
+ for (i in 0 until min(vm.cpus.size, vm.requestedBurst.size)) {
val cpu = vm.cpus[i]
// Limit each vCPU to at most an equal share of the host CPU
@@ -130,7 +136,7 @@ class HypervisorVirtDriver(
val burst = LongArray(hostContext.cpus.size)
for (vm in vms) {
- for (i in vm.cpus.indices) {
+ for (i in 0 until min(vm.cpus.size, vm.requestedBurst.size)) {
val cpu = vm.cpus[i]
// Limit each vCPU to at most an equal share of the host CPU
@@ -143,7 +149,7 @@ class HypervisorVirtDriver(
// We run the total burst on the host processor. Note that this call may be cancelled at any moment in
// time, so not all of the burst may be executed.
- val remainder = hostContext.run(burst, usage, deadline)
+ hostContext.run(burst, usage, deadline)
val end = simulationContext.clock.millis()
// No work was performed
@@ -152,17 +158,18 @@ class HypervisorVirtDriver(
}
for (vm in vms) {
- for (i in vm.cpus.indices) {
+ for (i in 0 until min(vm.cpus.size, vm.requestedBurst.size)) {
val cpu = vm.cpus[i]
// Limit each vCPU to at most an equal share of the host CPU
val actualUsage = min(vm.requestedUsage[i], cpu.frequency / vms.size)
+ val actualBurst = (duration * actualUsage * 1_000_000L).toLong()
// Compute the fraction of compute time allocated to the VM
val fraction = actualUsage / usage[i]
// Compute the burst time that the VM was actually granted
- val grantedBurst = max(0, burst[i] - ceil(remainder[i] * fraction).toLong())
+ val grantedBurst = max(0, actualBurst - ceil(burst[i] * fraction).toLong())
// Compute remaining burst time to be executed for the request
vm.requestedBurst[i] = max(0, vm.requestedBurst[i] - grantedBurst)
@@ -174,7 +181,6 @@ class HypervisorVirtDriver(
}
}
}
-
this.call = call
call.invokeOnCompletion { this.call = null }
}
@@ -194,8 +200,8 @@ class HypervisorVirtDriver(
val monitor: ServerMonitor,
ctx: SimulationContext
) : ServerManagementContext {
- val requestedBurst: LongArray = LongArray(server.flavor.cpuCount)
- val requestedUsage: DoubleArray = DoubleArray(server.flavor.cpuCount)
+ lateinit var requestedBurst: LongArray
+ lateinit var requestedUsage: DoubleArray
var requestedDeadline: Long = 0L
var chan = Channel<Unit>(Channel.RENDEZVOUS)
private var initialized: Boolean = false
@@ -234,11 +240,11 @@ class HypervisorVirtDriver(
monitors.forEach { it.onUpdate(vms.size, availableMemory) }
}
- override suspend fun run(burst: LongArray, maxUsage: DoubleArray, deadline: Long): LongArray {
- for (i in cpus.indices) {
- requestedBurst[i] = if (i < burst.size) burst[i] else 0
- requestedUsage[i] = if (i < maxUsage.size) maxUsage[i] else 0.0
- }
+ override suspend fun run(burst: LongArray, maxUsage: DoubleArray, deadline: Long) {
+ require(burst.size == maxUsage.size) { "Array dimensions do not match" }
+
+ requestedBurst = burst
+ requestedUsage = maxUsage
requestedDeadline = deadline
// Wait until the burst has been run or the coroutine is cancelled
@@ -251,7 +257,6 @@ class HypervisorVirtDriver(
}
activeVms -= this
reschedule()
- return requestedBurst
}
}
}