Skip to content

Commit

Permalink
Scenario and Portfolio update (#209)
Browse files Browse the repository at this point in the history
* Initial commit

* Implemented a new systems of defining and running scenarios / portfolios. Scenarios and Portfolios can now be defined using JSON files similar to topologies. This allows user to define experiments without changing any KotLin code.

* Ran spotlessApply
  • Loading branch information
DanteNiewenhuis authored Mar 19, 2024
1 parent 960b3d8 commit dff30fa
Show file tree
Hide file tree
Showing 84 changed files with 3,533 additions and 2,090 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,65 +34,85 @@ import org.opendc.compute.service.scheduler.weights.VCpuWeigher
import java.util.SplittableRandom
import java.util.random.RandomGenerator

public enum class ComputeSchedulerEnum {
Mem,
MemInv,
CoreMem,
CoreMemInv,
ActiveServers,
ActiveServersInv,
ProvisionedCores,
ProvisionedCoresInv,
Random,
Replay,
}

public fun createComputeScheduler(
name: String,
seeder: RandomGenerator,
placements: Map<String, String> = emptyMap(),
): ComputeScheduler {
return createComputeScheduler(ComputeSchedulerEnum.valueOf(name.uppercase()), seeder, placements)
}

/**
* Create a [ComputeScheduler] for the experiment.
*/
public fun createComputeScheduler(
name: String,
name: ComputeSchedulerEnum,
seeder: RandomGenerator,
placements: Map<String, String> = emptyMap(),
): ComputeScheduler {
val cpuAllocationRatio = 1.0
val ramAllocationRatio = 1.5
return when (name) {
"mem" ->
ComputeSchedulerEnum.Mem ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(RamWeigher(multiplier = 1.0)),
)
"mem-inv" ->
ComputeSchedulerEnum.MemInv ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(RamWeigher(multiplier = -1.0)),
)
"core-mem" ->
ComputeSchedulerEnum.CoreMem ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(CoreRamWeigher(multiplier = 1.0)),
)
"core-mem-inv" ->
ComputeSchedulerEnum.CoreMemInv ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(CoreRamWeigher(multiplier = -1.0)),
)
"active-servers" ->
ComputeSchedulerEnum.ActiveServers ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(InstanceCountWeigher(multiplier = -1.0)),
)
"active-servers-inv" ->
ComputeSchedulerEnum.ActiveServersInv ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(InstanceCountWeigher(multiplier = 1.0)),
)
"provisioned-cores" ->
ComputeSchedulerEnum.ProvisionedCores ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(VCpuWeigher(cpuAllocationRatio, multiplier = 1.0)),
)
"provisioned-cores-inv" ->
ComputeSchedulerEnum.ProvisionedCoresInv ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = listOf(VCpuWeigher(cpuAllocationRatio, multiplier = -1.0)),
)
"random" ->
ComputeSchedulerEnum.Random ->
FilterScheduler(
filters = listOf(ComputeFilter(), VCpuFilter(cpuAllocationRatio), RamFilter(ramAllocationRatio)),
weighers = emptyList(),
subsetSize = Int.MAX_VALUE,
random = SplittableRandom(seeder.nextLong()),
)
"replay" -> ReplayScheduler(placements)
else -> throw IllegalArgumentException("Unknown policy $name")
ComputeSchedulerEnum.Replay -> ReplayScheduler(placements)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 AtLarge Research
* Copyright (c) 2024 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
Expand All @@ -20,14 +20,22 @@
* SOFTWARE.
*/

package org.opendc.experiments.base.portfolio.model
package org.opendc.compute.simulator.failure

import org.opendc.compute.workload.ComputeWorkload
import org.opendc.compute.simulator.failure.models.Grid5000
import java.time.Duration
import kotlin.math.roundToLong

