diff options
| author | Dante Niewenhuis <d.niewenhuis@hotmail.com> | 2024-09-16 11:29:26 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-16 11:29:26 +0200 |
| commit | 4a010c6b9e033314a2624a0756dcdc7f17010d9d (patch) | |
| tree | 70dc26e98cf8421eb5db7f62cf63d4ea2399c505 | |
| parent | 5047e4a25a0814f96852882f02c4017e1d5f81e7 (diff) | |
All simulation are now run with a single CPU and single MemoryUnit. multi CPUs are combined into one. This is for performance and explainability. (#255)
49 files changed, 596 insertions, 760 deletions
diff --git a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java index 2d45817b..87464fe1 100644 --- a/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java +++ b/opendc-compute/opendc-compute-service/src/main/java/org/opendc/compute/service/driver/HostModel.java @@ -26,7 +26,7 @@ package org.opendc.compute.service.driver; * Record describing the static machine properties of the host. * * @param cpuCapacity The total CPU capacity of the host in MHz. - * @param cpuCount The number of logical processing cores available for this host. + * @param coreCount The number of logical processing cores available for this host. * @param memoryCapacity The amount of memory available for this host in MB. */ -public record HostModel(double cpuCapacity, int cpuCount, int coreCount, long memoryCapacity) {} +public record HostModel(double cpuCapacity, int coreCount, long memoryCapacity) {} diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt index f87658cd..5af7ccf0 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/filters/VCpuCapacityFilter.kt @@ -36,7 +36,7 @@ public class VCpuCapacityFilter : HostFilter { ): Boolean { val requiredCapacity = task.flavor.meta["cpu-capacity"] as? Double val hostModel = host.host.model - val availableCapacity = hostModel.cpuCapacity / hostModel.cpuCount + val availableCapacity = hostModel.cpuCapacity return requiredCapacity == null || availableCapacity >= (requiredCapacity / task.flavor.coreCount) } diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt index d84f5e68..6e320bf4 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/CoreRamWeigher.kt @@ -37,7 +37,7 @@ public class CoreRamWeigher(override val multiplier: Double = 1.0) : HostWeigher host: HostView, task: Task, ): Double { - return host.availableMemory.toDouble() / host.host.model.cpuCount + return host.availableMemory.toDouble() } override fun toString(): String = "CoreRamWeigher" diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt index 6d1482ff..5f99cab3 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuCapacityWeigher.kt @@ -35,7 +35,7 @@ public class VCpuCapacityWeigher(override val multiplier: Double = 1.0) : HostWe ): Double { val model = host.host.model val requiredCapacity = task.flavor.meta["cpu-capacity"] as? Double ?: 0.0 - return model.cpuCapacity / model.cpuCount - requiredCapacity / task.flavor.coreCount + return model.cpuCapacity - requiredCapacity / task.flavor.coreCount } override fun toString(): String = "VCpuWeigher" diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt index dfc30b54..0c3d9c21 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/scheduler/weights/VCpuWeigher.kt @@ -39,7 +39,7 @@ public class VCpuWeigher(private val allocationRatio: Double, override val multi host: HostView, task: Task, ): Double { - return host.host.model.cpuCount * allocationRatio - host.provisionedCores + return allocationRatio - host.provisionedCores } override fun toString(): String = "VCpuWeigher" diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt index fa5b775e..eb686faf 100644 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt +++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt @@ -136,7 +136,7 @@ internal class ComputeServiceTest { scope.runSimulation { val host = mockk<Host>(relaxUnitFun = true) - every { host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.state } returns HostState.UP assertEquals(emptySet<Host>(), service.hosts) @@ -157,7 +157,7 @@ internal class ComputeServiceTest { scope.runSimulation { val host = mockk<Host>(relaxUnitFun = true) - every { host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.state } returns HostState.DOWN assertEquals(emptySet<Host>(), service.hosts) @@ -230,7 +230,7 @@ internal class ComputeServiceTest { scope.runSimulation { val host = mockk<Host>(relaxUnitFun = true) - every { host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.state } returns HostState.UP every { host.canFit(any()) } returns false @@ -256,7 +256,7 @@ internal class ComputeServiceTest { val listeners = mutableListOf<HostListener>() every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.state } returns HostState.DOWN every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } every { host.canFit(any()) } returns false @@ -288,7 +288,7 @@ internal class ComputeServiceTest { val listeners = mutableListOf<HostListener>() every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.state } returns HostState.UP every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } every { host.canFit(any()) } returns false @@ -320,7 +320,7 @@ internal class ComputeServiceTest { val listeners = mutableListOf<HostListener>() every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.state } returns HostState.UP every { host.canFit(any()) } returns true every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } @@ -364,7 +364,7 @@ internal class ComputeServiceTest { val listeners = mutableListOf<HostListener>() every { host.uid } returns UUID.randomUUID() - every { host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.state } returns HostState.UP every { host.canFit(any()) } returns true every { host.addListener(any()) } answers { listeners.add(it.invocation.args[0] as HostListener) } diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt index 2478bf82..add10f8f 100644 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt +++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/scheduler/FilterSchedulerTest.kt @@ -193,12 +193,12 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.availableMemory } returns 512 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.availableMemory } returns 2048 scheduler.addHost(hostA) @@ -221,7 +221,7 @@ internal class FilterSchedulerTest { val host = mockk<HostView>() every { host.host.state } returns HostState.UP - every { host.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.availableMemory } returns 2048 scheduler.addHost(host) @@ -243,12 +243,12 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.provisionedCores } returns 3 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.provisionedCores } returns 0 scheduler.addHost(hostA) @@ -271,7 +271,7 @@ internal class FilterSchedulerTest { val host = mockk<HostView>() every { host.host.state } returns HostState.UP - every { host.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { host.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { host.provisionedCores } returns 0 scheduler.addHost(host) @@ -294,13 +294,13 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(8 * 2600.0, 1, 8, 2048) + every { hostA.host.model } returns HostModel(8 * 2600.0, 8, 2048) every { hostA.availableMemory } returns 512 scheduler.addHost(hostA) val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 3200.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 3200.0, 4, 2048) every { hostB.availableMemory } returns 512 scheduler.addHost(hostB) @@ -323,12 +323,12 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.instanceCount } returns 2 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.instanceCount } returns 0 scheduler.addHost(hostA) @@ -356,13 +356,13 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.host.instances } returns emptySet() every { hostA.provisionedCores } returns 3 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.host.instances } returns setOf(taskA) every { hostB.provisionedCores } returns 0 @@ -396,13 +396,13 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.host.instances } returns setOf(taskA) every { hostA.provisionedCores } returns 3 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.host.instances } returns emptySet() every { hostB.provisionedCores } returns 0 @@ -431,12 +431,12 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.availableMemory } returns 1024 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.availableMemory } returns 512 scheduler.addHost(hostA) @@ -460,12 +460,12 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(12 * 2600.0, 1, 12, 2048) + every { hostA.host.model } returns HostModel(12 * 2600.0, 12, 2048) every { hostA.availableMemory } returns 1024 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.availableMemory } returns 512 scheduler.addHost(hostA) @@ -488,12 +488,12 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.provisionedCores } returns 2 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.provisionedCores } returns 0 scheduler.addHost(hostA) @@ -516,12 +516,12 @@ internal class FilterSchedulerTest { val hostA = mockk<HostView>() every { hostA.host.state } returns HostState.UP - every { hostA.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostA.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostA.instanceCount } returns 2 val hostB = mockk<HostView>() every { hostB.host.state } returns HostState.UP - every { hostB.host.model } returns HostModel(4 * 2600.0, 1, 4, 2048) + every { hostB.host.model } returns HostModel(4 * 2600.0, 4, 2048) every { hostB.instanceCount } returns 0 scheduler.addHost(hostA) diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt index ac0a8043..e681403c 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt @@ -41,8 +41,6 @@ import org.opendc.simulator.compute.SimMachineContext import org.opendc.simulator.compute.kernel.SimHypervisor import org.opendc.simulator.compute.model.MachineModel 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.workload.SimWorkload import org.opendc.simulator.compute.workload.SimWorkloads import java.time.Duration @@ -96,10 +94,9 @@ public class SimHost( private val model: HostModel = HostModel( - machine.model.cpus.sumOf { it.frequency }, - machine.model.cpus.size, - machine.model.cpus.sumOf { it.node.coreCount }, - machine.model.memory.sumOf { it.size }, + machine.model.cpu.totalCapacity, + machine.model.cpu.coreCount, + machine.model.memory.size, ) /** @@ -349,22 +346,14 @@ public class SimHost( * Convert flavor to machine model. */ private fun Flavor.toMachineModel(): MachineModel { - val originalCpu = machine.model.cpus[0] - val originalNode = originalCpu.node - val cpuCapacity = (this.meta["cpu-capacity"] as? Double ?: Double.MAX_VALUE).coerceAtMost(originalCpu.frequency) - val processingNode = ProcessingNode(originalNode.vendor, originalNode.modelName, originalNode.architecture, coreCount) - val processingUnits = (0 until coreCount).map { ProcessingUnit(processingNode, it, cpuCapacity) } - val memoryUnits = listOf(MemoryUnit("Generic", "Generic", 3200.0, memorySize)) - - val model = MachineModel(processingUnits, memoryUnits) - return if (optimize) model.optimize() else model + return MachineModel(machine.model.cpu, MemoryUnit("Generic", "Generic", 3200.0, memorySize)) } private var localLastReport = clock.millis() private var localUptime = 0L private var localDowntime = 0L private var localBootTime: Instant? = null - private val localCpuLimit = machine.model.cpus.sumOf { it.frequency * it.node.coreCount } + private val localCpuLimit = machine.model.cpu.totalCapacity /** * Helper function to track the uptime of a machine. diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/DefaultWorkloadMapper.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/DefaultWorkloadMapper.kt index ea8f51d0..412da37f 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/DefaultWorkloadMapper.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/DefaultWorkloadMapper.kt @@ -39,8 +39,8 @@ internal object DefaultWorkloadMapper : SimWorkloadMapper { override fun createWorkload(task: Task): SimWorkload { val workload = delegate.createWorkload(task) - // FIXME: look at connecting this to frontend. Probably not needed since the duration is so small - val bootWorkload = SimWorkloads.runtime(Duration.ofMillis(1), 0.8, 0L, 0L) + // FIXME: look at connecting this to frontend. This does currently not work correctly + val bootWorkload = SimWorkloads.runtime(Duration.ofMillis(0), 1.0, 0L, 0L) return SimWorkloads.chain(bootWorkload, workload) } } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt index 1925233f..cf6c146a 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt @@ -31,7 +31,6 @@ import org.opendc.compute.simulator.SimHost import org.opendc.compute.simulator.SimWorkloadMapper import org.opendc.simulator.compute.SimMachineContext import org.opendc.simulator.compute.kernel.SimHypervisor -import org.opendc.simulator.compute.kernel.SimVirtualMachine import org.opendc.simulator.compute.workload.SimWorkload import java.time.Duration import java.time.Instant @@ -47,7 +46,7 @@ internal class Guest( private val mapper: SimWorkloadMapper, private val listener: GuestListener, val task: Task, - val machine: SimVirtualMachine, + val machine: SimHypervisor.SimVirtualMachine, ) { /** * The state of the [Guest]. @@ -225,7 +224,7 @@ internal class Guest( private var localDowntime = 0L private var localLastReport = clock.millis() private var localBootTime: Instant? = null - private val localCpuLimit = machine.model.cpus.sumOf { it.frequency } + private val localCpuLimit = machine.model.cpu.totalCapacity /** * Helper function to track the uptime and downtime of the guest. diff --git a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt index 77cd2291..b5bc66a9 100644 --- a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt +++ b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt @@ -38,10 +38,9 @@ import org.opendc.compute.service.driver.Host import org.opendc.compute.service.driver.HostListener import org.opendc.simulator.compute.SimBareMetalMachine import org.opendc.simulator.compute.kernel.SimHypervisor +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceFragment import org.opendc.simulator.flow2.FlowEngine @@ -60,14 +59,18 @@ internal class SimHostTest { @BeforeEach fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = MachineModel( - // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + Cpu( + 0, + 2, + 3200.0, + "Intel", + "Xeon", + "amd64", + ), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) } @@ -102,11 +105,11 @@ internal class SimHostTest { mapOf( "workload" to SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000, duration * 1000, 2 * 3500.0, 2), + SimTraceFragment(0, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 1000, duration * 1000, 3200.0, 2), SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000, duration * 1000, 2 * 183.0, 2), - ).createWorkload(1), + SimTraceFragment(duration * 3000, duration * 1000, 6500.0, 2), + ).createWorkload(0), ), ) @@ -134,16 +137,16 @@ internal class SimHostTest { } // Ensure last cycle is collected - delay(1000L * duration) +// delay(1000L * duration) host.close() val cpuStats = host.getCpuStats() assertAll( - { assertEquals(347908, cpuStats.activeTime, "Active time does not match") }, - { assertEquals(2652092, cpuStats.idleTime, "Idle time does not match") }, - { assertEquals(1, cpuStats.stealTime, "Steal time does not match") }, - { assertEquals(1500000, timeSource.millis()) }, + { assertEquals(450000, cpuStats.activeTime, "Active time does not match") }, + { assertEquals(750000, cpuStats.idleTime, "Idle time does not match") }, + { assertEquals(4688, cpuStats.stealTime, "Steal time does not match") }, + { assertEquals(1200000, timeSource.millis()) }, ) } @@ -178,11 +181,11 @@ internal class SimHostTest { mapOf( "workload" to SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000, duration * 1000, 2 * 3500.0, 2), + SimTraceFragment(0, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 1000, duration * 1000, 3200.0, 2), SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000, duration * 1000, 2 * 183.0, 2), - ).createWorkload(1), + SimTraceFragment(duration * 3000, duration * 1000, 6500.0, 2), + ).createWorkload(0), ), ) val vmImageB = @@ -193,11 +196,11 @@ internal class SimHostTest { mapOf( "workload" to SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000, duration * 1000, 2 * 3100.0, 2), + SimTraceFragment(0, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 1000, duration * 1000, 3200.0, 2), SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000, duration * 1000, 2 * 73.0, 2), - ).createWorkload(1), + SimTraceFragment(duration * 3000, duration * 1000, 6500.0, 2), + ).createWorkload(0), ), ) @@ -237,9 +240,9 @@ internal class SimHostTest { val cpuStats = host.getCpuStats() assertAll( - { assertEquals(629252, cpuStats.activeTime, "Active time does not match") }, - { assertEquals(2370748, cpuStats.idleTime, "Idle time does not match") }, - { assertEquals(18754, cpuStats.stealTime, "Steal time does not match") }, + { assertEquals(600000, cpuStats.activeTime, "Active time does not match") }, + { assertEquals(900000, cpuStats.idleTime, "Idle time does not match") }, + { assertEquals(309375, cpuStats.stealTime, "Steal time does not match") }, { assertEquals(1500000, timeSource.millis()) }, ) } @@ -274,11 +277,11 @@ internal class SimHostTest { mapOf( "workload" to SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000L, duration * 1000, 2 * 3500.0, 2), - SimTraceFragment(duration * 2000L, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000L, duration * 1000, 2 * 183.0, 2), - ).createWorkload(1), + SimTraceFragment(0, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 1000, duration * 1000, 3200.0, 2), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 3000, duration * 1000, 6500.0, 2), + ).createWorkload(0), ), ) val flavor = MockFlavor(2, 0) @@ -318,8 +321,8 @@ internal class SimHostTest { val guestSysStats = host.getSystemStats(server) assertAll( - { assertEquals(2062046, cpuStats.idleTime, "Idle time does not match") }, - { assertEquals(347954, cpuStats.activeTime, "Active time does not match") }, + { assertEquals(755000, cpuStats.idleTime, "Idle time does not match") }, + { assertEquals(450000, cpuStats.activeTime, "Active time does not match") }, { assertEquals(1205000, sysStats.uptime.toMillis(), "Uptime does not match") }, { assertEquals(300000, sysStats.downtime.toMillis(), "Downtime does not match") }, { assertEquals(1205000, guestSysStats.uptime.toMillis(), "Guest uptime does not match") }, diff --git a/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/ComputeMetricReader.kt b/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/ComputeMetricReader.kt index a98a1a6d..56cda31c 100644 --- a/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/ComputeMetricReader.kt +++ b/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/ComputeMetricReader.kt @@ -258,7 +258,8 @@ public class ComputeMetricReader( private val _host = host - override val host: HostInfo = HostInfo(host.uid.toString(), host.name, "x86", host.model.cpuCount, host.model.memoryCapacity) + override val host: HostInfo = + HostInfo(host.uid.toString(), host.name, "x86", host.model.coreCount, host.model.cpuCapacity, host.model.memoryCapacity) override val timestamp: Instant get() = _timestamp @@ -539,7 +540,15 @@ public class ComputeMetricReader( val newHost = service.lookupHost(task) if (newHost != null && newHost.uid != _host?.uid) { _host = newHost - host = HostInfo(newHost.uid.toString(), newHost.name, "x86", newHost.model.cpuCount, newHost.model.memoryCapacity) + host = + HostInfo( + newHost.uid.toString(), + newHost.name, + "x86", + newHost.model.coreCount, + newHost.model.cpuCapacity, + newHost.model.memoryCapacity, + ) } val cpuStats = _host?.getCpuStats(task) diff --git a/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/export/parquet/DfltHostExportColumns.kt b/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/export/parquet/DfltHostExportColumns.kt index 68b5a664..261c5462 100644 --- a/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/export/parquet/DfltHostExportColumns.kt +++ b/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/export/parquet/DfltHostExportColumns.kt @@ -76,8 +76,8 @@ public object DfltHostExportColumns { public val CPU_COUNT: ExportColumn<HostTableReader> = ExportColumn( - field = Types.required(INT32).named("cpu_count"), - ) { it.host.cpuCount } + field = Types.required(INT32).named("core_count"), + ) { it.host.coreCount } public val MEM_CAPACITY: ExportColumn<HostTableReader> = ExportColumn( diff --git a/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/table/HostInfo.kt b/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/table/HostInfo.kt index 58b7853d..62b7ef0d 100644 --- a/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/table/HostInfo.kt +++ b/opendc-compute/opendc-compute-telemetry/src/main/kotlin/org/opendc/compute/telemetry/table/HostInfo.kt @@ -25,4 +25,11 @@ package org.opendc.compute.telemetry.table /** * Information about a host exposed to the telemetry service. */ -public data class HostInfo(val id: String, val name: String, val arch: String, val cpuCount: Int, val memCapacity: Long) +public data class HostInfo( + val id: String, + val name: String, + val arch: String, + val coreCount: Int, + val coreSpeed: Double, + val memCapacity: Long, +) diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt index d4d4bfe3..e0fba34f 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt @@ -29,10 +29,9 @@ import org.opendc.compute.topology.specs.HostJSONSpec import org.opendc.compute.topology.specs.HostSpec import org.opendc.compute.topology.specs.TopologySpec import org.opendc.simulator.compute.SimPsuFactories +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.getPowerModel import java.io.File import java.io.InputStream @@ -119,14 +118,20 @@ private fun HostJSONSpec.toHostSpecs( clusterId: Int, random: RandomGenerator, ): HostSpec { - val unknownProcessingNode = ProcessingNode("unknown", "unknown", "unknown", cpu.coreCount) - val units = List(cpu.count) { ProcessingUnit(unknownProcessingNode, globalCoreId++, cpu.coreSpeed.toMHz()) } + val units = + List(cpu.count) { + Cpu( + globalCoreId++, + cpu.coreCount, + cpu.coreSpeed.toMHz(), + ) + } val unknownMemoryUnit = MemoryUnit(memory.vendor, memory.modelName, memory.memorySpeed.toMHz(), memory.memorySize.toMiB().toLong()) val machineModel = MachineModel( units, - listOf(unknownMemoryUnit), + unknownMemoryUnit, ) val powerModel = diff --git a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt index c6ae5180..08eddca0 100644 --- a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt +++ b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt @@ -120,12 +120,12 @@ class ScenarioIntegrationTest { { assertEquals(0, monitor.tasksActive, "All VMs should finish after a run") }, { assertEquals(0, monitor.attemptsFailure, "No VM should be unscheduled") }, { assertEquals(0, monitor.tasksPending, "No VM should not be in the queue") }, - { assertEquals(43101695530, monitor.idleTime) { "Incorrect idle time" } }, - { assertEquals(3489503997, monitor.activeTime) { "Incorrect active time" } }, - { assertEquals(142, monitor.stealTime) { "Incorrect steal time" } }, + { assertEquals(43101769345, monitor.idleTime) { "Incorrect idle time" } }, + { assertEquals(3489430672, monitor.activeTime) { "Incorrect active time" } }, + { assertEquals(0, monitor.stealTime) { "Incorrect steal time" } }, { assertEquals(0, monitor.lostTime) { "Incorrect lost time" } }, { assertEquals(3.3388920269258898E7, monitor.powerDraw, 1E4) { "Incorrect power draw" } }, - { assertEquals(1.0016142948422823E10, monitor.energyUsage, 1E4) { "Incorrect energy usage" } }, + { assertEquals(1.0016127451211525E10, monitor.energyUsage, 1E4) { "Incorrect energy usage" } }, ) } @@ -162,9 +162,9 @@ class ScenarioIntegrationTest { // Note that these values have been verified beforehand assertAll( - { assertEquals(1373412033, monitor.idleTime) { "Idle time incorrect" } }, - { assertEquals(1217675912, monitor.activeTime) { "Active time incorrect" } }, - { assertEquals(19, monitor.stealTime) { "Steal time incorrect" } }, + { assertEquals(1373419781, monitor.idleTime) { "Idle time incorrect" } }, + { assertEquals(1217668222, monitor.activeTime) { "Active time incorrect" } }, + { assertEquals(0, monitor.stealTime) { "Steal time incorrect" } }, { assertEquals(0, monitor.lostTime) { "Lost time incorrect" } }, { assertEquals(2539987.394500494, monitor.powerDraw, 1E4) { "Incorrect power draw" } }, { assertEquals(7.617527900379665E8, monitor.energyUsage, 1E4) { "Incorrect energy usage" } }, diff --git a/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt index 346059a8..49d7d489 100644 --- a/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt +++ b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt @@ -30,10 +30,9 @@ import org.opendc.faas.service.FaaSService import org.opendc.faas.service.autoscaler.FunctionTerminationPolicyFixed import org.opendc.faas.service.router.RandomRoutingPolicy import org.opendc.faas.simulator.delay.ColdStartModel +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.kotlin.runSimulation import java.io.File import java.time.Duration @@ -80,13 +79,11 @@ class FaaSExperiment { * Construct the machine model to test with. */ private fun createMachineModel(): MachineModel { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - return MachineModel( // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, + Cpu(0, 2, 1000.0, "Intel", "Xeon", "amd64"), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) } } diff --git a/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/core/SimTFDevice.kt b/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/core/SimTFDevice.kt index 1a99cedf..11e010ec 100644 --- a/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/core/SimTFDevice.kt +++ b/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/core/SimTFDevice.kt @@ -29,9 +29,9 @@ import org.opendc.simulator.compute.SimBareMetalMachine import org.opendc.simulator.compute.SimMachine import org.opendc.simulator.compute.SimMachineContext import org.opendc.simulator.compute.SimPsuFactories +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit -import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.power.CpuPowerModel import org.opendc.simulator.compute.workload.SimWorkload import org.opendc.simulator.flow2.FlowEngine @@ -52,7 +52,7 @@ public class SimTFDevice( override val uid: UUID, override val isGpu: Boolean, dispatcher: Dispatcher, - pu: ProcessingUnit, + pu: Cpu, private val memory: MemoryUnit, powerModel: CpuPowerModel, ) : TFDevice { @@ -62,7 +62,7 @@ public class SimTFDevice( private val machine = SimBareMetalMachine.create( FlowEngine.create(dispatcher).newGraph(), - MachineModel(listOf(pu), listOf(memory)), + MachineModel(pu, memory), SimPsuFactories.simple(powerModel), ) @@ -108,7 +108,7 @@ public class SimTFDevice( output = stage.getOutlet("out") lastPull = ctx.graph.engine.clock.millis() - ctx.graph.connect(output, ctx.cpus[0].input) + ctx.graph.connect(output, ctx.cpu.input) } override fun onStop(ctx: SimMachineContext) { diff --git a/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/util/MLEnvironmentReader.kt b/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/util/MLEnvironmentReader.kt index 077bcc04..34b4bc7b 100644 --- a/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/util/MLEnvironmentReader.kt +++ b/opendc-experiments/opendc-experiments-tf20/src/main/kotlin/org/opendc/experiments/tf20/util/MLEnvironmentReader.kt @@ -25,10 +25,9 @@ package org.opendc.experiments.tf20.util import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.CpuPowerModels import java.io.InputStream import java.util.UUID @@ -54,36 +53,50 @@ public class MLEnvironmentReader { var maxPower = 350.0 var minPower = 200.0 val cores = - machine.cpus.flatMap { id -> + machine.cpus.map { id -> when (id) { 1 -> { // ref: https://www.guru3d.com/articles-pages/nvidia-geforce-gtx-titan-x-review,8.html#:~:text=GeForce%20GTX%20Titan%20X%20%2D%20On,power%20supply%20unit%20as%20minimum. - maxPower = 334.0 - minPower = 90.0 - val node = ProcessingNode("NVidia", "TITAN X", "Pascal", 4992) - List(node.coreCount) { ProcessingUnit(node, it, 824.0) } + Cpu( + 0, + 4992, + 824.0, + "NVidia", + "TITAN X", + "Pascal", + ) } 2 -> { // ref: https://www.microway.com/hpc-tech-tips/nvidia-tesla-p100-pci-e-16gb-gpu-accelerator-pascal-gp100-close/ - maxPower = 250.0 - minPower = 125.0 - val node = ProcessingNode("NVIDIA", "Tesla P100", "Pascal", 3584) - List(node.coreCount) { ProcessingUnit(node, it, 1190.0) } + Cpu( + 0, + 3584, + 1190.0, + "NVIDIA", + "Tesla P100", + "Pascal", + ) } 3 -> { // ref: https://www.anandtech.com/show/10923/openpower-saga-tyans-1u-power8-gt75/7 - minPower = 84.0 - maxPower = 135.0 - val node = ProcessingNode("Intel", "E5-2690v3 Haswell24", "amd64", 24) - isGpuFlag = false - List(node.coreCount) { ProcessingUnit(node, it, 3498.0) } + Cpu( + 0, + 24, + 3498.0, + "Intel", + "E5-2690v3 Haswell24", + "amd64", + ) } 4 -> { - minPower = 130.0 - maxPower = 190.0 - val node = ProcessingNode("IBM", "POWER8", "RISC", 10) - isGpuFlag = false - List(node.coreCount) { ProcessingUnit(node, it, 143000.0) } // 28600.0 3690 + Cpu( + 0, + 10, + 143000.0, + "IBM", + "POWER8", + "RISC", + ) } else -> throw IllegalArgumentException("The cpu id $id is not recognized") } @@ -103,7 +116,7 @@ public class MLEnvironmentReader { UUID(0, counter.toLong()), "node-${counter++}", mapOf("gpu" to isGpuFlag), - MachineModel(cores, memories), + MachineModel(cores, memories[0]), CpuPowerModels.linear(maxPower, minPower), ) } diff --git a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt index 28a77c2e..447827e9 100644 --- a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt +++ b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/TensorFlowTest.kt @@ -49,8 +49,8 @@ class TensorFlowTest { def.uid, def.meta["gpu"] as Boolean, dispatcher, - def.model.cpus[0], - def.model.memory[0], + def.model.cpu, + def.model.memory, CpuPowerModels.linear(250.0, 60.0), ) val strategy = OneDeviceStrategy(device) @@ -84,8 +84,8 @@ class TensorFlowTest { def.uid, def.meta["gpu"] as Boolean, dispatcher, - def.model.cpus[0], - def.model.memory[0], + def.model.cpu, + def.model.memory, CpuPowerModels.linear(250.0, 60.0), ) val strategy = OneDeviceStrategy(device) @@ -119,8 +119,8 @@ class TensorFlowTest { def.uid, def.meta["gpu"] as Boolean, dispatcher, - def.model.cpus[0], - def.model.memory[0], + def.model.cpu, + def.model.memory, CpuPowerModels.linear(250.0, 60.0), ) @@ -129,8 +129,8 @@ class TensorFlowTest { UUID.randomUUID(), def.meta["gpu"] as Boolean, dispatcher, - def.model.cpus[0], - def.model.memory[0], + def.model.cpu, + def.model.memory, CpuPowerModels.linear(250.0, 60.0), ) diff --git a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt index 76473868..e0c4599a 100644 --- a/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt +++ b/opendc-experiments/opendc-experiments-tf20/src/test/kotlin/org/opendc/experiments/tf20/core/SimTFDeviceTest.kt @@ -27,9 +27,8 @@ import kotlinx.coroutines.launch import org.junit.jupiter.api.Assertions.assertAll import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test +import org.opendc.simulator.compute.model.Cpu 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.CpuPowerModels import org.opendc.simulator.kotlin.runSimulation import java.util.UUID @@ -41,8 +40,7 @@ internal class SimTFDeviceTest { @Test fun testSmoke() = runSimulation { - val puNode = ProcessingNode("NVIDIA", "Tesla V100", "unknown", 1) - val pu = ProcessingUnit(puNode, 0, 960 * 1230.0) + val pu = Cpu(0, 1, 960 * 1230.0, "NVIDIA", "Tesla V100", "unknown") val memory = MemoryUnit("NVIDIA", "Tesla V100", 877.0, 32_000) val device = diff --git a/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt b/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt index f68860e3..2d6d4ac8 100644 --- a/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt +++ b/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt @@ -36,10 +36,9 @@ import org.opendc.faas.service.router.RandomRoutingPolicy import org.opendc.faas.simulator.delay.ColdStartModel import org.opendc.faas.simulator.delay.StochasticDelayInjector import org.opendc.faas.simulator.workload.SimFaaSWorkload +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.workload.SimWorkload import org.opendc.simulator.compute.workload.SimWorkloads import org.opendc.simulator.kotlin.runSimulation @@ -54,12 +53,17 @@ internal class SimFaaSServiceTest { @BeforeEach fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = MachineModel( - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + Cpu( + 0, + 2, + 1000.0, + "Intel", + "Xeon", + "amd64", + ), + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) } diff --git a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt index 3707b601..5975f944 100644 --- a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt +++ b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt @@ -25,10 +25,10 @@ package org.opendc.simulator.compute import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import org.opendc.simulator.compute.kernel.SimHypervisor +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.workload.SimTrace import org.opendc.simulator.flow2.FlowEngine import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory @@ -59,7 +59,13 @@ class SimMachineBenchmarks { machineModel = MachineModel( // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, + List(cpuNode.coreCount) { + Cpu( + cpuNode, + it, + 1000.0, + ) + }, // memory List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, ) diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java index af56f248..3a9e35c1 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java @@ -23,7 +23,6 @@ package org.opendc.simulator.compute; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.function.Consumer; import org.opendc.simulator.compute.device.SimNetworkAdapter; @@ -43,7 +42,7 @@ import org.opendc.simulator.flow2.util.FlowTransforms; public abstract class SimAbstractMachine implements SimMachine { private final MachineModel model; - private Context activeContext; + private SimAbstractMachineContext activeContext; /** * Construct a {@link SimAbstractMachine} instance. @@ -66,40 +65,40 @@ public abstract class SimAbstractMachine implements SimMachine { throw new IllegalStateException("A machine cannot run multiple workloads concurrently"); } - final Context ctx = createContext(workload, new HashMap<>(meta), completion); + final SimAbstractMachineContext ctx = createContext(workload, new HashMap<>(meta), completion); ctx.start(); return ctx; } @Override public final void cancel() { - final Context context = activeContext; + final SimAbstractMachineContext context = activeContext; if (context != null) { context.shutdown(); } } /** - * Construct a new {@link Context} instance representing the active execution. + * Construct a new {@link SimAbstractMachineContext} instance representing the active execution. * * @param workload The workload to start on the machine. * @param meta The metadata to pass to the workload. * @param completion A block that is invoked when the workload completes carrying an exception if thrown by the workload. */ - protected abstract Context createContext( + protected abstract SimAbstractMachineContext createContext( SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion); /** - * Return the active {@link Context} instance (if any). + * Return the active {@link SimAbstractMachineContext} instance (if any). */ - protected Context getActiveContext() { + protected SimAbstractMachineContext getActiveContext() { return activeContext; } /** * The execution context in which the workload runs. */ - public abstract static class Context implements SimMachineContext { + public abstract static class SimAbstractMachineContext implements SimMachineContext { private final SimAbstractMachine machine; private final SimWorkload workload; private final Map<String, Object> meta; @@ -108,14 +107,14 @@ public abstract class SimAbstractMachine implements SimMachine { private SimWorkload snapshot; /** - * Construct a new {@link Context} instance. + * Construct a new {@link SimAbstractMachineContext} instance. * * @param machine The {@link SimAbstractMachine} to which the context belongs. * @param workload The {@link SimWorkload} to which the context belongs. * @param meta The metadata passed to the context. * @param completion A block that is invoked when the workload completes carrying an exception if thrown by the workload. */ - public Context( + public SimAbstractMachineContext( SimAbstractMachine machine, SimWorkload workload, Map<String, Object> meta, @@ -145,10 +144,8 @@ public abstract class SimAbstractMachine implements SimMachine { public void reset() { final FlowGraph graph = getMemory().getInput().getGraph(); - for (SimProcessingUnit cpu : getCpus()) { - final Inlet inlet = cpu.getInput(); - graph.disconnect(inlet); - } + final Inlet inlet = getCpu().getInput(); + graph.disconnect(inlet); graph.disconnect(getMemory().getInput()); @@ -225,16 +222,12 @@ public abstract class SimAbstractMachine implements SimMachine { */ public static final class Memory implements SimMemory { private final SimpleFlowSink sink; - private final List<MemoryUnit> models; + private final MemoryUnit memoryUnit; - public Memory(FlowGraph graph, List<MemoryUnit> models) { - long memorySize = 0; - for (MemoryUnit mem : models) { - memorySize += mem.getSize(); - } + public Memory(FlowGraph graph, MemoryUnit memoryUnit) { - this.sink = new SimpleFlowSink(graph, (float) memorySize); - this.models = models; + this.memoryUnit = memoryUnit; + this.sink = new SimpleFlowSink(graph, (float) memoryUnit.getSize()); } @Override @@ -243,8 +236,8 @@ public abstract class SimAbstractMachine implements SimMachine { } @Override - public List<MemoryUnit> getModels() { - return models; + public MemoryUnit getMemoryUnit() { + return memoryUnit; } @Override diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java index 11356eb2..6acc605e 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java @@ -28,8 +28,8 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; import org.opendc.simulator.compute.device.SimPeripheral; +import org.opendc.simulator.compute.model.Cpu; import org.opendc.simulator.compute.model.MachineModel; -import org.opendc.simulator.compute.model.ProcessingUnit; import org.opendc.simulator.compute.workload.SimWorkload; import org.opendc.simulator.flow2.FlowGraph; import org.opendc.simulator.flow2.InPort; @@ -56,7 +56,7 @@ public final class SimBareMetalMachine extends SimAbstractMachine { /** * The resources of this machine. */ - private final List<Cpu> cpus; + private final SimCpu cpu; private final Memory memory; private final List<NetworkAdapter> net; @@ -75,13 +75,7 @@ public final class SimBareMetalMachine extends SimAbstractMachine { this.graph = graph; this.psu = psuFactory.newPsu(this, graph); - int cpuIndex = 0; - final ArrayList<Cpu> cpus = new ArrayList<>(); - this.cpus = cpus; - for (ProcessingUnit cpu : model.getCpus()) { - cpus.add(new Cpu(psu, cpu, cpuIndex++)); - } - + this.cpu = new SimCpu(psu, model.getCpu(), 0); this.memory = new Memory(graph, model.getMemory()); int netIndex = 0; @@ -139,76 +133,58 @@ public final class SimBareMetalMachine extends SimAbstractMachine { * Return the CPU capacity of the machine in MHz. */ public double getCpuCapacity() { - final Context context = (Context) getActiveContext(); + final SimAbstractMachineContext context = (SimAbstractMachineContext) getActiveContext(); if (context == null) { return 0.0; } - float capacity = 0.f; - - for (SimProcessingUnit cpu : context.cpus) { - capacity += cpu.getFrequency(); - } - - return capacity; + return cpu.getFrequency(); } /** * The CPU demand of the machine in MHz. */ public double getCpuDemand() { - final Context context = (Context) getActiveContext(); + final SimAbstractMachineContext context = (SimAbstractMachineContext) getActiveContext(); if (context == null) { return 0.0; } - float demand = 0.f; - - for (SimProcessingUnit cpu : context.cpus) { - demand += cpu.getDemand(); - } - - return demand; + return cpu.getDemand(); } /** * The CPU usage of the machine in MHz. */ public double getCpuUsage() { - final Context context = (Context) getActiveContext(); + final SimAbstractMachineContext context = (SimAbstractMachineContext) getActiveContext(); if (context == null) { return 0.0; } - float rate = 0.f; - - for (SimProcessingUnit cpu : context.cpus) { - rate += cpu.getSpeed(); - } - - return rate; + return cpu.getSpeed(); } @Override - protected SimAbstractMachine.Context createContext( + protected SimAbstractMachine.SimAbstractMachineContext createContext( SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion) { - return new Context(this, workload, meta, completion); + return new SimAbstractMachineContext(this, workload, meta, completion); } /** * The execution context for a {@link SimBareMetalMachine}. */ - private static final class Context extends SimAbstractMachine.Context { + private static final class SimAbstractMachineContext extends SimAbstractMachine.SimAbstractMachineContext { private final FlowGraph graph; - private final List<Cpu> cpus; + private final SimCpu cpu; private final Memory memory; private final List<NetworkAdapter> net; private final List<StorageDevice> disk; - private Context( + private SimAbstractMachineContext( SimBareMetalMachine machine, SimWorkload workload, Map<String, Object> meta, @@ -216,7 +192,7 @@ public final class SimBareMetalMachine extends SimAbstractMachine { super(machine, workload, meta, completion); this.graph = machine.graph; - this.cpus = machine.cpus; + this.cpu = machine.cpu; this.memory = machine.memory; this.net = machine.net; this.disk = machine.disk; @@ -228,8 +204,8 @@ public final class SimBareMetalMachine extends SimAbstractMachine { } @Override - public List<? extends SimProcessingUnit> getCpus() { - return cpus; + public SimCpu getCpu() { + return cpu; } @Override @@ -251,17 +227,17 @@ public final class SimBareMetalMachine extends SimAbstractMachine { /** * A {@link SimProcessingUnit} of a bare-metal machine. */ - private static final class Cpu implements SimProcessingUnit { + private static final class SimCpu implements SimProcessingUnit { private final SimPsu psu; - private final ProcessingUnit model; + private final Cpu cpuModel; private final InPort port; - private Cpu(SimPsu psu, ProcessingUnit model, int id) { + private SimCpu(SimPsu psu, Cpu cpuModel, int id) { this.psu = psu; - this.model = model; - this.port = psu.getCpuPower(id, model); + this.cpuModel = cpuModel; + this.port = psu.getCpuPower(id, cpuModel); - this.port.pull((float) model.getFrequency()); + this.port.pull((float) cpuModel.getTotalCapacity()); } @Override @@ -272,7 +248,7 @@ public final class SimBareMetalMachine extends SimAbstractMachine { @Override public void setFrequency(double frequency) { // Clamp the capacity of the CPU between [0.0, maxFreq] - frequency = Math.max(0, Math.min(model.getFrequency(), frequency)); + frequency = Math.max(0, Math.min(cpuModel.getTotalCapacity(), frequency)); psu.setCpuFrequency(port, frequency); } @@ -287,8 +263,8 @@ public final class SimBareMetalMachine extends SimAbstractMachine { } @Override - public ProcessingUnit getModel() { - return model; + public org.opendc.simulator.compute.model.Cpu getCpuModel() { + return cpuModel; } @Override @@ -298,7 +274,7 @@ public final class SimBareMetalMachine extends SimAbstractMachine { @Override public String toString() { - return "SimBareMetalMachine.Cpu[model=" + model + "]"; + return "SimBareMetalMachine.Cpu[model=" + cpuModel + "]"; } } } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java index 7f98dee5..887967fb 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java @@ -51,7 +51,7 @@ public interface SimMachineContext { /** * Return the CPUs available on the machine. */ - List<? extends SimProcessingUnit> getCpus(); + SimProcessingUnit getCpu(); /** * Return the memory interface of the machine. diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java index 4fcc64ab..85027f28 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java @@ -22,7 +22,6 @@ package org.opendc.simulator.compute; -import java.util.List; import org.opendc.simulator.compute.model.MemoryUnit; import org.opendc.simulator.flow2.sink.FlowSink; @@ -38,5 +37,5 @@ public interface SimMemory extends FlowSink { /** * Return the models representing the static information of the memory units supporting this interface. */ - List<MemoryUnit> getModels(); + MemoryUnit getMemoryUnit(); } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java index 3dbd3656..213c3d4f 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java @@ -22,7 +22,7 @@ package org.opendc.simulator.compute; -import org.opendc.simulator.compute.model.ProcessingUnit; +import org.opendc.simulator.compute.model.Cpu; import org.opendc.simulator.flow2.sink.FlowSink; /** @@ -58,5 +58,5 @@ public interface SimProcessingUnit extends FlowSink { /** * The model representing the static properties of the processing unit. */ - ProcessingUnit getModel(); + Cpu getCpuModel(); } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java index 68dae4bf..e7718604 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java @@ -22,7 +22,7 @@ package org.opendc.simulator.compute; -import org.opendc.simulator.compute.model.ProcessingUnit; +import org.opendc.simulator.compute.model.Cpu; import org.opendc.simulator.flow2.InPort; import org.opendc.simulator.power.SimPowerInlet; @@ -57,7 +57,7 @@ public abstract class SimPsu extends SimPowerInlet { * @param id The unique identifier of the CPU for this machine. * @param model The details of the processing unit. */ - abstract InPort getCpuPower(int id, ProcessingUnit model); + abstract InPort getCpuPower(int id, Cpu model); /** * This method is invoked when the CPU frequency is changed for the specified <code>port</code>. diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java index 5b118429..27327616 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java @@ -24,7 +24,7 @@ package org.opendc.simulator.compute; import java.time.InstantSource; import org.jetbrains.annotations.NotNull; -import org.opendc.simulator.compute.model.ProcessingUnit; +import org.opendc.simulator.compute.model.Cpu; import org.opendc.simulator.compute.power.CpuPowerModel; import org.opendc.simulator.flow2.FlowGraph; import org.opendc.simulator.flow2.FlowStage; @@ -92,7 +92,7 @@ public class SimPsuFactories { } @Override - InPort getCpuPower(int id, ProcessingUnit model) { + InPort getCpuPower(int id, Cpu model) { final InPort port = stage.getInlet("cpu" + id); port.setMask(true); return port; @@ -165,8 +165,8 @@ public class SimPsuFactories { } @Override - InPort getCpuPower(int id, ProcessingUnit model) { - targetFreq += model.getFrequency(); + InPort getCpuPower(int id, Cpu model) { + targetFreq += model.getTotalCapacity(); final InPort port = stage.getInlet("cpu" + id); port.setHandler(handler); diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java index aced54a7..42750b0f 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Map; import java.util.SplittableRandom; import java.util.function.Consumer; -import java.util.stream.Collectors; import org.opendc.simulator.compute.SimAbstractMachine; import org.opendc.simulator.compute.SimMachine; import org.opendc.simulator.compute.SimMachineContext; @@ -44,8 +43,8 @@ import org.opendc.simulator.compute.kernel.cpufreq.ScalingPolicy; import org.opendc.simulator.compute.kernel.interference.VmInterferenceDomain; import org.opendc.simulator.compute.kernel.interference.VmInterferenceMember; import org.opendc.simulator.compute.kernel.interference.VmInterferenceProfile; +import org.opendc.simulator.compute.model.Cpu; import org.opendc.simulator.compute.model.MachineModel; -import org.opendc.simulator.compute.model.ProcessingUnit; import org.opendc.simulator.compute.workload.SimWorkload; import org.opendc.simulator.flow2.FlowGraph; import org.opendc.simulator.flow2.FlowStage; @@ -68,8 +67,8 @@ public final class SimHypervisor implements SimWorkload { private final ScalingGovernorFactory scalingGovernorFactory; private final VmInterferenceDomain interferenceDomain; - private Context activeContext; - private final ArrayList<VirtualMachine> vms = new ArrayList<>(); + private SimHyperVisorContext activeContext; + private final ArrayList<SimVirtualMachine> vms = new ArrayList<>(); private final HvCounters counters = new HvCounters(); @Override @@ -156,7 +155,7 @@ public final class SimHypervisor implements SimWorkload { throw new IllegalArgumentException("Machine does not fit"); } - VirtualMachine vm = new VirtualMachine(model); + SimVirtualMachine vm = new SimVirtualMachine(model); vms.add(vm); return vm; } @@ -169,7 +168,7 @@ public final class SimHypervisor implements SimWorkload { public void removeMachine(SimVirtualMachine machine) { if (vms.remove(machine)) { // This cast must always succeed, since `_vms` only contains `VirtualMachine` types. - ((VirtualMachine) machine).close(); + ((SimVirtualMachine) machine).close(); } } @@ -177,7 +176,7 @@ public final class SimHypervisor implements SimWorkload { * Return the CPU capacity of the hypervisor in MHz. */ public double getCpuCapacity() { - final Context context = activeContext; + final SimHyperVisorContext context = activeContext; if (context == null) { return 0.0; @@ -190,7 +189,7 @@ public final class SimHypervisor implements SimWorkload { * The CPU demand of the hypervisor in MHz. */ public double getCpuDemand() { - final Context context = activeContext; + final SimHyperVisorContext context = activeContext; if (context == null) { return 0.0; @@ -203,7 +202,7 @@ public final class SimHypervisor implements SimWorkload { * The CPU usage of the hypervisor in MHz. */ public double getCpuUsage() { - final Context context = activeContext; + final SimHyperVisorContext context = activeContext; if (context == null) { return 0.0; @@ -217,26 +216,26 @@ public final class SimHypervisor implements SimWorkload { * moment. */ public boolean canFit(MachineModel model) { - final Context context = activeContext; + final SimHyperVisorContext context = activeContext; if (context == null) { return false; } final FlowMultiplexer multiplexer = context.multiplexer; - return (multiplexer.getMaxInputs() - multiplexer.getInputCount()) - >= model.getCpus().size(); + return (multiplexer.getMaxInputs() - multiplexer.getInputCount()) >= 1; } @Override public void onStart(SimMachineContext ctx) { - final Context context = new Context(ctx, muxFactory, scalingGovernorFactory, counters); + final SimHyperVisorContext context = + new SimHyperVisorContext(ctx, muxFactory, scalingGovernorFactory, counters); context.start(); activeContext = context; } @Override public void onStop(SimMachineContext ctx) { - final Context context = activeContext; + final SimHyperVisorContext context = activeContext; if (context != null) { activeContext = null; context.stop(); @@ -276,11 +275,11 @@ public final class SimHypervisor implements SimWorkload { /** * The context which carries the state when the hypervisor is running on a machine. */ - private static final class Context implements FlowStageLogic { + private static final class SimHyperVisorContext implements FlowStageLogic { private final SimMachineContext ctx; private final FlowMultiplexer multiplexer; private final FlowStage stage; - private final List<ScalingGovernor> scalingGovernors; + private final ScalingGovernor scalingGovernor; private final InstantSource clock; private final HvCounters counters; @@ -290,7 +289,7 @@ public final class SimHypervisor implements SimWorkload { private float previousRate; private float previousCapacity; - private Context( + private SimHyperVisorContext( SimMachineContext ctx, FlowMultiplexerFactory muxFactory, ScalingGovernorFactory scalingGovernorFactory, @@ -306,20 +305,15 @@ public final class SimHypervisor implements SimWorkload { this.lastCounterUpdate = clock.millis(); + final SimProcessingUnit cpu = ctx.getCpu(); + if (scalingGovernorFactory != null) { - this.scalingGovernors = ctx.getCpus().stream() - .map(cpu -> scalingGovernorFactory.newGovernor(new ScalingPolicyImpl(cpu))) - .collect(Collectors.toList()); + this.scalingGovernor = scalingGovernorFactory.newGovernor(new ScalingPolicyImpl(cpu)); } else { - this.scalingGovernors = Collections.emptyList(); + this.scalingGovernor = null; } - float cpuCapacity = 0.f; - final List<? extends SimProcessingUnit> cpus = ctx.getCpus(); - for (SimProcessingUnit cpu : cpus) { - cpuCapacity += cpu.getFrequency(); - } - this.d = cpus.size() / cpuCapacity; + this.d = 1 / cpu.getFrequency(); } /** @@ -329,12 +323,10 @@ public final class SimHypervisor implements SimWorkload { final FlowGraph graph = ctx.getGraph(); final FlowMultiplexer multiplexer = this.multiplexer; - for (SimProcessingUnit cpu : ctx.getCpus()) { - graph.connect(multiplexer.newOutput(), cpu.getInput()); - } + graph.connect(multiplexer.newOutput(), ctx.getCpu().getInput()); - for (ScalingGovernor governor : scalingGovernors) { - governor.onStart(); + if (this.scalingGovernor != null) { + this.scalingGovernor.onStart(); } } @@ -392,7 +384,7 @@ public final class SimHypervisor implements SimWorkload { updateCounters(now); final FlowMultiplexer multiplexer = this.multiplexer; - final List<ScalingGovernor> scalingGovernors = this.scalingGovernors; + final ScalingGovernor scalingGovernors = this.scalingGovernor; float demand = multiplexer.getDemand(); float rate = multiplexer.getRate(); @@ -404,10 +396,8 @@ public final class SimHypervisor implements SimWorkload { double load = rate / Math.min(1.0, capacity); - if (!scalingGovernors.isEmpty()) { - for (ScalingGovernor governor : scalingGovernors) { - governor.onLimit(load); - } + if (scalingGovernor != null) { + scalingGovernor.onLimit(load); } return Long.MAX_VALUE; @@ -446,27 +436,25 @@ public final class SimHypervisor implements SimWorkload { @Override public double getMax() { - return cpu.getModel().getFrequency(); + return cpu.getCpuModel().getTotalCapacity(); } } /** * A virtual machine running on the hypervisor. */ - private class VirtualMachine extends SimAbstractMachine implements SimVirtualMachine { + public class SimVirtualMachine extends SimAbstractMachine { private boolean isClosed; private final VmCounters counters = new VmCounters(this); - private VirtualMachine(MachineModel model) { + private SimVirtualMachine(MachineModel model) { super(model); } - @Override public SimHypervisorCounters getCounters() { return counters; } - @Override public double getCpuDemand() { final VmContext context = (VmContext) getActiveContext(); @@ -477,7 +465,6 @@ public final class SimHypervisor implements SimWorkload { return context.previousDemand; } - @Override public double getCpuUsage() { final VmContext context = (VmContext) getActiveContext(); @@ -488,7 +475,6 @@ public final class SimHypervisor implements SimWorkload { return context.usage; } - @Override public double getCpuCapacity() { final VmContext context = (VmContext) getActiveContext(); @@ -505,13 +491,13 @@ public final class SimHypervisor implements SimWorkload { } @Override - protected Context createContext( + protected SimAbstractMachineContext createContext( SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion) { if (isClosed) { throw new IllegalStateException("Virtual machine does not exist anymore"); } - final SimHypervisor.Context context = activeContext; + final SimHyperVisorContext context = activeContext; if (context == null) { throw new IllegalStateException("Hypervisor is inactive"); } @@ -529,7 +515,7 @@ public final class SimHypervisor implements SimWorkload { } @Override - public Context getActiveContext() { + public SimAbstractMachineContext getActiveContext() { return super.getActiveContext(); } @@ -544,10 +530,11 @@ public final class SimHypervisor implements SimWorkload { } /** - * A {@link SimAbstractMachine.Context} for a virtual machine instance. + * A {@link SimAbstractMachine.SimAbstractMachineContext} for a virtual machine instance. */ - private static final class VmContext extends SimAbstractMachine.Context implements FlowStageLogic { - private final Context context; + private static final class VmContext extends SimAbstractMachine.SimAbstractMachineContext + implements FlowStageLogic { + private final SimHyperVisorContext simHyperVisorContext; private final SplittableRandom random; private final VmCounters vmCounters; private final HvCounters hvCounters; @@ -556,7 +543,7 @@ public final class SimHypervisor implements SimWorkload { private final FlowMultiplexer multiplexer; private final InstantSource clock; - private final List<VCpu> cpus; + private final VCpu cpu; private final SimAbstractMachine.Memory memory; private final List<SimAbstractMachine.NetworkAdapter> net; private final List<SimAbstractMachine.StorageDevice> disk; @@ -574,8 +561,8 @@ public final class SimHypervisor implements SimWorkload { private float previousCapacity; private VmContext( - Context context, - VirtualMachine machine, + SimHyperVisorContext simHyperVisorContext, + SimVirtualMachine machine, SplittableRandom random, VmInterferenceDomain interferenceDomain, VmCounters vmCounters, @@ -585,11 +572,11 @@ public final class SimHypervisor implements SimWorkload { Consumer<Exception> completion) { super(machine, workload, meta, completion); - this.context = context; + this.simHyperVisorContext = simHyperVisorContext; this.random = random; this.vmCounters = vmCounters; this.hvCounters = hvCounters; - this.clock = context.clock; + this.clock = simHyperVisorContext.clock; final VmInterferenceProfile interferenceProfile = (VmInterferenceProfile) meta.get("interference-profile"); VmInterferenceMember interferenceMember = null; @@ -599,45 +586,36 @@ public final class SimHypervisor implements SimWorkload { } this.interferenceMember = interferenceMember; - final FlowGraph graph = context.ctx.getGraph(); + final FlowGraph graph = simHyperVisorContext.ctx.getGraph(); final FlowStage stage = graph.newStage(this); this.stage = stage; this.lastUpdate = clock.millis(); this.lastCounterUpdate = clock.millis(); - final FlowMultiplexer multiplexer = context.multiplexer; + final FlowMultiplexer multiplexer = simHyperVisorContext.multiplexer; this.multiplexer = multiplexer; final MachineModel model = machine.getModel(); - final List<ProcessingUnit> cpuModels = model.getCpus(); - final Inlet[] muxInlets = new Inlet[cpuModels.size()]; - final ArrayList<VCpu> cpus = new ArrayList<>(); + final Cpu cpuModel = model.getCpu(); + final Inlet[] muxInlets = new Inlet[1]; this.muxInlets = muxInlets; - this.cpus = cpus; - - float capacity = 0.f; - for (int i = 0; i < cpuModels.size(); i++) { - final Inlet muxInlet = multiplexer.newInput(); - muxInlets[i] = muxInlet; + final Inlet muxInlet = multiplexer.newInput(); + muxInlets[0] = muxInlet; - final InPort input = stage.getInlet("cpu" + i); - final OutPort output = stage.getOutlet("mux" + i); + final InPort input = stage.getInlet("cpu"); + final OutPort output = stage.getOutlet("mux"); - final Handler handler = new Handler(this, input, output); - input.setHandler(handler); - output.setHandler(handler); + final Handler handler = new Handler(this, input, output); + input.setHandler(handler); + output.setHandler(handler); - final ProcessingUnit cpuModel = cpuModels.get(i); - capacity += cpuModel.getFrequency(); + this.cpu = new VCpu(cpuModel, input); - final VCpu cpu = new VCpu(cpuModel, input); - cpus.add(cpu); + graph.connect(output, muxInlet); - graph.connect(output, muxInlet); - } - this.d = cpuModels.size() / capacity; + this.d = 1 / cpuModel.getTotalCapacity(); this.memory = new SimAbstractMachine.Memory(graph, model.getMemory()); @@ -664,7 +642,7 @@ public final class SimHypervisor implements SimWorkload { void updateCounters(long now) { long lastUpdate = this.lastCounterUpdate; this.lastCounterUpdate = now; - long delta = now - lastUpdate; + long delta = now - lastUpdate; // time between updates if (delta > 0) { final VmCounters counters = this.vmCounters; @@ -673,7 +651,7 @@ public final class SimHypervisor implements SimWorkload { float rate = this.usage; float capacity = this.previousCapacity; - final double factor = this.d * delta; + final double factor = this.d * delta; // time between divided by total capacity final double active = rate * factor; counters.cpuActiveTime += Math.round(active); @@ -695,8 +673,8 @@ public final class SimHypervisor implements SimWorkload { } @Override - public List<? extends SimProcessingUnit> getCpus() { - return cpus; + public SimProcessingUnit getCpu() { + return cpu; } @Override @@ -746,7 +724,7 @@ public final class SimHypervisor implements SimWorkload { } // Invalidate the FlowStage of the hypervisor to update its counters (via onUpdate) - context.invalidate(); + simHyperVisorContext.invalidate(); return Long.MAX_VALUE; } @@ -776,14 +754,14 @@ public final class SimHypervisor implements SimWorkload { * A {@link SimProcessingUnit} of a virtual machine. */ private static final class VCpu implements SimProcessingUnit { - private final ProcessingUnit model; + private final Cpu model; private final InPort input; - private VCpu(ProcessingUnit model, InPort input) { + private VCpu(Cpu model, InPort input) { this.model = model; this.input = input; - input.pull((float) model.getFrequency()); + input.pull((float) model.getTotalCapacity()); } @Override @@ -807,7 +785,7 @@ public final class SimHypervisor implements SimWorkload { } @Override - public ProcessingUnit getModel() { + public Cpu getCpuModel() { return model; } @@ -901,7 +879,7 @@ public final class SimHypervisor implements SimWorkload { @Override public void sync() { - final Context context = activeContext; + final SimHyperVisorContext context = activeContext; if (context != null) { context.updateCounters(); @@ -913,13 +891,13 @@ public final class SimHypervisor implements SimWorkload { * Implementation of {@link SimHypervisorCounters} for the virtual machine. */ private static class VmCounters implements SimHypervisorCounters { - private final VirtualMachine vm; + private final SimVirtualMachine vm; private long cpuActiveTime; private long cpuIdleTime; private long cpuStealTime; private long cpuLostTime; - private VmCounters(VirtualMachine vm) { + private VmCounters(SimVirtualMachine vm) { this.vm = vm; } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimVirtualMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimVirtualMachine.java deleted file mode 100644 index fdf5e47f..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimVirtualMachine.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022 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.kernel; - -import org.opendc.simulator.compute.SimMachine; - -/** - * A virtual {@link SimMachine} running on top of another {@link SimMachine}. - */ -public interface SimVirtualMachine extends SimMachine { - /** - * Return the performance counters associated with the virtual machine. - */ - SimHypervisorCounters getCounters(); - - /** - * Return the CPU usage of the VM in MHz. - */ - double getCpuUsage(); - - /** - * Return the CPU usage of the VM in MHz. - */ - double getCpuDemand(); - - /** - * Return the CPU capacity of the VM in MHz. - */ - double getCpuCapacity(); -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/Cpu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/Cpu.java new file mode 100644 index 00000000..c319ae1a --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/Cpu.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2022 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.model; + +import java.util.Objects; + +/** + * A single logical compute unit of processor node, either virtual or physical. + */ +public final class Cpu { + private final int id; + private final int coreCount; + private final double coreSpeed; + private final double totalCapacity; + + private final String vendor; + private final String modelName; + private final String arch; + + /** + * Construct a {@link Cpu} instance. + * + * @param id The identifier of the CPU core within the processing node. + * @param coreCount The number of cores present in the CPU + * @param coreSpeed The speed of a single core + * @param vendor The vendor of the CPU + * @param modelName The name of the CPU + * @param arch The architecture of the CPU + */ + public Cpu(int id, int coreCount, double coreSpeed, String vendor, String modelName, String arch) { + this.id = id; + this.coreCount = coreCount; + this.coreSpeed = coreSpeed; + this.totalCapacity = coreSpeed * coreCount; + this.vendor = vendor; + this.modelName = modelName; + this.arch = arch; + } + + public Cpu(int id, int coreCount, double coreSpeed) { + this(id, coreCount, coreSpeed, "unkown", "unkown", "unkown"); + } + + /** + * Return the identifier of the CPU core within the processing node. + */ + public int getId() { + return id; + } + + /** + * Return the number of logical CPUs in the processor node. + */ + public int getCoreCount() { + return coreCount; + } + + /** + * Return the clock rate of a single core of the CPU MHz. + */ + public double getCoreSpeed() { + return coreSpeed; + } + + /** + * Return the clock rate of the CPU in MHz. + */ + public double getTotalCapacity() { + return totalCapacity; + } + + /** + * Return the vendor of the storage device. + */ + public String getVendor() { + return vendor; + } + + /** + * Return the model name of the device. + */ + public String getModelName() { + return modelName; + } + + /** + * Return the micro-architecture of the processor node. + */ + public String getArchitecture() { + return arch; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Cpu that = (Cpu) o; + return id == that.id + && Double.compare(that.totalCapacity, totalCapacity) == 0 + && Double.compare(that.coreSpeed, coreSpeed) == 0 + && Objects.equals(vendor, that.vendor) + && Objects.equals(modelName, that.modelName) + && Objects.equals(arch, that.arch); + } + + @Override + public int hashCode() { + return Objects.hash(id, coreCount, coreSpeed, totalCapacity, vendor, modelName, arch); + } + + @Override + public String toString() { + return "ProcessingUnit[" + "id= " + id + ", coreCount= " + coreCount + ", coreSpeed= " + coreSpeed + + ", frequency= " + totalCapacity + ", vendor= " + vendor + ", modelName= " + modelName + ", arch= " + + arch + "]"; + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java index 2c625fce..e4019dac 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java @@ -31,29 +31,23 @@ import java.util.Objects; * A description of the physical or virtual machine on which a bootable image runs. */ public final class MachineModel { - private final List<ProcessingUnit> cpus; - private final List<MemoryUnit> memory; + private final Cpu cpu; + private final MemoryUnit memory; private final List<NetworkAdapter> net; private final List<StorageDevice> storage; /** * Construct a {@link MachineModel} instance. * - * @param cpus The list of processing units available to the image. + * @param cpu The cpu available to the image. * @param memory The list of memory units available to the image. * @param net A list of network adapters available to the machine. * @param storage A list of storage devices available to the machine. */ - public MachineModel( - Iterable<ProcessingUnit> cpus, - Iterable<MemoryUnit> memory, - Iterable<NetworkAdapter> net, - Iterable<StorageDevice> storage) { - this.cpus = new ArrayList<>(); - cpus.forEach(this.cpus::add); + public MachineModel(Cpu cpu, MemoryUnit memory, Iterable<NetworkAdapter> net, Iterable<StorageDevice> storage) { + this.cpu = cpu; - this.memory = new ArrayList<>(); - memory.forEach(this.memory::add); + this.memory = memory; this.net = new ArrayList<>(); net.forEach(this.net::add); @@ -62,54 +56,50 @@ public final class MachineModel { storage.forEach(this.storage::add); } + public MachineModel(Cpu cpu, MemoryUnit memory) { + this(cpu, memory, Collections.emptyList(), Collections.emptyList()); + } + /** * Construct a {@link MachineModel} instance. + * A list of the same cpus, are automatically converted to a single CPU with the number of cores of + * all cpus in the list combined. * * @param cpus The list of processing units available to the image. * @param memory The list of memory units available to the image. */ - public MachineModel(Iterable<ProcessingUnit> cpus, Iterable<MemoryUnit> memory) { - this(cpus, memory, Collections.emptyList(), Collections.emptyList()); + public MachineModel( + List<Cpu> cpus, MemoryUnit memory, Iterable<NetworkAdapter> net, Iterable<StorageDevice> storage) { + + this( + new Cpu( + cpus.get(0).getId(), + cpus.get(0).getCoreCount() * cpus.size(), + cpus.get(0).getCoreSpeed(), + cpus.get(0).getVendor(), + cpus.get(0).getModelName(), + cpus.get(0).getArchitecture()), + memory, + net, + storage); } - /** - * Optimize the [MachineModel] by merging all resources of the same type into a single resource with the combined - * capacity. Such configurations can be simulated more efficiently by OpenDC. - */ - public MachineModel optimize() { - ProcessingUnit originalCpu = cpus.get(0); - - double freq = 0.0; - for (ProcessingUnit cpu : cpus) { - freq += cpu.getFrequency(); - } - - ProcessingNode originalNode = originalCpu.getNode(); - ProcessingNode processingNode = new ProcessingNode( - originalNode.getVendor(), originalNode.getModelName(), originalNode.getArchitecture(), 1); - ProcessingUnit processingUnit = new ProcessingUnit(processingNode, originalCpu.getId(), freq); - - long memorySize = 0; - for (MemoryUnit mem : memory) { - memorySize += mem.getSize(); - } - MemoryUnit memoryUnit = new MemoryUnit("Generic", "Generic", 3200.0, memorySize); - - return new MachineModel(List.of(processingUnit), List.of(memoryUnit)); + public MachineModel(List<Cpu> cpus, MemoryUnit memory) { + this(cpus, memory, Collections.emptyList(), Collections.emptyList()); } /** * Return the processing units of this machine. */ - public List<ProcessingUnit> getCpus() { - return Collections.unmodifiableList(cpus); + public Cpu getCpu() { + return this.cpu; } /** * Return the memory units of this machine. */ - public List<MemoryUnit> getMemory() { - return Collections.unmodifiableList(memory); + public MemoryUnit getMemory() { + return memory; } /** @@ -131,7 +121,7 @@ public final class MachineModel { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MachineModel that = (MachineModel) o; - return cpus.equals(that.cpus) + return cpu.equals(that.cpu) && memory.equals(that.memory) && net.equals(that.net) && storage.equals(that.storage); @@ -139,11 +129,11 @@ public final class MachineModel { @Override public int hashCode() { - return Objects.hash(cpus, memory, net, storage); + return Objects.hash(cpu, memory, net, storage); } @Override public String toString() { - return "MachineModel[cpus=" + cpus + ",memory=" + memory + ",net=" + net + ",storage=" + storage + "]"; + return "MachineModel[cpus=" + cpu + ",memory=" + memory + ",net=" + net + ",storage=" + storage + "]"; } } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingUnit.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingUnit.java deleted file mode 100644 index 0bead16a..00000000 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingUnit.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2022 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.model; - -import java.util.Objects; - -/** - * A single logical compute unit of processor node, either virtual or physical. - */ -public final class ProcessingUnit { - private final ProcessingNode node; - private final int id; - private final double frequency; - - /** - * Construct a {@link ProcessingUnit} instance. - * - * @param node The processing node containing the CPU core. - * @param id The identifier of the CPU core within the processing node. - * @param frequency The clock rate of the CPU in MHz. - */ - public ProcessingUnit(ProcessingNode node, int id, double frequency) { - this.node = node; - this.id = id; - this.frequency = frequency * node.getCoreCount(); - } - - /** - * Return the processing node containing the CPU core. - */ - public ProcessingNode getNode() { - return node; - } - - /** - * Return the identifier of the CPU core within the processing node. - */ - public int getId() { - return id; - } - - /** - * Return the clock rate of the CPU in MHz. - */ - public double getFrequency() { - return frequency; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ProcessingUnit that = (ProcessingUnit) o; - return id == that.id && Double.compare(that.frequency, frequency) == 0 && Objects.equals(node, that.node); - } - - @Override - public int hashCode() { - return Objects.hash(node, id, frequency); - } - - @Override - public String toString() { - return "ProcessingUnit[node=" + node + ",id=" + id + ",frequency=" + frequency + "]"; - } -} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java index edf201a7..1dcb3674 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java @@ -41,7 +41,7 @@ final class SimChainWorkload implements SimWorkload { private final SimWorkload[] workloads; private int activeWorkloadIndex; - private Context activeContext; + private SimChainWorkloadContext activeContext; private long checkpointInterval = 0; private long checkpointDuration = 0; @@ -108,7 +108,7 @@ final class SimChainWorkload implements SimWorkload { return; } - final Context context = new Context(ctx); + final SimChainWorkloadContext context = new SimChainWorkloadContext(ctx); activeContext = context; if (checkpointInterval > 0) { @@ -128,7 +128,7 @@ final class SimChainWorkload implements SimWorkload { return; } - final Context context = activeContext; + final SimChainWorkloadContext context = activeContext; activeContext = null; if (this.checkpointModel != null) { @@ -174,7 +174,7 @@ final class SimChainWorkload implements SimWorkload { private Boolean firstCheckPoint = true; CheckPointModel( - Context context, + SimChainWorkloadContext context, SimChainWorkload workload, long checkpointInterval, long checkpointDuration, @@ -228,11 +228,11 @@ final class SimChainWorkload implements SimWorkload { /** * A {@link SimMachineContext} that intercepts the shutdown calls. */ - private class Context implements SimMachineContext { + private class SimChainWorkloadContext implements SimMachineContext { private final SimMachineContext ctx; private SimWorkload snapshot; - private Context(SimMachineContext ctx) { + private SimChainWorkloadContext(SimMachineContext ctx) { this.ctx = ctx; } @@ -247,8 +247,8 @@ final class SimChainWorkload implements SimWorkload { } @Override - public List<? extends SimProcessingUnit> getCpus() { - return ctx.getCpus(); + public SimProcessingUnit getCpu() { + return ctx.getCpu(); } @Override diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java index 06fcb2bc..5311fa38 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java @@ -22,7 +22,6 @@ package org.opendc.simulator.compute.workload; -import java.util.List; import org.opendc.simulator.compute.SimMachineContext; import org.opendc.simulator.compute.SimProcessingUnit; import org.opendc.simulator.flow2.FlowGraph; @@ -92,17 +91,14 @@ public class SimFlopsWorkload implements SimWorkload, FlowStageLogic { final FlowStage stage = graph.newStage(this); this.stage = stage; - final List<? extends SimProcessingUnit> cpus = ctx.getCpus(); - final OutPort[] outputs = new OutPort[cpus.size()]; + final SimProcessingUnit cpu = ctx.getCpu(); + final OutPort[] outputs = new OutPort[1]; this.outputs = outputs; - for (int i = 0; i < cpus.size(); i++) { - final SimProcessingUnit cpu = cpus.get(i); - final OutPort output = stage.getOutlet("cpu" + i); + final OutPort output = stage.getOutlet("cpu"); - graph.connect(output, cpu.getInput()); - outputs[i] = output; - } + graph.connect(output, cpu.getInput()); + outputs[0] = output; this.remainingAmount = flops; this.lastUpdate = graph.getEngine().getClock().millis(); diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java index 64b1a10b..be4cc2f5 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java @@ -22,7 +22,6 @@ package org.opendc.simulator.compute.workload; -import java.util.List; import org.opendc.simulator.compute.SimMachineContext; import org.opendc.simulator.compute.SimProcessingUnit; import org.opendc.simulator.flow2.FlowGraph; @@ -122,17 +121,14 @@ public class SimRuntimeWorkload implements SimWorkload, FlowStageLogic { final FlowStage stage = graph.newStage(this); this.stage = stage; - final List<? extends SimProcessingUnit> cpus = ctx.getCpus(); - final OutPort[] outputs = new OutPort[cpus.size()]; + final OutPort[] outputs = new OutPort[1]; this.outputs = outputs; - for (int i = 0; i < cpus.size(); i++) { - final SimProcessingUnit cpu = cpus.get(i); - final OutPort output = stage.getOutlet("cpu" + i); + final SimProcessingUnit cpu = ctx.getCpu(); + final OutPort output = stage.getOutlet("cpu"); - graph.connect(output, cpu.getInput()); - outputs[i] = output; - } + graph.connect(output, cpu.getInput()); + outputs[0] = output; this.remainingDuration = duration; this.lastUpdate = graph.getEngine().getClock().millis(); diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java index 384907b2..b8445a9c 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java @@ -210,11 +210,7 @@ public final class SimTrace { @Override public void onStart(SimMachineContext ctx) { final WorkloadStageLogic logic; - if (ctx.getCpus().size() == 1) { - logic = new SingleWorkloadLogic(ctx, offset, fragments.iterator()); - } else { - logic = new MultiWorkloadLogic(ctx, offset, fragments.iterator()); - } + logic = new SingleWorkloadLogic(ctx, offset, fragments.iterator()); this.logic = logic; } @@ -325,11 +321,9 @@ public final class SimTrace { this.fragments = fragments; final FlowGraph graph = ctx.getGraph(); - final List<? extends SimProcessingUnit> cpus = ctx.getCpus(); - stage = graph.newStage(this); - final SimProcessingUnit cpu = cpus.get(0); + final SimProcessingUnit cpu = ctx.getCpu(); final OutPort output = stage.getOutlet("cpu"); this.output = output; @@ -416,149 +410,4 @@ public final class SimTrace { return Long.MAX_VALUE; } } - - /** - * Implementation of {@link FlowStageLogic} for multiple CPUs. - */ - private static class MultiWorkloadLogic implements WorkloadStageLogic { - private final FlowStage stage; - private final OutPort[] outputs; - private int index = 0; - - private final int coreCount; - - private Iterator<SimTraceFragment> fragments; - private SimTraceFragment currentFragment; - private long startOffFragment; - - private final SimMachineContext ctx; - - private MultiWorkloadLogic(SimMachineContext ctx, long offset, Iterator<SimTraceFragment> fragments) { - this.ctx = ctx; - this.fragments = fragments; - - final FlowGraph graph = ctx.getGraph(); - final List<? extends SimProcessingUnit> cpus = ctx.getCpus(); - - stage = graph.newStage(this); - this.coreCount = cpus.size(); - - final OutPort[] outputs = new OutPort[cpus.size()]; - this.outputs = outputs; - - for (int i = 0; i < cpus.size(); i++) { - final SimProcessingUnit cpu = cpus.get(i); - final OutPort output = stage.getOutlet("cpu" + i); - - graph.connect(output, cpu.getInput()); - outputs[i] = output; - } - - this.currentFragment = this.fragments.next(); - - int cores = Math.min(this.coreCount, currentFragment.coreCount()); - float usage = (float) currentFragment.cpuUsage() / cores; - - // Push the usage to all active cores - for (int i = 0; i < cores; i++) { - outputs[i].push(usage); - } - - // Push a usage of 0 to all non-active cores - for (int i = cores; i < outputs.length; i++) { - outputs[i].push(0.f); - } - - this.startOffFragment = offset; - } - - public long getPassedTime(long now) { - return now - this.startOffFragment; - } - - @Override - public void updateFragments(Iterator<SimTraceFragment> newFragments, long offset) { - this.fragments = newFragments; - - // Start the first Fragment - this.currentFragment = this.fragments.next(); - int cores = Math.min(this.coreCount, currentFragment.coreCount()); - float usage = (float) currentFragment.cpuUsage() / cores; - - // Push the usage to all active cores - for (int i = 0; i < cores; i++) { - outputs[i].push(usage); - } - - // Push a usage of 0 to all non-active cores - for (int i = cores; i < outputs.length; i++) { - outputs[i].push(0.f); - } - this.startOffFragment = offset; - } - - @Override - public long onUpdate(FlowStage ctx, long now) { - long passedTime = now - this.startOffFragment; - long duration = this.currentFragment.duration(); - - // The current Fragment has not yet been finished, continue - if (passedTime < duration) { - return now + (duration - passedTime); - } - - // Loop through fragments until the passed time is filled. - // We need a while loop to account for skipping of fragments. - while (passedTime >= duration) { - - // Stop running - if (!this.fragments.hasNext()) { - final SimMachineContext machineContext = this.ctx; - if (machineContext != null) { - machineContext.shutdown(); - } - ctx.close(); - return Long.MAX_VALUE; - } - - passedTime = passedTime - duration; - - // get next Fragment - this.index++; - currentFragment = this.fragments.next(); - duration = currentFragment.duration(); - } - - // start the new fragment - this.startOffFragment = now - passedTime; - - int cores = Math.min(this.coreCount, currentFragment.coreCount()); - float usage = (float) currentFragment.cpuUsage() / cores; - - final OutPort[] outputs = this.outputs; - - // Push the usage to all active cores - for (int i = 0; i < cores; i++) { - outputs[i].push(usage); - } - - // Push a usage of 0 to all non-active cores - for (int i = cores; i < outputs.length; i++) { - outputs[i].push(0.f); - } - - // Return the time when the current fragment will complete - return now + (duration - passedTime); - } - - @Override - public FlowStage getStage() { - return stage; - } - - @Override - public int getIndex() { - return index; - } - } } 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 da8bb5d2..be6d289c 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 @@ -35,11 +35,10 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.opendc.simulator.compute.device.SimNetworkAdapter +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.NetworkAdapter -import org.opendc.simulator.compute.model.ProcessingNode -import org.opendc.simulator.compute.model.ProcessingUnit import org.opendc.simulator.compute.model.StorageDevice import org.opendc.simulator.compute.power.CpuPowerModels import org.opendc.simulator.compute.workload.SimTrace @@ -60,12 +59,17 @@ class SimMachineTest { @BeforeEach fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = MachineModel( - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + Cpu( + 0, + 2, + 1000.0, + "Intel", + "Xeon", + "amd64", + ), + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), listOf(NetworkAdapter("Mellanox", "ConnectX-5", 25000.0)), listOf(StorageDevice("Samsung", "EVO", 1000.0, 250.0, 250.0)), ) @@ -121,11 +125,17 @@ class SimMachineTest { val engine = FlowEngine.create(dispatcher) val graph = engine.newGraph() - val cpuNode = machineModel.cpus[0].node + val cpuNode = machineModel.cpu val machineModel = MachineModel( - List(cpuNode.coreCount * 2) { ProcessingUnit(cpuNode, it % 2, 1000.0) }, - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + List(cpuNode.coreCount * 2) { + Cpu( + it, + cpuNode.coreCount, + 1000.0, + ) + }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) val machine = SimBareMetalMachine.create( @@ -179,10 +189,10 @@ class SimMachineTest { machine.runWorkload( object : SimWorkload { override fun onStart(ctx: SimMachineContext) { - val cpu = ctx.cpus[0] + val cpu = ctx.cpu - cpu.frequency = (cpu.model.frequency + 1000.0) - assertEquals(cpu.model.frequency, cpu.frequency) + cpu.frequency = (cpu.cpuModel.totalCapacity + 1000.0) + assertEquals(cpu.cpuModel.totalCapacity, cpu.frequency) cpu.frequency = -1.0 assertEquals(0.0, cpu.frequency) diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt index bef22699..6cebc46f 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt @@ -33,10 +33,9 @@ import org.junit.jupiter.api.assertDoesNotThrow import org.opendc.simulator.compute.SimBareMetalMachine import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernors import org.opendc.simulator.compute.kernel.interference.VmInterferenceModel +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.runWorkload import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceFragment @@ -53,13 +52,18 @@ internal class SimFairShareHypervisorTest { @BeforeEach fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) model = MachineModel( - // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + Cpu( + 0, + 1, + 3200.0, + "Intel", + "Xeon", + "amd64", + ), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) } @@ -167,13 +171,18 @@ internal class SimFairShareHypervisorTest { @Test fun testMultipleCPUs() = runSimulation { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) val model = MachineModel( - // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + Cpu( + 0, + 2, + 3200.0, + "Intel", + "Xeon", + "amd64", + ), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) val engine = FlowEngine.create(dispatcher) @@ -197,13 +206,18 @@ internal class SimFairShareHypervisorTest { @Test fun testInterference() = runSimulation { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) val model = MachineModel( - // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + Cpu( + 0, + 2, + 3200.0, + "Intel", + "Xeon", + "amd64", + ), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) val interferenceModel = diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt index b762acea..b4ae372c 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt @@ -33,10 +33,9 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.opendc.simulator.compute.SimBareMetalMachine +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.runWorkload import org.opendc.simulator.compute.workload.SimTrace import org.opendc.simulator.compute.workload.SimTraceFragment @@ -54,13 +53,18 @@ internal class SimSpaceSharedHypervisorTest { @BeforeEach fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) machineModel = MachineModel( - // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + Cpu( + 0, + 1, + 3200.0, + "Intel", + "Xeon", + "amd64", + ), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) } diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt index 33de7751..582635fc 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt @@ -33,10 +33,9 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.opendc.simulator.compute.SimBareMetalMachine import org.opendc.simulator.compute.SimMachineContext +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.runWorkload import org.opendc.simulator.flow2.FlowEngine import org.opendc.simulator.kotlin.runSimulation @@ -49,14 +48,18 @@ class SimChainWorkloadTest { @BeforeEach fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = MachineModel( - // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, + Cpu( + 0, + 2, + 1000.0, + "Intel", + "Xeon", + "amd64", + ), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) } diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt index e40d4f8b..a53f6c65 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt @@ -27,10 +27,9 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.opendc.simulator.compute.SimBareMetalMachine +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.runWorkload import org.opendc.simulator.flow2.FlowEngine import org.opendc.simulator.kotlin.runSimulation @@ -43,14 +42,18 @@ class SimTraceWorkloadTest { @BeforeEach fun setUp() { - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = MachineModel( - // cpus - List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) }, + Cpu( + 0, + 2, + 1000.0, + "Intel", + "Xeon", + "amd64", + ), // memory - List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4), ) } diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt index 18af0d1a..af9d5529 100644 --- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt +++ b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt @@ -37,10 +37,9 @@ import org.opendc.compute.workload.sampleByLoad import org.opendc.compute.workload.trace import org.opendc.experiments.base.runner.replay import org.opendc.simulator.compute.SimPsuFactories +import org.opendc.simulator.compute.model.Cpu import org.opendc.simulator.compute.model.MachineModel 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.CpuPowerModels import org.opendc.simulator.kotlin.runSimulation import org.opendc.web.proto.runner.Job @@ -325,15 +324,10 @@ public class OpenDCRunner( val position = machine.position val processors = - machine.cpus.flatMap { cpu -> - val cores = cpu.numberOfCores - val speed = cpu.clockRateMhz - // TODO: Remove hard coding of vendor - val node = ProcessingNode("Intel", "amd64", cpu.name, cores) - List(cores) { coreId -> - ProcessingUnit(node, coreId, speed) - } + machine.cpus.map { cpu -> + Cpu(0, cpu.numberOfCores, cpu.clockRateMhz, "Intel", "amd64", cpu.name) } + val memoryUnits = machine.memory.map { memory -> MemoryUnit( @@ -352,7 +346,7 @@ public class OpenDCRunner( UUID(random.nextLong(), random.nextLong()), "node-$clusterId-$position", mapOf("cluster" to clusterId), - MachineModel(processors, memoryUnits), + MachineModel(processors, memoryUnits[0]), SimPsuFactories.simple(powerModel), ) diff --git a/site/docs/advanced-guides/toolchain.md b/site/docs/advanced-guides/toolchain.md index a1735767..1673d974 100644 --- a/site/docs/advanced-guides/toolchain.md +++ b/site/docs/advanced-guides/toolchain.md @@ -41,7 +41,7 @@ Open the project once it's ready fetching the codebase, and let it set up with t that this is a Gradle codebase). You will now be prompted in a dialogue to enable auto-import for Gradle, which we suggest you do. Wait for any progress -bars in the lower bar to disappear and then look for the Gradle context menu on the right-hand side. In it, go +bars in the lower bar to disappear and then look for the Gradle simHyperVisorContext menu on the right-hand side. In it, go to `opendc > Tasks > verification > test`. This will build the codebase and run checks to verify that tests pass. If you get a `BUILD SUCCESSFUL` message, you're ready to go to the [next section](architecture)! diff --git a/site/docs/getting-started/0-installation.md b/site/docs/getting-started/0-installation.md index e0e944cc..e9f539a8 100644 --- a/site/docs/getting-started/0-installation.md +++ b/site/docs/getting-started/0-installation.md @@ -40,7 +40,7 @@ __ ____ __ _____ ___ __ ____ ______ 2022-09-12 10:30:22,282 INFO [org.ope.web.run.run.OpenDCRunnerRecorder] (main) Starting OpenDC Runner in background (polling every PT30S) 2022-09-12 10:30:22,347 INFO [io.quarkus] (main) opendc-web-server 2.1-rc1 on JVM (powered by Quarkus 2.11.1.Final) started in 1.366s. Listening on: http://0.0.0.0:8080 2022-09-12 10:30:22,348 INFO [io.quarkus] (main) Profile prod activated. -2022-09-12 10:30:22,348 INFO [io.quarkus] (main) Installed features: [agroal, cdi, flyway, hibernate-orm, hibernate-validator, jdbc-h2, jdbc-postgresql, kotlin, narayana-jta, opendc-runner, opendc-ui, resteasy, resteasy-jackson, security, smallrye-context-propagation, smallrye-openapi, swagger-ui, vertx] +2022-09-12 10:30:22,348 INFO [io.quarkus] (main) Installed features: [agroal, cdi, flyway, hibernate-orm, hibernate-validator, jdbc-h2, jdbc-postgresql, kotlin, narayana-jta, opendc-runner, opendc-ui, resteasy, resteasy-jackson, security, smallrye-simHyperVisorContext-propagation, smallrye-openapi, swagger-ui, vertx] ``` This will launch the built-in single-user OpenDC server on port 8080. Visit [http://localhost:8080](http://localhost:8080) to access the bundled web UI. diff --git a/site/docs/getting-started/1-design.mdx b/site/docs/getting-started/1-design.mdx index 144fbf98..e8ab2c58 100644 --- a/site/docs/getting-started/1-design.mdx +++ b/site/docs/getting-started/1-design.mdx @@ -83,7 +83,7 @@ build rooms. Let’s take a moment to familiarize ourselves with the interface. If you dismiss the sidebar on your left, you have controls for zooming in and out. Next to the zooming buttons, you also have a ‘Screenshot’ button, in case you want to record the state of the canvas and export it to an image file. On the -right side of the screen, you have the context menu. This menu changes depending on your zoom level. +right side of the screen, you have the simHyperVisorContext menu. This menu changes depending on your zoom level. As there are currently no rooms, we are in ‘Building’ mode, and our only option is to ‘Construct a new room’. Click on that button to build a first datacenter room - once you’ve clicked on it, every tile of the canvas that you click on @@ -106,7 +106,7 @@ Create at least a single room, with help of the above instructions. Once you’ve placed the tiles, you can give the room a name, if you want to. To do this, click on the room you want to edit. You’ll notice the application going into ‘Room’ mode, allowing you to manipulate the topology of the datacenter at -a more fine-grained level. In the context menu, change the room name, and click on the ‘Save’ button. You can exit +a more fine-grained level. In the simHyperVisorContext menu, change the room name, and click on the ‘Save’ button. You can exit ‘Room’ mode by clicking on any of the darkened areas outside of the selected room. This will bring you back to ‘Building’ mode. @@ -131,7 +131,7 @@ Add a couple of servers to the rack. ::: To add actual servers to the empty racks, we’ll need to go one level deeper in the topological hierarchy of the -datacenter. Clicking on a rack lets you do just that. Once you’ve clicked on it, you’ll notice the context menu now +datacenter. Clicking on a rack lets you do just that. Once you’ve clicked on it, you’ll notice the simHyperVisorContext menu now displaying slots. In each slot fits exactly one server unit. To add such a server unit, click on the ‘Add machine’ button of that slot. Just like in ‘Room’ mode, you can exit ‘Rack’ mode by clicking on any of the darkened tiles around the currently @@ -148,7 +148,7 @@ Populate the machines with CPU and memory resources. ::: -To do this, click on any machine you want to edit. Notice the context menu changing, with tabs to add different kinds of +To do this, click on any machine you want to edit. Notice the simHyperVisorContext menu changing, with tabs to add different kinds of units to your machine. Have a look around as to what can be added. Once you are satisfied with the datacenter design, we will experiment with the design in the next chapter. diff --git a/site/docs/getting-started/2-experiment.mdx b/site/docs/getting-started/2-experiment.mdx index e25dffc9..14970ea6 100644 --- a/site/docs/getting-started/2-experiment.mdx +++ b/site/docs/getting-started/2-experiment.mdx @@ -31,7 +31,7 @@ The baseline for comparison in a portfolio is the **base scenario**. It represen or, when planning infrastructure from scratch, it consists of very simple base workloads and topologies. The other scenarios in a portfolio, called the **candidate scenarios**, represent changes to the configuration that might be of interest to the datacenter designer. Dividing scenarios into these two categories ensures that any -comparative insights provided by OpenDC are meaningful within the context of the current architecture. +comparative insights provided by OpenDC are meaningful within the simHyperVisorContext of the current architecture. To create a new scenario, open a portfolio in the OpenDC web interface and click on ‘+ New Scenario’ in the top right corner of the scenario table. This opens a modal with the following options (as shown in [Figure 1](#explore)): |
