diff options
9 files changed, 63 insertions, 23 deletions
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt index 320c09ff..92c0ab0c 100644 --- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt +++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt @@ -1,3 +1,3 @@ package com.atlarge.opendc.compute.core.image -data class FlopsHistoryFragment(val tick: Long, val flops: Long, val duration: Long) +data class FlopsHistoryFragment(val tick: Long, val flops: Long, val duration: Long, val usage: Double) 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 257b6149..4e8162ec 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 @@ -1,5 +1,6 @@ package com.atlarge.opendc.compute.core.image +import com.atlarge.odcsim.processContext import com.atlarge.opendc.compute.core.execution.ServerContext import com.atlarge.opendc.core.resource.TagContainer import kotlinx.coroutines.coroutineScope @@ -24,11 +25,10 @@ class VmImage( } else { val cores = min(this.cores, ctx.server.flavor.cpuCount) val req = fragment.flops / cores - coroutineScope { for (cpu in ctx.cpus.take(cores)) { - val usage = req / (fragment.duration * 1_000_000L).toDouble() - launch { cpu.run(req, usage, fragment.tick + fragment.duration) } + val usage = req / (fragment.usage * 1_000_000L) + launch { cpu.run(req, usage, processContext.clock.millis() + fragment.duration) } } } } 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 202c30e9..b6d74cde 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 @@ -130,16 +130,19 @@ public class SimpleBareMetalDriver( private data class ProcessorContextImpl(override val info: ProcessingUnit) : ProcessorContext { override suspend fun run(burst: Long, maxUsage: Double, deadline: Long): Long { val start = processContext.clock.millis() - val usage = min(maxUsage, info.clockRate) + val usage = min(maxUsage, info.clockRate) * 1_000_000 // Usage from MHz to Hz try { - val duration = min(max(0, deadline - start), ceil(burst / usage).toLong()) + val duration = min( + max(0, deadline - start), // Determine duration between now and deadline + ceil(burst / usage * 1000).toLong() // Convert from seconds to milliseconds + ) delay(duration) } catch (_: CancellationException) { // On cancellation, we compute and return the remaining burst } val end = processContext.clock.millis() - val granted = ceil((end - start) * usage * 1_000_000).toLong() + val granted = ceil((end - start) / 1000.0 * usage).toLong() return max(0, burst - 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 65ec75a2..c0d5fe0f 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 @@ -61,6 +61,7 @@ class HypervisorVirtDriver( if (memoryAvailable - requiredMemory < 0) { throw InsufficientMemoryOnServerException() } + require(flavor.cpuCount <= hostContext.server.flavor.cpuCount) { "Machine does not fit" } val server = Server(UUID.randomUUID(), "<unnamed>", emptyMap(), flavor, image, ServerState.BUILD) memoryAvailable -= requiredMemory diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmSchedulerImpl.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmSchedulerImpl.kt index dfed3d58..0b172c61 100644 --- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmSchedulerImpl.kt +++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmSchedulerImpl.kt @@ -55,8 +55,12 @@ public class VmSchedulerImpl( override fun createVirtualCpus(flavor: Flavor): List<ProcessorContext> { // TODO At the moment, the first N cores get filled the first. Distribute over all cores instead - return cpus.asSequence() + require(flavor.cpuCount <= cpus.size) { "Flavor cannot fit on machine" } + + return cpus + .asSequence() .take(flavor.cpuCount) + .sortedBy { it.vcpus.size } .map { VirtualProcessorContext(it) } .toList() } @@ -96,7 +100,7 @@ public class VmSchedulerImpl( vcpu.actualUsage = min(vcpu.requestedUsage, info.clockRate / vcpus.size) // The duration that we want to run is that of the shortest request from a vCPU - duration = min(duration, ceil(vcpu.requestedBurst / vcpu.actualUsage).toLong()) + duration = min(duration, ceil(vcpu.requestedBurst / (vcpu.actualUsage * 1_000_000L)).toLong()) deadline = min(deadline, vcpu.requestedDeadline) } @@ -104,16 +108,21 @@ public class VmSchedulerImpl( var usage: Double = 0.0 for (vcpu in vcpus) { - vcpu.actualBurst = (duration * vcpu.actualUsage).toLong() + vcpu.actualBurst = (duration * vcpu.actualUsage * 1_000_000L).toLong() burst += vcpu.actualBurst usage += vcpu.actualUsage } + // Ignore time slice if no work to request + if (burst <= 0L) { + return@launch + } + // 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 = run(burst, usage, deadline) val time = processContext.clock.millis() - var totalGrantedBurst: Long = 0 + val totalGrantedBurst: Long = burst - remainder // Compute for each vCPU the for (vcpu in vcpus) { @@ -121,7 +130,6 @@ public class VmSchedulerImpl( val fraction = vcpu.actualUsage / usage // Compute the burst time that the VM was actually granted val grantedBurst = max(0, vcpu.actualBurst - ceil(remainder * fraction).toLong()) - totalGrantedBurst += grantedBurst // Compute remaining burst time to be executed for the request vcpu.requestedBurst = max(0, vcpu.requestedBurst - grantedBurst) diff --git a/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Sc20HypervisorMonitor.kt b/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Sc20HypervisorMonitor.kt index fc0c2686..e095d300 100644 --- a/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Sc20HypervisorMonitor.kt +++ b/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Sc20HypervisorMonitor.kt @@ -2,13 +2,15 @@ package com.atlarge.opendc.experiments.sc20 import com.atlarge.opendc.compute.core.Server import com.atlarge.opendc.compute.virt.monitor.HypervisorMonitor -import java.io.File +import java.io.BufferedWriter +import java.io.Closeable +import java.io.FileWriter -class Sc20HypervisorMonitor : HypervisorMonitor { - private val outputFile = File("sc20-experiment-results.csv") +class Sc20HypervisorMonitor : HypervisorMonitor, Closeable { + private val outputFile = BufferedWriter(FileWriter("sc20-experiment-results.csv")) init { - outputFile.writeText("time,requestedBurst,grantedBurst,numberOfDeployedImages,server\n") + outputFile.write("time,requestedBurst,grantedBurst,numberOfDeployedImages,server\n") } override fun onSliceFinish( @@ -18,6 +20,10 @@ class Sc20HypervisorMonitor : HypervisorMonitor { numberOfDeployedImages: Int, hostServer: Server ) { - outputFile.appendText("$time,$requestedBurst,$grantedBurst,$numberOfDeployedImages,$numberOfDeployedImages,${hostServer.uid}\n") + outputFile.write("$time,$requestedBurst,$grantedBurst,$numberOfDeployedImages,$numberOfDeployedImages,${hostServer.uid}\n") + } + + override fun close() { + outputFile.close() } } diff --git a/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/TestExperiment.kt b/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/TestExperiment.kt index 439412ba..3882feb7 100644 --- a/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/TestExperiment.kt +++ b/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/TestExperiment.kt @@ -49,7 +49,7 @@ fun main(args: Array<String>) { return } - val environment = Sc20EnvironmentReader(object {}.javaClass.getResourceAsStream("/env/setup-test.json")) + val environment = Sc20EnvironmentReader(object {}.javaClass.getResourceAsStream("/env/setup-small.json")) .use { it.read() } val token = Channel<Boolean>() diff --git a/opendc/opendc-experiments-sc20/src/main/resources/env/setup-small.json b/opendc/opendc-experiments-sc20/src/main/resources/env/setup-small.json new file mode 100644 index 00000000..80b24dba --- /dev/null +++ b/opendc/opendc-experiments-sc20/src/main/resources/env/setup-small.json @@ -0,0 +1,21 @@ +{ + "name": "Experimental Setup 2", + "rooms": [ + { + "type": "SERVER", + "objects": [ + { + "type": "RACK", + "machines": [ + {"cpus": [1], "memories": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}, + {"cpus": [1], "memories": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}, + {"cpus": [1], "memories": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}, + {"cpus": [1], "memories": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}, + {"cpus": [1], "memories": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}, + {"cpus": [1], "memories": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]} + ] + } + ] + } + ] +} diff --git a/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/vm/VmTraceReader.kt b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/vm/VmTraceReader.kt index c3db9d33..2e881a6c 100644 --- a/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/vm/VmTraceReader.kt +++ b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/vm/VmTraceReader.kt @@ -89,23 +89,24 @@ class VmTraceReader(traceDirectory: File) : TraceReader<VmWorkload> { vmId = vmFile.nameWithoutExtension.trim().toLong() val timestamp = values[timestampCol].trim().toLong() - 5 * 60 cores = values[coreCol].trim().toInt() - val cpuUsage = values[cpuUsageCol].trim().toDouble() + val cpuUsage = values[cpuUsageCol].trim().toDouble() // MHz requiredMemory = (values[provisionedMemoryCol].trim().toDouble() / 1000).toLong() - val flops: Long = (cpuUsage * cores * 1_000_000L * 5 * 60).toLong() + val flops: Long = (cpuUsage * 1_000_000L * 5 * 60 * cores).toLong() if (flopsHistory.isEmpty()) { - flopsHistory.add(FlopsHistoryFragment(timestamp, flops, traceInterval)) + flopsHistory.add(FlopsHistoryFragment(timestamp, flops, traceInterval, cpuUsage)) } else { if (flopsHistory.last().flops != flops) { - flopsHistory.add(FlopsHistoryFragment(timestamp, flops, traceInterval)) + flopsHistory.add(FlopsHistoryFragment(timestamp, flops, traceInterval, cpuUsage)) } else { val oldFragment = flopsHistory.removeAt(flopsHistory.size - 1) flopsHistory.add( FlopsHistoryFragment( oldFragment.tick, oldFragment.flops + flops, - oldFragment.duration + traceInterval + oldFragment.duration + traceInterval, + cpuUsage ) ) } |
