summaryrefslogtreecommitdiff
path: root/opendc-simulator
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-06-09 14:48:31 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2021-06-09 15:44:15 +0200
commite11cc719201b1e09a30fc88a30524219a17a1af0 (patch)
treed1fc5d4382eb7b450047bb4801ec07424feba747 /opendc-simulator
parente2f6cd904ccd8018b65ff897181388ae3f02ae6f (diff)
simulator: Add memory resource
This change introduces a memory resource which can be used to model memory usage. The SimMachineContext now exposes a memory field of type SimMemory which provides access to this resource and allows workloads to start a consumer on this resource.
Diffstat (limited to 'opendc-simulator')
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt14
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt4
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt5
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMemory.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt154
5 files changed, 206 insertions, 7 deletions
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
index e12ac72b..93d306cf 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
@@ -63,6 +63,11 @@ public abstract class SimAbstractMachine(
protected abstract val cpus: List<SimProcessingUnit>
/**
+ * The memory interface of the machine.
+ */
+ protected val memory: SimMemory = Memory(SimResourceSource(model.memory.sumOf { it.size }.toDouble(), interpreter), model.memory)
+
+ /**
* A flag to indicate that the machine is terminated.
*/
private var isTerminated = false
@@ -163,8 +168,15 @@ public abstract class SimAbstractMachine(
override val cpus: List<SimProcessingUnit> = this@SimAbstractMachine.cpus
- override val memory: List<MemoryUnit> = model.memory
+ override val memory: SimMemory = this@SimAbstractMachine.memory
override fun close() = cancel()
}
+
+ /**
+ * The [SimMemory] implementation for a machine.
+ */
+ private class Memory(source: SimResourceSource, override val models: List<MemoryUnit>) : SimMemory, SimResourceProvider by source {
+ override fun toString(): String = "SimAbstractMachine.Memory"
+ }
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
index 5d5d1e5a..642873fd 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
@@ -76,9 +76,7 @@ public class SimBareMetalMachine(
get() = source.capacity
set(value) {
// Clamp the capacity of the CPU between [0.0, maxFreq]
- if (value >= 0.0 && value <= model.frequency) {
- source.capacity = value
- }
+ source.capacity = value.coerceIn(0.0, model.frequency)
}
override fun toString(): String = "SimBareMetalMachine.Cpu[model=$model]"
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt
index 5cbabc86..391442ec 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt
@@ -22,7 +22,6 @@
package org.opendc.simulator.compute
-import org.opendc.simulator.compute.model.MemoryUnit
import org.opendc.simulator.resources.SimResourceInterpreter
/**
@@ -47,9 +46,9 @@ public interface SimMachineContext : AutoCloseable {
public val cpus: List<SimProcessingUnit>
/**
- * The memory available on the machine
+ * The memory interface of the machine.
*/
- public val memory: List<MemoryUnit>
+ public val memory: SimMemory
/**
* Stop the workload.
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMemory.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMemory.kt
new file mode 100644
index 00000000..6623df23
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMemory.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021 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 org.opendc.simulator.compute
+
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.resources.SimResourceProvider
+
+/**
+ * An interface to control the memory usage of simulated workloads.
+ */
+public interface SimMemory : SimResourceProvider {
+ /**
+ * The models representing the static information of the memory units supporting this interface.
+ */
+ public val models: List<MemoryUnit>
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
index 69f562d2..0c686aa0 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
@@ -24,6 +24,7 @@ package org.opendc.simulator.compute
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.toList
+import org.junit.jupiter.api.Assertions.assertArrayEquals
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -33,10 +34,14 @@ import org.opendc.simulator.compute.model.MemoryUnit
import org.opendc.simulator.compute.model.ProcessingNode
import org.opendc.simulator.compute.model.ProcessingUnit
import org.opendc.simulator.compute.power.ConstantPowerModel
+import org.opendc.simulator.compute.power.LinearPowerModel
import org.opendc.simulator.compute.power.SimplePowerDriver
+import org.opendc.simulator.compute.util.SimWorkloadLifecycle
import org.opendc.simulator.compute.workload.SimFlopsWorkload
+import org.opendc.simulator.compute.workload.SimWorkload
import org.opendc.simulator.core.runBlockingSimulation
import org.opendc.simulator.resources.SimResourceInterpreter
+import org.opendc.simulator.resources.consumer.SimWorkConsumer
/**
* Test suite for the [SimBareMetalMachine] class.
@@ -118,6 +123,155 @@ class SimMachineTest {
}
@Test
+ fun testSpeed() = runBlockingSimulation {
+ val machine = SimBareMetalMachine(
+ SimResourceInterpreter(coroutineContext, clock),
+ machineModel,
+ SimplePowerDriver(ConstantPowerModel(0.0))
+ )
+
+ try {
+ coroutineScope {
+ launch { machine.run(SimFlopsWorkload(2_000, utilization = 1.0)) }
+ assertArrayEquals(doubleArrayOf(1000.0, 1000.0), machine.speed)
+ }
+ } finally {
+ machine.close()
+ }
+ }
+
+ @Test
+ fun testPower() = runBlockingSimulation {
+ val machine = SimBareMetalMachine(
+ SimResourceInterpreter(coroutineContext, clock),
+ machineModel,
+ SimplePowerDriver(LinearPowerModel(100.0, 50.0))
+ )
+
+ try {
+ coroutineScope {
+ launch { machine.run(SimFlopsWorkload(2_000, utilization = 1.0)) }
+ assertEquals(100.0, machine.powerDraw)
+ }
+ } finally {
+ machine.close()
+ }
+ }
+
+ @Test
+ fun testCapacityClamp() = runBlockingSimulation {
+ val machine = SimBareMetalMachine(
+ SimResourceInterpreter(coroutineContext, clock),
+ machineModel,
+ SimplePowerDriver(ConstantPowerModel(0.0))
+ )
+
+ try {
+ machine.run(object : SimWorkload {
+ override fun onStart(ctx: SimMachineContext) {
+ val cpu = ctx.cpus[0]
+
+ cpu.capacity = cpu.model.frequency + 1000.0
+ assertEquals(cpu.model.frequency, cpu.capacity)
+ cpu.capacity = -1.0
+ assertEquals(0.0, cpu.capacity)
+
+ ctx.close()
+ }
+ })
+ } finally {
+ machine.close()
+ }
+ }
+
+ @Test
+ fun testMemory() = runBlockingSimulation {
+ val machine = SimBareMetalMachine(
+ SimResourceInterpreter(coroutineContext, clock),
+ machineModel,
+ SimplePowerDriver(ConstantPowerModel(0.0))
+ )
+
+ try {
+ machine.run(object : SimWorkload {
+ override fun onStart(ctx: SimMachineContext) {
+ assertEquals(32_000 * 4.0, ctx.memory.capacity)
+ ctx.close()
+ }
+ })
+ } finally {
+ machine.close()
+ }
+ }
+
+ @Test
+ fun testMemoryUsage() = runBlockingSimulation {
+ val machine = SimBareMetalMachine(
+ SimResourceInterpreter(coroutineContext, clock),
+ machineModel,
+ SimplePowerDriver(ConstantPowerModel(0.0))
+ )
+
+ try {
+ machine.run(object : SimWorkload {
+ override fun onStart(ctx: SimMachineContext) {
+ val lifecycle = SimWorkloadLifecycle(ctx)
+ ctx.memory.startConsumer(lifecycle.waitFor(SimWorkConsumer(ctx.memory.capacity, utilization = 0.8)))
+ }
+ })
+
+ assertEquals(1250, clock.millis())
+ } finally {
+ machine.close()
+ }
+ }
+
+ @Test
+ fun testCancellation() = runBlockingSimulation {
+ val machine = SimBareMetalMachine(
+ SimResourceInterpreter(coroutineContext, clock),
+ machineModel,
+ SimplePowerDriver(ConstantPowerModel(0.0))
+ )
+
+ try {
+ coroutineScope {
+ launch { machine.run(SimFlopsWorkload(2_000, utilization = 1.0)) }
+ cancel()
+ }
+ } catch (_: CancellationException) {
+ // Ignore
+ } finally {
+ machine.close()
+ }
+
+ assertEquals(0, clock.millis())
+ }
+
+ @Test
+ fun testConcurrentRuns() = runBlockingSimulation {
+ val machine = SimBareMetalMachine(
+ SimResourceInterpreter(coroutineContext, clock),
+ machineModel,
+ SimplePowerDriver(ConstantPowerModel(0.0))
+ )
+
+ try {
+ coroutineScope {
+ launch {
+ machine.run(SimFlopsWorkload(2_000, utilization = 1.0))
+ }
+
+ assertThrows<IllegalStateException> {
+ machine.run(SimFlopsWorkload(2_000, utilization = 1.0))
+ }
+ }
+ } finally {
+ machine.close()
+ }
+ }
+
+ @Test
fun testClose() = runBlockingSimulation {
val machine = SimBareMetalMachine(
SimResourceInterpreter(coroutineContext, clock),