/**
* A single workload originating from a trace.
* Get failure model
*
* @param name the name of the workload.
* @param source The source of the workload data.
* @param failureInterval The interval of failures occurring in s
* @return
*/
public data class Workload(val name: String, val source: ComputeWorkload)
public fun getFailureModel(failureInterval: Double): FailureModel? {
return if (failureInterval > 0) {
Grid5000(Duration.ofSeconds(failureInterval.roundToLong()))
} else {
null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,47 +22,49 @@

@file:JvmName("FailureModels")

package org.opendc.compute.simulator.failure
package org.opendc.compute.simulator.failure.models

import org.apache.commons.math3.distribution.LogNormalDistribution
import org.apache.commons.math3.random.Well19937c
import org.opendc.compute.service.ComputeService
import org.opendc.compute.simulator.SimHost
import org.opendc.compute.simulator.failure.FailureModel
import org.opendc.compute.simulator.failure.HostFaultInjector
import org.opendc.compute.simulator.failure.StartStopHostFault
import org.opendc.compute.simulator.failure.StochasticVictimSelector
import java.time.Duration
import java.time.InstantSource
import java.util.random.RandomGenerator
import kotlin.coroutines.CoroutineContext
import kotlin.math.ln

/**
* Obtain a [FailureModel] based on the GRID'5000 failure trace.
* A [FailureModel] based on the GRID'5000 failure trace.
*
* This fault injector uses parameters from the GRID'5000 failure trace as described in
* "A Framework for the Study of Grid Inter-Operation Mechanisms", A. Iosup, 2009.
*/
public fun grid5000(failureInterval: Duration): FailureModel {
return object : FailureModel {
override fun createInjector(
context: CoroutineContext,
clock: InstantSource,
service: ComputeService,
random: RandomGenerator,
): HostFaultInjector {
val rng = Well19937c(random.nextLong())
val hosts = service.hosts.map { it as SimHost }.toSet()
public class Grid5000(private val failureInterval: Duration) : FailureModel {
override fun createInjector(
context: CoroutineContext,
clock: InstantSource,
service: ComputeService,
random: RandomGenerator,
): HostFaultInjector {
val rng = Well19937c(random.nextLong())
val hosts = service.hosts.map { it as SimHost }.toSet()

// Parameters from A. Iosup, A Framework for the Study of Grid Inter-Operation Mechanisms, 2009
// GRID'5000
return HostFaultInjector(
context,
clock,
hosts,
iat = LogNormalDistribution(rng, ln(failureInterval.toHours().toDouble()), 1.03),
selector = StochasticVictimSelector(LogNormalDistribution(rng, 1.88, 1.25), random),
fault = StartStopHostFault(LogNormalDistribution(rng, 8.89, 2.71)),
)
}

override fun toString(): String = "Grid5000FailureModel"
// Parameters from A. Iosup, A Framework for the Study of Grid Inter-Operation Mechanisms, 2009
// GRID'5000
return HostFaultInjector(
context,
clock,
hosts,
iat = LogNormalDistribution(rng, ln(failureInterval.toHours().toDouble()), 1.03),
selector = StochasticVictimSelector(LogNormalDistribution(rng, 1.88, 1.25), random),
fault = StartStopHostFault(LogNormalDistribution(rng, 8.89, 2.71)),
)
}

override fun toString(): String = "Grid5000FailureModel"
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public class ComputeWorkloadLoader(private val baseDir: File) {
val memCapacity = reader.getDouble(memCol) / 1000.0 // Convert from KB to MB
val uid = UUID.nameUUIDFromBytes("$id-${counter++}".toByteArray())

val builder = fragments.getValue(id)
val builder = fragments.getValue(id) // Get all fragments related to this VM
val totalLoad = builder.totalLoad

entries.add(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal class LoadSampledComputeWorkload(val source: ComputeWorkload, val fract
loader: ComputeWorkloadLoader,
random: RandomGenerator,
): List<VirtualMachine> {
val vms = source.resolve(loader, random)
val vms = source.resolve(loader, random) // fixme: Should be shuffled, otherwise the first fraction is always chosen
val res = mutableListOf<VirtualMachine>()

val totalLoad = vms.sumOf { it.totalLoad }
Expand Down
12 changes: 12 additions & 0 deletions opendc-experiments/opendc-experiments-base/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,22 @@ plugins {
`kotlin-library-conventions`
`testing-conventions`
`jacoco-conventions`
kotlin("plugin.serialization") version "1.9.22"
}

dependencies {

api(projects.opendcCompute.opendcComputeService)
api(projects.opendcCompute.opendcComputeSimulator)

implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation(libs.progressbar)
implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-workload")))
implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-telemetry")))
implementation(project(mapOf("path" to ":opendc-simulator:opendc-simulator-core")))
implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-topology")))

runtimeOnly(projects.opendcTrace.opendcTraceOpendc)
runtimeOnly(libs.log4j.core)
runtimeOnly(libs.log4j.slf4j)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@
* SOFTWARE.
*/

package org.opendc.experiments.base.portfolio
package org.opendc.experiments.base.models.portfolio

import org.opendc.experiments.base.portfolio.model.Scenario
import org.opendc.experiments.base.models.scenario.Scenario

/**
* A portfolio represents a collection of scenarios are tested for the work.
*/
public interface Portfolio {
/**
* The scenarios that belong to this portfolio.
*/
public val scenarios: Iterable<Scenario>
}
public class Portfolio(
public val scenarios: Iterable<Scenario>,
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 AtLarge Research
* Copyright (c) 2024 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
Expand All @@ -20,21 +20,26 @@
* SOFTWARE.
*/

package org.opendc.experiments.base.portfolio.model
package org.opendc.experiments.base.models.portfolio

/**
* A single scenario of a portfolio.
*
* @property topology The topology to test.
* @property workload The workload to test.
* @property operationalPhenomena The [OperationalPhenomena] to model.
* @property allocationPolicy The allocation policy of the scheduler.
* @property partitions The partition of the scenario.
*/
public data class Scenario(
val topology: Topology,
val workload: Workload,
val operationalPhenomena: OperationalPhenomena,
val allocationPolicy: String,
val partitions: Map<String, String> = emptyMap(),
)
import org.opendc.experiments.base.models.scenario.getScenario
import java.io.File

private val porfolioReader = PortfolioReader()

public fun getPortfolio(filePath: String): Portfolio {
return getPortfolio(File(filePath))
}

public fun getPortfolio(file: File): Portfolio {
return getPortfolio(porfolioReader.read(file))
}

public fun getPortfolio(portfolioSpec: PortfolioSpec): Portfolio {
return Portfolio(
portfolioSpec.scenarios.map {
scenario ->
getScenario(scenario)
},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 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.experiments.base.models.portfolio

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import java.io.File
import java.io.InputStream

public class PortfolioReader {
@OptIn(ExperimentalSerializationApi::class)
public fun read(file: File): PortfolioSpec {
val input = file.inputStream()
val obj = Json.decodeFromStream<PortfolioSpec>(input)

return obj
}

/**
* Read the specified [input].
*/
@OptIn(ExperimentalSerializationApi::class)
public fun read(input: InputStream): PortfolioSpec {
val obj = Json.decodeFromStream<PortfolioSpec>(input)
return obj
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 AtLarge Research
* Copyright (c) 2024 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
Expand All @@ -20,9 +20,12 @@
* SOFTWARE.
*/

package org.opendc.experiments.base.portfolio.model
package org.opendc.experiments.base.models.portfolio

/**
* The topology on which we simulate the workload.
*/
public data class Topology(val name: String)
import kotlinx.serialization.Serializable
import org.opendc.experiments.base.models.scenario.ScenarioSpec

@Serializable
public data class PortfolioSpec(
val scenarios: List<ScenarioSpec>,
)
Loading

0 comments on commit dff30fa

Please sign in to comment.