summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Flavor.kt (renamed from opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerFlavor.kt)15
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/MemoryUnit.kt40
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt2
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt2
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt5
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt15
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/VirtDriver.kt4
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorImage.kt2
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorVirtDriver.kt27
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/InsufficientMemoryOnServerException.kt3
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmScheduler.kt4
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmSchedulerImpl.kt7
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/monitor/HypervisorMonitor.kt8
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt29
-rw-r--r--opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt7
-rw-r--r--opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt4
-rw-r--r--opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt4
-rw-r--r--opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorTest.kt14
-rw-r--r--opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Sc20HypervisorMonitor.kt8
-rw-r--r--opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/TestExperiment.kt7
-rw-r--r--opendc/opendc-experiments-sc20/src/main/resources/env/setup-test.json32
-rw-r--r--opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt5
-rw-r--r--opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Model.kt45
-rw-r--r--opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20EnvironmentReader.kt106
-rw-r--r--opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/vm/VmTraceReader.kt9
25 files changed, 317 insertions, 87 deletions
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerFlavor.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Flavor.kt
index d57dadf9..ff5060de 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerFlavor.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Flavor.kt
@@ -25,18 +25,17 @@
package com.atlarge.opendc.compute.core
/**
- * (Virtual) hardware configuration of a server.
+ * Flavors define the compute and memory capacity of [Server] instance. o put it simply, a flavor is an available
+ * hardware configuration for a server. It defines the size of a virtual server that can be launched.
*/
-public data class ServerFlavor(
+public data class Flavor(
/**
- * The processing units of this machine.
+ * The number of (virtual) processing cores to use.
*/
- public val cpus: List<ProcessingUnit>,
+ public val cpuCount: Int,
/**
- * Key and value pairs that can be used to describe the specification of the server which is more than just about
- * CPU, disk and RAM. For example, it can be used to indicate that the server created by this flavor has PCI
- * devices, etc.
+ * The amount of RAM available to the server (in MB).
*/
- public val details: Map<String, Any> = emptyMap()
+ public val memorySize: Long
)
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/MemoryUnit.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/MemoryUnit.kt
new file mode 100644
index 00000000..ce57fc72
--- /dev/null
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/MemoryUnit.kt
@@ -0,0 +1,40 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.opendc.compute.core
+
+/**
+ * A memory unit of a compute resource, either virtual or physical.
+ *
+ * @property vendor The vendor string of the memory.
+ * @property modelName The name of the memory model.
+ * @property speed The access speed of the memory in MHz.
+ * @property size The size of the memory unit in MBs.
+ */
+public data class MemoryUnit(
+ public val vendor: String,
+ public val modelName: String,
+ public val speed: Double,
+ public val size: Long
+)
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt
index cb11cfc7..86ec9a5b 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt
@@ -53,7 +53,7 @@ public data class Server(
/**
* The hardware configuration of the server.
*/
- public val flavor: ServerFlavor,
+ public val flavor: Flavor,
/**
* The image running on the server.
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 f09adc84..3576b488 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
@@ -60,7 +60,7 @@ class FlopsApplicationImage(
* Execute the runtime behavior based on a number of floating point operations to execute.
*/
override suspend fun invoke(ctx: ServerContext) {
- val cores = min(this.cores, ctx.server.flavor.cpus.sumBy { it.cores })
+ val cores = min(this.cores, ctx.server.flavor.cpuCount)
val req = flops / cores
coroutineScope {
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 b7eacd88..257b6149 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
@@ -13,7 +13,8 @@ class VmImage(
public override val name: String,
public override val tags: TagContainer,
public val flopsHistory: List<FlopsHistoryFragment>,
- public val cores: Int
+ public val cores: Int,
+ public val requiredMemory: Long
) : Image {
override suspend fun invoke(ctx: ServerContext) {
@@ -21,7 +22,7 @@ class VmImage(
if (fragment.flops == 0L) {
delay(fragment.duration)
} else {
- val cores = min(this.cores, ctx.server.flavor.cpus.sumBy { it.cores })
+ val cores = min(this.cores, ctx.server.flavor.cpuCount)
val req = fragment.flops / cores
coroutineScope {
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 29573007..202c30e9 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
@@ -28,7 +28,8 @@ import com.atlarge.odcsim.ProcessContext
import com.atlarge.odcsim.processContext
import com.atlarge.opendc.compute.core.ProcessingUnit
import com.atlarge.opendc.compute.core.Server
-import com.atlarge.opendc.compute.core.ServerFlavor
+import com.atlarge.opendc.compute.core.Flavor
+import com.atlarge.opendc.compute.core.MemoryUnit
import com.atlarge.opendc.compute.core.ServerState
import com.atlarge.opendc.compute.core.execution.ProcessorContext
import com.atlarge.opendc.compute.core.execution.ServerManagementContext
@@ -49,12 +50,13 @@ import kotlin.math.min
*
* @param uid The unique identifier of the machine.
* @param name An optional name of the machine.
- * @param flavor The hardware configuration of the machine.
+ * @param cpuNodes The CPU nodes/packages available to the bare metal machine.
*/
public class SimpleBareMetalDriver(
uid: UUID,
name: String,
- private val flavor: ServerFlavor
+ val cpuNodes: List<ProcessingUnit>,
+ val memoryUnits: List<MemoryUnit>
) : BareMetalDriver {
/**
* The monitor to use.
@@ -66,6 +68,11 @@ public class SimpleBareMetalDriver(
*/
private var node: Node = Node(uid, name, PowerState.POWER_OFF, EmptyImage, null)
+ /**
+ * The flavor that corresponds to this machine.
+ */
+ private val flavor = Flavor(cpuNodes.sumBy { it.cores }, memoryUnits.map { it.size }.sum())
+
override suspend fun init(monitor: ServerMonitor): Node {
this.monitor = monitor
return node
@@ -141,7 +148,7 @@ public class SimpleBareMetalDriver(
private var initialized: Boolean = false
private lateinit var ctx: ProcessContext
- override val cpus: List<ProcessorContextImpl> = flavor.cpus
+ override val cpus: List<ProcessorContextImpl> = cpuNodes
.asSequence()
.flatMap { cpu ->
generateSequence { ProcessorContextImpl(cpu) }.take(cpu.cores)
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/VirtDriver.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/VirtDriver.kt
index 3541b414..68b8e541 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/VirtDriver.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/VirtDriver.kt
@@ -25,7 +25,7 @@
package com.atlarge.opendc.compute.virt.driver
import com.atlarge.opendc.compute.core.Server
-import com.atlarge.opendc.compute.core.ServerFlavor
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.image.Image
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
import com.atlarge.opendc.core.services.AbstractServiceKey
@@ -44,7 +44,7 @@ public interface VirtDriver {
* @param flavor The flavor of the server which this driver is controlling.
* @return The virtual server spawned by this method.
*/
- public suspend fun spawn(image: Image, monitor: ServerMonitor, flavor: ServerFlavor): Server
+ public suspend fun spawn(image: Image, monitor: ServerMonitor, flavor: Flavor): Server
/**
* Returns the number of spawned images on the server managed by this driver.
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorImage.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorImage.kt
index fc7322db..b7848cf3 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorImage.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorImage.kt
@@ -43,7 +43,7 @@ class HypervisorImage(
override val tags: TagContainer = emptyMap()
override suspend fun invoke(ctx: ServerContext) {
- val driver = HypervisorVirtDriver(VmSchedulerImpl(ctx, hypervisorMonitor))
+ val driver = HypervisorVirtDriver(ctx, VmSchedulerImpl(ctx, hypervisorMonitor))
ctx.publishService(VirtDriver.Key, driver)
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 9ae71f14..65ec75a2 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
@@ -27,9 +27,10 @@ package com.atlarge.opendc.compute.virt.driver.hypervisor
import com.atlarge.odcsim.ProcessContext
import com.atlarge.odcsim.processContext
import com.atlarge.opendc.compute.core.Server
-import com.atlarge.opendc.compute.core.ServerFlavor
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.ServerState
import com.atlarge.opendc.compute.core.execution.ProcessorContext
+import com.atlarge.opendc.compute.core.execution.ServerContext
import com.atlarge.opendc.compute.core.execution.ServerManagementContext
import com.atlarge.opendc.compute.core.image.Image
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
@@ -41,15 +42,29 @@ import java.util.UUID
/**
* A [VirtDriver] that is backed by a simple hypervisor implementation.
*/
-class HypervisorVirtDriver(private val scheduler: VmScheduler) : VirtDriver {
+class HypervisorVirtDriver(
+ private val hostContext: ServerContext,
+ private val scheduler: VmScheduler
+) : VirtDriver {
/**
* A set for tracking the VM context objects.
*/
internal val vms: MutableSet<VmServerContext> = mutableSetOf()
- override suspend fun spawn(image: Image, monitor: ServerMonitor, flavor: ServerFlavor): Server {
+ /**
+ * Current total memory use of the images on this hypervisor.
+ */
+ private var memoryAvailable: Long = hostContext.server.flavor.memorySize
+
+ override suspend fun spawn(image: Image, monitor: ServerMonitor, flavor: Flavor): Server {
+ val requiredMemory = flavor.memorySize
+ if (memoryAvailable - requiredMemory < 0) {
+ throw InsufficientMemoryOnServerException()
+ }
+
val server = Server(UUID.randomUUID(), "<unnamed>", emptyMap(), flavor, image, ServerState.BUILD)
- vms.add(VmServerContext(server, monitor, flavor, processContext))
+ memoryAvailable -= requiredMemory
+ vms.add(VmServerContext(server, monitor, processContext))
return server
}
@@ -60,7 +75,6 @@ class HypervisorVirtDriver(private val scheduler: VmScheduler) : VirtDriver {
internal inner class VmServerContext(
override var server: Server,
val monitor: ServerMonitor,
- flavor: ServerFlavor,
ctx: ProcessContext
) : ServerManagementContext {
private var initialized: Boolean = false
@@ -75,7 +89,7 @@ class HypervisorVirtDriver(private val scheduler: VmScheduler) : VirtDriver {
}
}
- override val cpus: List<ProcessorContext> = scheduler.createVirtualCpus(flavor)
+ override val cpus: List<ProcessorContext> = scheduler.createVirtualCpus(server.flavor)
override suspend fun init() {
if (initialized) {
@@ -92,6 +106,7 @@ class HypervisorVirtDriver(private val scheduler: VmScheduler) : VirtDriver {
val previousState = server.state
val state = if (cause == null) ServerState.SHUTOFF else ServerState.ERROR
server = server.copy(state = state)
+ memoryAvailable += server.flavor.memorySize
monitor.onUpdate(server, previousState)
initialized = false
}
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/InsufficientMemoryOnServerException.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/InsufficientMemoryOnServerException.kt
new file mode 100644
index 00000000..926234b5
--- /dev/null
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/InsufficientMemoryOnServerException.kt
@@ -0,0 +1,3 @@
+package com.atlarge.opendc.compute.virt.driver.hypervisor
+
+public class InsufficientMemoryOnServerException : IllegalStateException("Insufficient memory left on server.")
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmScheduler.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmScheduler.kt
index f02ac2b3..7b00d99c 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmScheduler.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/VmScheduler.kt
@@ -24,7 +24,7 @@
package com.atlarge.opendc.compute.virt.driver.hypervisor
-import com.atlarge.opendc.compute.core.ServerFlavor
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.execution.ProcessorContext
/**
@@ -34,5 +34,5 @@ public interface VmScheduler {
/**
* Create the virtual CPUs for the specified [flavor].
*/
- fun createVirtualCpus(flavor: ServerFlavor): List<ProcessorContext>
+ fun createVirtualCpus(flavor: Flavor): List<ProcessorContext>
}
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 b6be935e..dfed3d58 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
@@ -26,7 +26,7 @@ package com.atlarge.opendc.compute.virt.driver.hypervisor
import com.atlarge.odcsim.processContext
import com.atlarge.opendc.compute.core.ProcessingUnit
-import com.atlarge.opendc.compute.core.ServerFlavor
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.execution.ProcessorContext
import com.atlarge.opendc.compute.core.execution.ServerContext
import com.atlarge.opendc.compute.virt.monitor.HypervisorMonitor
@@ -53,9 +53,10 @@ public class VmSchedulerImpl(
*/
private val cpus = hostContext.cpus.map { HostProcessorContext(it, hostContext, hypervisorMonitor) }
- override fun createVirtualCpus(flavor: ServerFlavor): List<ProcessorContext> {
+ 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()
- .take(flavor.cpus.sumBy { it.cores })
+ .take(flavor.cpuCount)
.map { VirtualProcessorContext(it) }
.toList()
}
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/monitor/HypervisorMonitor.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/monitor/HypervisorMonitor.kt
index d4d71aaa..e259a3c0 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/monitor/HypervisorMonitor.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/monitor/HypervisorMonitor.kt
@@ -10,15 +10,15 @@ interface HypervisorMonitor {
* Invoked after a scheduling slice has finished processed.
*
* @param time The current time (in ms).
- * @param totalRequestedBurst The total requested CPU time (can be above capacity).
- * @param totalGrantedBurst The actual total granted capacity.
+ * @param requestedBurst The total requested CPU time (can be above capacity).
+ * @param grantedBurst The actual total granted capacity.
* @param numberOfDeployedImages The number of images deployed on this hypervisor.
* @param hostServer The server hosting this hypervisor.
*/
fun onSliceFinish(
time: Long,
- totalRequestedBurst: Long,
- totalGrantedBurst: Long,
+ requestedBurst: Long,
+ grantedBurst: Long,
numberOfDeployedImages: Int,
hostServer: Server
)
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt
index baf3f9ef..ef1528d9 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt
@@ -1,14 +1,16 @@
package com.atlarge.opendc.compute.virt.service
import com.atlarge.odcsim.ProcessContext
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.Server
import com.atlarge.opendc.compute.core.ServerState
import com.atlarge.opendc.compute.core.image.Image
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
import com.atlarge.opendc.compute.metal.Node
import com.atlarge.opendc.compute.metal.service.ProvisioningService
-import com.atlarge.opendc.compute.virt.driver.hypervisor.HypervisorImage
import com.atlarge.opendc.compute.virt.driver.VirtDriver
+import com.atlarge.opendc.compute.virt.driver.hypervisor.HypervisorImage
+import com.atlarge.opendc.compute.virt.driver.hypervisor.InsufficientMemoryOnServerException
import com.atlarge.opendc.compute.virt.monitor.HypervisorMonitor
import kotlinx.coroutines.launch
@@ -63,8 +65,8 @@ class SimpleVirtProvisioningService(
}
}
- override suspend fun deploy(image: Image, monitor: ServerMonitor) {
- val vmInstance = ImageView(image, monitor)
+ override suspend fun deploy(image: Image, monitor: ServerMonitor, flavor: Flavor) {
+ val vmInstance = ImageView(image, monitor, flavor)
incomingImages += vmInstance
requestCycle()
}
@@ -85,16 +87,20 @@ class SimpleVirtProvisioningService(
it.server!!.serviceRegistry[VirtDriver.Key].getNumberOfSpawnedImages()
}
- imageInstance.server = selectedNode?.server!!.serviceRegistry[VirtDriver.Key].spawn(
- imageInstance.image,
- imageInstance.monitor,
- nodes[0].server!!.flavor
- )
+ try {
+ imageInstance.server = selectedNode?.server!!.serviceRegistry[VirtDriver.Key].spawn(
+ imageInstance.image,
+ imageInstance.monitor,
+ imageInstance.flavor
+ )
+ activeImages += imageInstance
+ imagesByServer.putIfAbsent(imageInstance.server!!, mutableSetOf())
+ imagesByServer[imageInstance.server!!]!!.add(imageInstance)
+ } catch (e: InsufficientMemoryOnServerException) {
+ println("Unable to deploy image due to insufficient memory")
+ }
incomingImages -= imageInstance
- activeImages += imageInstance
- imagesByServer.putIfAbsent(imageInstance.server!!, mutableSetOf())
- imagesByServer[imageInstance.server!!]!!.add(imageInstance)
}
}
@@ -113,6 +119,7 @@ class SimpleVirtProvisioningService(
class ImageView(
val image: Image,
val monitor: ServerMonitor,
+ val flavor: Flavor,
var server: Server? = null
)
}
diff --git a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt
index 8e0e1137..fb087f9d 100644
--- a/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt
+++ b/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt
@@ -1,5 +1,6 @@
package com.atlarge.opendc.compute.virt.service
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.image.Image
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
@@ -9,6 +10,10 @@ import com.atlarge.opendc.compute.core.monitor.ServerMonitor
interface VirtProvisioningService {
/**
* Submit the specified [Image] to the provisioning service.
+ *
+ * @param image The image to be deployed.
+ * @param monitor The monitor to inform on events.
+ * @param flavor The flavor of the machine instance to run this [image] on.
*/
- public suspend fun deploy(image: Image, monitor: ServerMonitor)
+ public suspend fun deploy(image: Image, monitor: ServerMonitor, flavor: Flavor)
}
diff --git a/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt b/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt
index 05e943e2..dc4f8078 100644
--- a/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt
+++ b/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt
@@ -27,7 +27,6 @@ package com.atlarge.opendc.compute.metal.driver
import com.atlarge.odcsim.SimulationEngineProvider
import com.atlarge.opendc.compute.core.ProcessingUnit
import com.atlarge.opendc.compute.core.Server
-import com.atlarge.opendc.compute.core.ServerFlavor
import com.atlarge.opendc.compute.core.ServerState
import com.atlarge.opendc.compute.core.image.FlopsApplicationImage
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
@@ -46,14 +45,13 @@ internal class SimpleBareMetalDriverTest {
fun smoke() {
val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first()
val system = provider({ _ ->
- val flavor = ServerFlavor(listOf(ProcessingUnit("Intel", "Xeon", "amd64", 2300.0, 4)))
val image = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1000, 2)
val monitor = object : ServerMonitor {
override suspend fun onUpdate(server: Server, previousState: ServerState) {
println(server)
}
}
- val driver = SimpleBareMetalDriver(UUID.randomUUID(), "test", flavor)
+ val driver = SimpleBareMetalDriver(UUID.randomUUID(), "test", listOf(ProcessingUnit("Intel", "Xeon", "amd64", 2300.0, 4)), emptyList())
driver.init(monitor)
driver.setImage(image)
diff --git a/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt b/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt
index a2112657..85e3383c 100644
--- a/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt
+++ b/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt
@@ -27,7 +27,6 @@ package com.atlarge.opendc.compute.metal.service
import com.atlarge.odcsim.SimulationEngineProvider
import com.atlarge.opendc.compute.core.ProcessingUnit
import com.atlarge.opendc.compute.core.Server
-import com.atlarge.opendc.compute.core.ServerFlavor
import com.atlarge.opendc.compute.core.ServerState
import com.atlarge.opendc.compute.core.image.FlopsApplicationImage
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
@@ -49,14 +48,13 @@ internal class SimpleProvisioningServiceTest {
fun smoke() {
val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first()
val system = provider({ _ ->
- val flavor = ServerFlavor(listOf(ProcessingUnit("Intel", "Xeon", "amd64", 2300.0, 4)))
val image = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1000, 2)
val monitor = object : ServerMonitor {
override suspend fun onUpdate(server: Server, previousState: ServerState) {
println(server)
}
}
- val driver = SimpleBareMetalDriver(UUID.randomUUID(), "test", flavor)
+ val driver = SimpleBareMetalDriver(UUID.randomUUID(), "test", listOf(ProcessingUnit("Intel", "Xeon", "amd64", 2300.0, 4)), emptyList())
val provisioner = SimpleProvisioningService()
provisioner.create(driver)
diff --git a/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorTest.kt b/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorTest.kt
index ce0ed10d..f59f4830 100644
--- a/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorTest.kt
+++ b/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/driver/hypervisor/HypervisorTest.kt
@@ -28,7 +28,7 @@ import com.atlarge.odcsim.SimulationEngineProvider
import com.atlarge.odcsim.processContext
import com.atlarge.opendc.compute.core.ProcessingUnit
import com.atlarge.opendc.compute.core.Server
-import com.atlarge.opendc.compute.core.ServerFlavor
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.ServerState
import com.atlarge.opendc.compute.core.image.FlopsApplicationImage
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
@@ -53,12 +53,11 @@ internal class HypervisorTest {
fun smoke() {
val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first()
val system = provider({ _ ->
- val metalFlavor = ServerFlavor(listOf(ProcessingUnit("Intel", "Xeon", "amd64", 2000.0, 1)))
val vmm = HypervisorImage(object : HypervisorMonitor {
override fun onSliceFinish(
time: Long,
- totalRequestedBurst: Long,
- totalGrantedBurst: Long,
+ requestedBurst: Long,
+ grantedBurst: Long,
numberOfDeployedImages: Int,
hostServer: Server
) {
@@ -72,16 +71,17 @@ internal class HypervisorTest {
println("[${processContext.clock.millis()}]: $server")
}
}
- val metalDriver = SimpleBareMetalDriver(UUID.randomUUID(), "test", metalFlavor)
+ val metalDriver = SimpleBareMetalDriver(UUID.randomUUID(), "test", listOf(ProcessingUnit("Intel", "Xeon", "amd64", 2000.0, 1)), emptyList())
metalDriver.init(monitor)
metalDriver.setImage(vmm)
metalDriver.setPower(PowerState.POWER_ON)
delay(5)
+ val flavor = Flavor(1, 0)
val vmDriver = metalDriver.refresh().server!!.serviceRegistry[VirtDriver]
- vmDriver.spawn(workloadA, monitor, metalFlavor)
- vmDriver.spawn(workloadB, monitor, metalFlavor)
+ vmDriver.spawn(workloadA, monitor, flavor)
+ vmDriver.spawn(workloadB, monitor, flavor)
}, name = "sim")
runBlocking {
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 7b1c2dbf..fc0c2686 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
@@ -8,16 +8,16 @@ class Sc20HypervisorMonitor : HypervisorMonitor {
private val outputFile = File("sc20-experiment-results.csv")
init {
- outputFile.writeText("time,totalRequestedBurst,totalGrantedBurst,numberOfDeployedImages,server\n")
+ outputFile.writeText("time,requestedBurst,grantedBurst,numberOfDeployedImages,server\n")
}
override fun onSliceFinish(
time: Long,
- totalRequestedBurst: Long,
- totalGrantedBurst: Long,
+ requestedBurst: Long,
+ grantedBurst: Long,
numberOfDeployedImages: Int,
hostServer: Server
) {
- outputFile.appendText("$time,$totalRequestedBurst,$totalGrantedBurst,$numberOfDeployedImages,$numberOfDeployedImages,${hostServer.uid}\n")
+ outputFile.appendText("$time,$requestedBurst,$grantedBurst,$numberOfDeployedImages,$numberOfDeployedImages,${hostServer.uid}\n")
}
}
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 c7d7ac51..439412ba 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
@@ -25,12 +25,13 @@
package com.atlarge.opendc.experiments.sc20
import com.atlarge.odcsim.SimulationEngineProvider
+import com.atlarge.opendc.compute.core.Flavor
import com.atlarge.opendc.compute.core.Server
import com.atlarge.opendc.compute.core.ServerState
import com.atlarge.opendc.compute.core.monitor.ServerMonitor
import com.atlarge.opendc.compute.metal.service.ProvisioningService
import com.atlarge.opendc.compute.virt.service.SimpleVirtProvisioningService
-import com.atlarge.opendc.format.environment.sc18.Sc18EnvironmentReader
+import com.atlarge.opendc.format.environment.sc20.Sc20EnvironmentReader
import com.atlarge.opendc.format.trace.vm.VmTraceReader
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
@@ -48,7 +49,7 @@ fun main(args: Array<String>) {
return
}
- val environment = Sc18EnvironmentReader(object {}.javaClass.getResourceAsStream("/env/setup-test.json"))
+ val environment = Sc20EnvironmentReader(object {}.javaClass.getResourceAsStream("/env/setup-test.json"))
.use { it.read() }
val token = Channel<Boolean>()
@@ -73,7 +74,7 @@ fun main(args: Array<String>) {
while (reader.hasNext()) {
val (time, workload) = reader.next()
delay(max(0, time * 1000 - ctx.clock.millis()))
- scheduler.deploy(workload.image, monitor)
+ scheduler.deploy(workload.image, monitor, Flavor(workload.image.cores, workload.image.requiredMemory))
}
token.receive()
diff --git a/opendc/opendc-experiments-sc20/src/main/resources/env/setup-test.json b/opendc/opendc-experiments-sc20/src/main/resources/env/setup-test.json
index 0965b250..02a1d25b 100644
--- a/opendc/opendc-experiments-sc20/src/main/resources/env/setup-test.json
+++ b/opendc/opendc-experiments-sc20/src/main/resources/env/setup-test.json
@@ -7,27 +7,27 @@
{
"type": "RACK",
"machines": [
- { "cpus": [2] }, { "cpus": [2]},
- { "cpus": [2] }, { "cpus": [2]},
- { "cpus": [2] }, { "cpus": [2]},
- { "cpus": [2] }, { "cpus": [2]},
- { "cpus": [2] }, { "cpus": [2]},
- { "cpus": [2] }, { "cpus": [2]},
- { "cpus": [2] }, { "cpus": [2]},
- { "cpus": [2] }, { "cpus": [2]}
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]},
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]},
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]},
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]},
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]},
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]},
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]},
+ {"cpus": [2], "memories": [1, 1, 1, 1]}, {"cpus": [2], "memories": [1, 1, 1, 1]}
]
},
{
"type": "RACK",
"machines": [
- { "cpus": [1] }, { "cpus": [1]},
- { "cpus": [1] }, { "cpus": [1]},
- { "cpus": [1] }, { "cpus": [1]},
- { "cpus": [1] }, { "cpus": [1]},
- { "cpus": [1] }, { "cpus": [1]},
- { "cpus": [1] }, { "cpus": [1]},
- { "cpus": [1] }, { "cpus": [1]},
- { "cpus": [1] }, { "cpus": [1]}
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]},
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]},
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]},
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]},
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]},
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]},
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]},
+ {"cpus": [1], "memories": [1, 1, 1, 1]}, {"cpus": [1], "memories": [1, 1, 1, 1]}
]
}
]
diff --git a/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt
index 55061492..ac44337a 100644
--- a/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt
+++ b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt
@@ -25,7 +25,7 @@
package com.atlarge.opendc.format.environment.sc18
import com.atlarge.opendc.compute.core.ProcessingUnit
-import com.atlarge.opendc.compute.core.ServerFlavor
+import com.atlarge.opendc.compute.core.MemoryUnit
import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver
import com.atlarge.opendc.compute.metal.service.ProvisioningService
import com.atlarge.opendc.compute.metal.service.SimpleProvisioningService
@@ -69,8 +69,7 @@ class Sc18EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonOb
else -> throw IllegalArgumentException("The cpu id $id is not recognized")
}
}
- val flavor = ServerFlavor(cores)
- SimpleBareMetalDriver(UUID.randomUUID(), "node-${counter++}", flavor)
+ SimpleBareMetalDriver(UUID.randomUUID(), "node-${counter++}", cores, listOf(MemoryUnit("", "", 2300.0, 16000)))
}
}
}
diff --git a/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Model.kt b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Model.kt
new file mode 100644
index 00000000..3ef1d9eb
--- /dev/null
+++ b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Model.kt
@@ -0,0 +1,45 @@
+package com.atlarge.opendc.format.environment.sc20
+
+import com.fasterxml.jackson.annotation.JsonSubTypes
+import com.fasterxml.jackson.annotation.JsonTypeInfo
+
+/**
+ * A datacenter setup.
+ *
+ * @property name The name of the setup.
+ * @property rooms The rooms in the datacenter.
+ */
+internal data class Setup(val name: String, val rooms: List<Room>)
+
+/**
+ * A room in a datacenter.
+ *
+ * @property type The type of room in the datacenter.
+ * @property objects The objects in the room.
+ */
+internal data class Room(val type: String, val objects: List<RoomObject>)
+
+/**
+ * An object in a [Room].
+ *
+ * @property type The type of the room object.
+ */
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
+@JsonSubTypes(value = [JsonSubTypes.Type(name = "RACK", value = RoomObject.Rack::class)])
+internal sealed class RoomObject(val type: String) {
+ /**
+ * A rack in a server room.
+ *
+ * @property machines The machines in the rack.
+ */
+ internal data class Rack(val machines: List<Machine>) : RoomObject("RACK")
+}
+
+/**
+ * A machine in the setup that consists of the specified CPU's represented as
+ * integer identifiers and ethernet speed.
+ *
+ * @property cpus The CPUs in the machine represented as integer identifiers.
+ * @property memories The memories in the machine represented as integer identifiers.
+ */
+internal data class Machine(val cpus: List<Int>, val memories: List<Int>)
diff --git a/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20EnvironmentReader.kt b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20EnvironmentReader.kt
new file mode 100644
index 00000000..5eb711cc
--- /dev/null
+++ b/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20EnvironmentReader.kt
@@ -0,0 +1,106 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.opendc.format.environment.sc20
+
+import com.atlarge.opendc.compute.core.MemoryUnit
+import com.atlarge.opendc.compute.core.ProcessingUnit
+import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver
+import com.atlarge.opendc.compute.metal.service.ProvisioningService
+import com.atlarge.opendc.compute.metal.service.SimpleProvisioningService
+import com.atlarge.opendc.core.Environment
+import com.atlarge.opendc.core.Platform
+import com.atlarge.opendc.core.Zone
+import com.atlarge.opendc.core.services.ServiceRegistryImpl
+import com.atlarge.opendc.format.environment.EnvironmentReader
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import com.fasterxml.jackson.module.kotlin.readValue
+import kotlinx.coroutines.runBlocking
+import java.io.InputStream
+import java.util.UUID
+
+/**
+ * A parser for the JSON experiment setup files used for the SC20 paper.
+ *
+ * @param input The input stream to read from.
+ * @param mapper The Jackson object mapper to use.
+ */
+class Sc20EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : EnvironmentReader {
+ /**
+ * The environment that was read from the file.
+ */
+ private val environment: Environment
+
+ init {
+ val setup = mapper.readValue<Setup>(input)
+ var counter = 0
+ val nodes = setup.rooms.flatMap { room ->
+ room.objects.flatMap { roomObject ->
+ when (roomObject) {
+ is RoomObject.Rack -> {
+ roomObject.machines.map { machine ->
+ val cores = machine.cpus.map { id ->
+ when (id) {
+ 1 -> ProcessingUnit("Intel", "Core(TM) i7-6920HQ", "amd64", 4100.0, 4)
+ 2 -> ProcessingUnit("Intel", "Core(TM) I7-6920HQ", "amd64", 3500.0, 2)
+ else -> throw IllegalArgumentException("The cpu id $id is not recognized")
+ }
+ }
+ val memories = machine.memories.map { id ->
+ when (id) {
+ 1 -> MemoryUnit("Samsung", "PC DRAM K4A4G045WD", 1600.0, 4_000L)
+ else -> throw IllegalArgumentException("The cpu id $id is not recognized")
+ }
+ }
+ SimpleBareMetalDriver(UUID.randomUUID(), "node-${counter++}", cores, memories)
+ }
+ }
+ }
+ }
+ }
+
+ val provisioningService = SimpleProvisioningService()
+ runBlocking {
+ for (node in nodes) {
+ provisioningService.create(node)
+ }
+ }
+
+ val serviceRegistry = ServiceRegistryImpl()
+ serviceRegistry[ProvisioningService.Key] = provisioningService
+
+ val platform = Platform(
+ UUID.randomUUID(), "sc20-platform", listOf(
+ Zone(UUID.randomUUID(), "zone", serviceRegistry)
+ )
+ )
+
+ environment = Environment(setup.name, null, listOf(platform))
+ }
+
+ override fun read(): Environment = environment
+
+ override fun close() {}
+}
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 f4ed0f57..c3db9d33 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
@@ -55,6 +55,7 @@ class VmTraceReader(traceDirectory: File) : TraceReader<VmWorkload> {
var timestampCol = 0
var coreCol = 0
var cpuUsageCol = 0
+ var provisionedMemoryCol = 0
val traceInterval = 5 * 60 * 1000L
traceDirectory.walk()
@@ -64,6 +65,8 @@ class VmTraceReader(traceDirectory: File) : TraceReader<VmWorkload> {
val flopsHistory = mutableListOf<FlopsHistoryFragment>()
var vmId = -1L
var cores = -1
+ var requiredMemory = -1L
+
BufferedReader(FileReader(vmFile)).use { reader ->
reader.lineSequence()
.filter { line ->
@@ -79,6 +82,7 @@ class VmTraceReader(traceDirectory: File) : TraceReader<VmWorkload> {
timestampCol = header["Timestamp [ms]"]!!
coreCol = header["CPU cores"]!!
cpuUsageCol = header["CPU usage [MHZ]"]!!
+ provisionedMemoryCol = header["Memory capacity provisioned [KB]"]!!
return@forEachIndexed
}
@@ -86,6 +90,7 @@ class VmTraceReader(traceDirectory: File) : TraceReader<VmWorkload> {
val timestamp = values[timestampCol].trim().toLong() - 5 * 60
cores = values[coreCol].trim().toInt()
val cpuUsage = values[cpuUsageCol].trim().toDouble()
+ requiredMemory = (values[provisionedMemoryCol].trim().toDouble() / 1000).toLong()
val flops: Long = (cpuUsage * cores * 1_000_000L * 5 * 60).toLong()
@@ -110,8 +115,8 @@ class VmTraceReader(traceDirectory: File) : TraceReader<VmWorkload> {
val uuid = UUID(0L, vmId)
val vmWorkload = VmWorkload(
- uuid, "<unnamed>", UnnamedUser,
- VmImage(uuid, "<unnamed>", emptyMap(), flopsHistory, cores)
+ uuid, "VM Workload $vmId", UnnamedUser,
+ VmImage(uuid, vmId.toString(), emptyMap(), flopsHistory, cores, requiredMemory)
)
entries[vmId] = TraceEntryImpl(
flopsHistory.firstOrNull()?.tick ?: -1,