Skip to content

Commit

Permalink
All simulation are now run with a single CPU and single MemoryUnit. m…
Browse files Browse the repository at this point in the history
…ulti CPUs are combined into one. This is for performance and explainability. (#255)
  • Loading branch information
DanteNiewenhuis authored Sep 16, 2024
1 parent 5047e4a commit 4a010c6
Show file tree
Hide file tree
Showing 49 changed files with 596 additions and 760 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* 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) {}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) }
Expand Down Expand Up @@ -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) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
)

/**
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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].
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 4a010c6

Please sign in to comment.