diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-05-06 12:54:45 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-05-06 22:13:43 +0200 |
| commit | d431cea8b220cc50c623e37be9595025125438f5 (patch) | |
| tree | 421f6cd873489ea2d8c1b887a2e3cf1592937f1e /opendc-experiments | |
| parent | 183c29d907bc231c93ff5fe525040c931776b567 (diff) | |
refactor(exp/capelin): Add independent Capelin distribution
This change updates the Capelin experiments so it can be distributed and
executed independently of the main OpenDC distribution. We provide a new
command line interface for users to directly run the experiments.
Alternatively, the `CapelinRunner` class encapsulates the logic for
running the experiments and can be used programmatically.
Diffstat (limited to 'opendc-experiments')
16 files changed, 490 insertions, 305 deletions
diff --git a/opendc-experiments/opendc-experiments-capelin/LICENSE.txt b/opendc-experiments/opendc-experiments-capelin/LICENSE.txt new file mode 100644 index 00000000..3931600a --- /dev/null +++ b/opendc-experiments/opendc-experiments-capelin/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Georgios Andreadis, Fabian Mastenbroek + +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. diff --git a/opendc-experiments/opendc-experiments-capelin/README.md b/opendc-experiments/opendc-experiments-capelin/README.md new file mode 100644 index 00000000..d86fe81d --- /dev/null +++ b/opendc-experiments/opendc-experiments-capelin/README.md @@ -0,0 +1,9 @@ +# Capelin +Data-Driven Compute Capacity Procurement for Cloud Datacenters Using Portfolios of Scenarios. + +See the [publication](https://arxiv.org/abs/2103.02060) and +[thesis](https://repository.tudelft.nl/islandora/object/uuid:d6d50861-86a3-4dd3-a13f-42d84db7af66?collection=education) for information. + +## License + +OpenDC and Capelin are distributed under the MIT license. See [LICENSE-OpenDC.txt](/LICENSE.txt) and [LICENSE.txt](LICENSE.txt). diff --git a/opendc-experiments/opendc-experiments-capelin/build.gradle.kts b/opendc-experiments/opendc-experiments-capelin/build.gradle.kts index 39cf101d..8320179a 100644 --- a/opendc-experiments/opendc-experiments-capelin/build.gradle.kts +++ b/opendc-experiments/opendc-experiments-capelin/build.gradle.kts @@ -24,28 +24,62 @@ description = "Experiments for the Capelin work" /* Build configuration */ plugins { - `experiment-conventions` + `kotlin-conventions` `testing-conventions` `jacoco-conventions` `benchmark-conventions` + distribution } dependencies { - api(projects.opendcHarness.opendcHarnessApi) api(projects.opendcCompute.opendcComputeWorkload) implementation(projects.opendcSimulator.opendcSimulatorCore) implementation(projects.opendcSimulator.opendcSimulatorCompute) implementation(projects.opendcCompute.opendcComputeSimulator) - implementation(libs.config) + implementation(libs.clikt) + implementation(libs.progressbar) implementation(libs.kotlin.logging) - implementation(libs.jackson.databind) - implementation(libs.jackson.module.kotlin) implementation(libs.jackson.dataformat.csv) - implementation(kotlin("reflect")) runtimeOnly(projects.opendcTrace.opendcTraceOpendc) + runtimeOnly(libs.log4j.slf4j) +} + +val createCapelinApp by tasks.creating(CreateStartScripts::class) { + dependsOn(tasks.jar) + + applicationName = "capelin" + mainClass.set("org.opendc.experiments.capelin.CapelinCli") + classpath = tasks.jar.get().outputs.files + configurations["runtimeClasspath"] + outputDir = project.buildDir.resolve("scripts") +} + +/* Create custom Capelin distribution */ +distributions { + main { + distributionBaseName.set("capelin") + + contents { + from("README.md") + from("LICENSE.txt") + from("../../LICENSE.txt") { + rename { "LICENSE-OpenDC.txt" } + } + + into("bin") { + from(createCapelinApp) + } + + into("lib") { + from(tasks.jar) + from(configurations["runtimeClasspath"]) + } - testImplementation(libs.log4j.slf4j) + into("input") { + from("input") + } + } + } } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinCli.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinCli.kt new file mode 100644 index 00000000..875ae0dc --- /dev/null +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinCli.kt @@ -0,0 +1,152 @@ +/* + * 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. + */ + +@file:JvmName("CapelinCli") +package org.opendc.experiments.capelin + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.options.* +import com.github.ajalt.clikt.parameters.types.choice +import com.github.ajalt.clikt.parameters.types.file +import com.github.ajalt.clikt.parameters.types.int +import com.github.ajalt.clikt.parameters.types.long +import me.tongfei.progressbar.ProgressBarBuilder +import me.tongfei.progressbar.ProgressBarStyle +import org.opendc.experiments.capelin.model.Scenario +import org.opendc.experiments.capelin.portfolio.* +import java.io.File +import java.util.concurrent.ForkJoinPool +import java.util.stream.LongStream + +/** + * Main entrypoint of the application. + */ +fun main(args: Array<String>): Unit = CapelinCommand().main(args) + +/** + * Represents the command for the Capelin experiments. + */ +internal class CapelinCommand : CliktCommand(name = "capelin") { + /** + * The path to the environment directory. + */ + private val envPath by option("--env-path", help = "path to environment directory") + .file(canBeDir = true, canBeFile = false) + .defaultLazy { File("input/environments") } + + /** + * The path to the trace directory. + */ + private val tracePath by option("--trace-path", help = "path to trace directory") + .file(canBeDir = true, canBeFile = false) + .defaultLazy { File("input/traces") } + + /** + * The path to the experiment output. + */ + private val outputPath by option("-O", "--output", help = "path to experiment output") + .file(canBeDir = true, canBeFile = false) + .defaultLazy { File("output") } + + /** + * Disable writing output. + */ + private val disableOutput by option("--disable-output", help = "disable output").flag() + + /** + * The number of threads to use for parallelism. + */ + private val parallelism by option("-p", "--parallelism", help = "number of worker threads") + .int() + .default(Runtime.getRuntime().availableProcessors() - 1) + + /** + * The number of repeats. + */ + private val repeats by option("-r", "--repeats", help = "number of repeats") + .int() + .default(128) + + /** + * The seed for seeding the random instances. + */ + private val seed by option("-s", "--seed", help = "initial seed for randomness") + .long() + .default(0) + + /** + * The portfolio to replay. + */ + private val portfolio by argument(help = "portfolio to replay") + .choice( + "test" to { TestPortfolio() }, + "composite-workload" to { CompositeWorkloadPortfolio() }, + "hor-ver" to { HorVerPortfolio() }, + "more-hpc" to { MoreHpcPortfolio() }, + "more-velocity" to { MoreVelocityPortfolio() }, + "op-phen" to { OperationalPhenomenaPortfolio() }, + ) + + /** + * The base partitions to use for the invocation + */ + private val basePartitions: Map<String, String> by option("-P", "--base-partitions").associate() + + override fun run() { + val runner = CapelinRunner(envPath, tracePath, outputPath.takeUnless { disableOutput }) + val scenarios = portfolio().scenarios.toList() + + val pool = ForkJoinPool(parallelism) + + echo("Detected ${scenarios.size} scenarios [$repeats replications]") + + for (scenario in scenarios) { + runScenario(runner, pool, scenario) + } + + pool.shutdown() + } + + /** + * Run a single scenario. + */ + private fun runScenario(runner: CapelinRunner, pool: ForkJoinPool, scenario: Scenario) { + val pb = ProgressBarBuilder() + .setInitialMax(repeats.toLong()) + .setStyle(ProgressBarStyle.ASCII) + .setTaskName("Simulating...") + .build() + + pool.submit { + LongStream.range(0, repeats.toLong()) + .parallel() + .forEach { repeat -> + val augmentedScenario = scenario.copy(partitions = basePartitions + scenario.partitions) + runner.runScenario(augmentedScenario, seed + repeat) + pb.step() + } + + pb.close() + }.join() + } +} diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinRunner.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinRunner.kt new file mode 100644 index 00000000..cca5b6cf --- /dev/null +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CapelinRunner.kt @@ -0,0 +1,115 @@ +/* + * 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.experiments.capelin + +import org.opendc.compute.api.Server +import org.opendc.compute.workload.ComputeServiceHelper +import org.opendc.compute.workload.ComputeWorkloadLoader +import org.opendc.compute.workload.createComputeScheduler +import org.opendc.compute.workload.export.parquet.ParquetComputeMonitor +import org.opendc.compute.workload.grid5000 +import org.opendc.compute.workload.telemetry.ComputeMetricReader +import org.opendc.compute.workload.topology.apply +import org.opendc.experiments.capelin.model.Scenario +import org.opendc.experiments.capelin.topology.clusterTopology +import org.opendc.simulator.core.runBlockingSimulation +import java.io.File +import java.time.Duration +import java.util.* +import kotlin.math.roundToLong + +/** + * Helper class for running the Capelin experiments. + * + * @param envPath The path to the directory containing the environments. + * @param tracePath The path to the directory containing the traces. + * @param outputPath The path to the directory where the output should be written (or `null` if no output should be generated). + */ +public class CapelinRunner( + private val envPath: File, + tracePath: File, + private val outputPath: File? +) { + /** + * The [ComputeWorkloadLoader] to use for loading the traces. + */ + private val workloadLoader = ComputeWorkloadLoader(tracePath) + + /** + * Run a single [scenario] with the specified seed. + */ + fun runScenario(scenario: Scenario, seed: Long) = runBlockingSimulation { + val seeder = Random(seed) + + val operationalPhenomena = scenario.operationalPhenomena + val computeScheduler = createComputeScheduler(scenario.allocationPolicy, seeder) + val failureModel = + if (operationalPhenomena.failureFrequency > 0) + grid5000(Duration.ofSeconds((operationalPhenomena.failureFrequency * 60).roundToLong())) + else + null + val (vms, interferenceModel) = scenario.workload.source.resolve(workloadLoader, seeder) + val runner = ComputeServiceHelper( + coroutineContext, + clock, + computeScheduler, + failureModel, + interferenceModel?.withSeed(seed) + ) + + val topology = clusterTopology(File(envPath, "${scenario.topology.name}.txt")) + + val servers = mutableListOf<Server>() + val partitions = scenario.partitions + ("seed" to seed.toString()) + val partition = partitions.map { (k, v) -> "$k=$v" }.joinToString("/") + val exporter = if (outputPath != null) { + ComputeMetricReader( + this, + clock, + runner.service, + servers, + ParquetComputeMonitor( + outputPath, + partition, + bufferSize = 4096 + ), + exportInterval = Duration.ofMinutes(5) + ) + } else { + null + } + + try { + // Instantiate the desired topology + runner.apply(topology, optimize = true) + + // Run the workload trace + runner.run(vms, seeder.nextLong(), servers) + + // Stop the metric collection + exporter?.close() + } finally { + runner.close() + } + } +} diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/Portfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/Portfolio.kt deleted file mode 100644 index 0de8aa7b..00000000 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/Portfolio.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.experiments.capelin - -import com.typesafe.config.ConfigFactory -import kotlinx.coroutines.* -import org.opendc.compute.api.Server -import org.opendc.compute.workload.ComputeServiceHelper -import org.opendc.compute.workload.ComputeWorkloadLoader -import org.opendc.compute.workload.createComputeScheduler -import org.opendc.compute.workload.export.parquet.ParquetComputeMonitor -import org.opendc.compute.workload.grid5000 -import org.opendc.compute.workload.telemetry.ComputeMetricReader -import org.opendc.compute.workload.topology.apply -import org.opendc.experiments.capelin.model.OperationalPhenomena -import org.opendc.experiments.capelin.model.Topology -import org.opendc.experiments.capelin.model.Workload -import org.opendc.experiments.capelin.topology.clusterTopology -import org.opendc.harness.dsl.Experiment -import org.opendc.harness.dsl.anyOf -import org.opendc.simulator.core.runBlockingSimulation -import java.io.File -import java.time.Duration -import java.util.* -import kotlin.math.roundToLong - -/** - * A portfolio represents a collection of scenarios are tested for the work. - * - * @param name The name of the portfolio. - */ -abstract class Portfolio(name: String) : Experiment(name) { - /** - * The configuration to use. - */ - private val config = ConfigFactory.load().getConfig("opendc.experiments.capelin") - - /** - * The path to the original VM placements file. - */ - private val vmPlacements by anyOf(emptyMap<String, String>()) - - /** - * The topology to test. - */ - abstract val topology: Topology - - /** - * The workload to test. - */ - abstract val workload: Workload - - /** - * The operational phenomenas to consider. - */ - abstract val operationalPhenomena: OperationalPhenomena - - /** - * The allocation policies to consider. - */ - abstract val allocationPolicy: String - - /** - * A helper class to load workload traces. - */ - private val workloadLoader = ComputeWorkloadLoader(File(config.getString("trace-path"))) - - /** - * Perform a single trial for this portfolio. - */ - override fun doRun(repeat: Int): Unit = runBlockingSimulation { - val seeder = Random(repeat.toLong()) - - val computeScheduler = createComputeScheduler(allocationPolicy, seeder, vmPlacements) - val failureModel = - if (operationalPhenomena.failureFrequency > 0) - grid5000(Duration.ofSeconds((operationalPhenomena.failureFrequency * 60).roundToLong())) - else - null - val (vms, interferenceModel) = workload.source.resolve(workloadLoader, seeder) - val runner = ComputeServiceHelper( - coroutineContext, - clock, - computeScheduler, - failureModel, - interferenceModel?.withSeed(repeat.toLong()) - ) - - val topology = clusterTopology(File(config.getString("env-path"), "${topology.name}.txt")) - val servers = mutableListOf<Server>() - val exporter = ComputeMetricReader( - this, - clock, - runner.service, - servers, - ParquetComputeMonitor( - File(config.getString("output-path")), - "portfolio_id=$name/scenario_id=$id/run_id=$repeat", - bufferSize = 4096 - ), - exportInterval = Duration.ofMinutes(5) - ) - - try { - // Instantiate the desired topology - runner.apply(topology) - - coroutineScope { - // Run the workload trace - runner.run(vms, seeder.nextLong(), servers) - - // Stop the metric collection - exporter.close() - } - } finally { - runner.close() - exporter.close() - } - } -} diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/ReplayPortfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/model/Scenario.kt index 17ec48d4..2218a46b 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/ReplayPortfolio.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/model/Scenario.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * 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 @@ -20,32 +20,21 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin - -import org.opendc.compute.workload.trace -import org.opendc.experiments.capelin.model.OperationalPhenomena -import org.opendc.experiments.capelin.model.Topology -import org.opendc.experiments.capelin.model.Workload -import org.opendc.harness.dsl.anyOf +package org.opendc.experiments.capelin.model /** - * A [Portfolio] that compares the original VM placements against our policies. + * 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 class ReplayPortfolio : Portfolio("replay") { - override val topology: Topology by anyOf( - Topology("base") - ) - - override val workload: Workload by anyOf( - Workload("solvinity", trace("solvinity")) - ) - - override val operationalPhenomena: OperationalPhenomena by anyOf( - OperationalPhenomena(failureFrequency = 0.0, hasInterference = false) - ) - - override val allocationPolicy: String by anyOf( - "replay", - "active-servers" - ) -} +public data class Scenario( + val topology: Topology, + val workload: Workload, + val operationalPhenomena: OperationalPhenomena, + val allocationPolicy: String, + val partitions: Map<String, String> = emptyMap() +) diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CompositeWorkloadPortfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/CompositeWorkloadPortfolio.kt index 31e8f961..68eb15b3 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/CompositeWorkloadPortfolio.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/CompositeWorkloadPortfolio.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * 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 @@ -20,29 +20,26 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin +package org.opendc.experiments.capelin.portfolio import org.opendc.compute.workload.composite import org.opendc.compute.workload.trace import org.opendc.experiments.capelin.model.OperationalPhenomena +import org.opendc.experiments.capelin.model.Scenario import org.opendc.experiments.capelin.model.Topology import org.opendc.experiments.capelin.model.Workload -import org.opendc.harness.dsl.anyOf /** * A [Portfolio] that explores the effect of a composite workload. */ -public class CompositeWorkloadPortfolio : Portfolio("composite-workload") { - private val totalSampleLoad = 1.3301733005049648E12 - - override val topology: Topology by anyOf( +public class CompositeWorkloadPortfolio : Portfolio { + private val topologies = listOf( Topology("base"), Topology("exp-vol-hor-hom"), Topology("exp-vol-ver-hom"), Topology("exp-vel-ver-hom") ) - - override val workload: Workload by anyOf( + private val workloads = listOf( Workload( "all-azure", composite(trace("solvinity-short") to 0.0, trace("azure") to 1.0) @@ -64,12 +61,18 @@ public class CompositeWorkloadPortfolio : Portfolio("composite-workload") { composite(trace("solvinity-short") to 1.0, trace("azure") to 0.0) ) ) + private val operationalPhenomena = OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = false) + private val allocationPolicy = "active-servers" - override val operationalPhenomena: OperationalPhenomena by anyOf( - OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = false) - ) - - override val allocationPolicy: String by anyOf( - "active-servers" - ) + override val scenarios: Iterable<Scenario> = topologies.flatMap { topology -> + workloads.map { workload -> + Scenario( + topology, + workload, + operationalPhenomena, + allocationPolicy, + mapOf("topology" to topology.name, "workload" to workload.name) + ) + } + } } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/HorVerPortfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/HorVerPortfolio.kt index cd093e6c..0d7f3072 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/HorVerPortfolio.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/HorVerPortfolio.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * 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 @@ -20,20 +20,20 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin +package org.opendc.experiments.capelin.portfolio import org.opendc.compute.workload.sampleByLoad import org.opendc.compute.workload.trace import org.opendc.experiments.capelin.model.OperationalPhenomena +import org.opendc.experiments.capelin.model.Scenario import org.opendc.experiments.capelin.model.Topology import org.opendc.experiments.capelin.model.Workload -import org.opendc.harness.dsl.anyOf /** * A [Portfolio] that explores the difference between horizontal and vertical scaling. */ -public class HorVerPortfolio : Portfolio("horizontal_vs_vertical") { - override val topology: Topology by anyOf( +public class HorVerPortfolio : Portfolio { + private val topologies = listOf( Topology("base"), Topology("rep-vol-hor-hom"), Topology("rep-vol-hor-het"), @@ -45,18 +45,24 @@ public class HorVerPortfolio : Portfolio("horizontal_vs_vertical") { Topology("exp-vol-ver-het") ) - override val workload: Workload by anyOf( - Workload("solvinity", trace("solvinity").sampleByLoad(0.1)), - Workload("solvinity", trace("solvinity").sampleByLoad(0.25)), - Workload("solvinity", trace("solvinity").sampleByLoad(0.5)), - Workload("solvinity", trace("solvinity").sampleByLoad(1.0)) + private val workloads = listOf( + Workload("solvinity-10%", trace("solvinity").sampleByLoad(0.1)), + Workload("solvinity-25%", trace("solvinity").sampleByLoad(0.25)), + Workload("solvinity-50%", trace("solvinity").sampleByLoad(0.5)), + Workload("solvinity-100%", trace("solvinity").sampleByLoad(1.0)) ) + private val operationalPhenomena = OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) + private val allocationPolicy = "active-servers" - override val operationalPhenomena: OperationalPhenomena by anyOf( - OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) - ) - - override val allocationPolicy: String by anyOf( - "active-servers" - ) + override val scenarios: Iterable<Scenario> = topologies.flatMap { topology -> + workloads.map { workload -> + Scenario( + topology, + workload, + operationalPhenomena, + allocationPolicy, + mapOf("topology" to topology.name, "workload" to workload.name) + ) + } + } } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/MoreHpcPortfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/MoreHpcPortfolio.kt index 73e59a58..6afffc09 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/MoreHpcPortfolio.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/MoreHpcPortfolio.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * 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 @@ -20,42 +20,48 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin +package org.opendc.experiments.capelin.portfolio import org.opendc.compute.workload.sampleByHpc import org.opendc.compute.workload.sampleByHpcLoad import org.opendc.compute.workload.trace import org.opendc.experiments.capelin.model.OperationalPhenomena +import org.opendc.experiments.capelin.model.Scenario import org.opendc.experiments.capelin.model.Topology import org.opendc.experiments.capelin.model.Workload -import org.opendc.harness.dsl.anyOf /** * A [Portfolio] to explore the effect of HPC workloads. */ -public class MoreHpcPortfolio : Portfolio("more_hpc") { - override val topology: Topology by anyOf( +public class MoreHpcPortfolio : Portfolio { + private val topologies = listOf( Topology("base"), Topology("exp-vol-hor-hom"), Topology("exp-vol-ver-hom"), Topology("exp-vel-ver-hom") ) - - override val workload: Workload by anyOf( - Workload("solvinity", trace("solvinity").sampleByHpc(0.0)), - Workload("solvinity", trace("solvinity").sampleByHpc(0.25)), - Workload("solvinity", trace("solvinity").sampleByHpc(0.5)), - Workload("solvinity", trace("solvinity").sampleByHpc(1.0)), - Workload("solvinity", trace("solvinity").sampleByHpcLoad(0.25)), - Workload("solvinity", trace("solvinity").sampleByHpcLoad(0.5)), - Workload("solvinity", trace("solvinity").sampleByHpcLoad(1.0)) + private val workloads = listOf( + Workload("hpc-0%", trace("solvinity").sampleByHpc(0.0)), + Workload("hpc-25%", trace("solvinity").sampleByHpc(0.25)), + Workload("hpc-50%", trace("solvinity").sampleByHpc(0.5)), + Workload("hpc-100%", trace("solvinity").sampleByHpc(1.0)), + Workload("hpc-load-25%", trace("solvinity").sampleByHpcLoad(0.25)), + Workload("hpc-load-50%", trace("solvinity").sampleByHpcLoad(0.5)), + Workload("hpc-load-100%", trace("solvinity").sampleByHpcLoad(1.0)) ) - override val operationalPhenomena: OperationalPhenomena by anyOf( - OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) - ) + private val operationalPhenomena = OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) + private val allocationPolicy: String = "active-servers" - override val allocationPolicy: String by anyOf( - "active-servers" - ) + override val scenarios: Iterable<Scenario> = topologies.flatMap { topology -> + workloads.map { workload -> + Scenario( + topology, + workload, + operationalPhenomena, + allocationPolicy, + mapOf("topology" to topology.name, "workload" to workload.name) + ) + } + } } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/MoreVelocityPortfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/MoreVelocityPortfolio.kt index 9d5717bb..92bf80b3 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/MoreVelocityPortfolio.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/MoreVelocityPortfolio.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * 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 @@ -20,20 +20,20 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin +package org.opendc.experiments.capelin.portfolio import org.opendc.compute.workload.sampleByLoad import org.opendc.compute.workload.trace import org.opendc.experiments.capelin.model.OperationalPhenomena +import org.opendc.experiments.capelin.model.Scenario import org.opendc.experiments.capelin.model.Topology import org.opendc.experiments.capelin.model.Workload -import org.opendc.harness.dsl.anyOf /** * A [Portfolio] that explores the effect of adding more velocity to a cluster (e.g., faster machines). */ -public class MoreVelocityPortfolio : Portfolio("more_velocity") { - override val topology: Topology by anyOf( +public class MoreVelocityPortfolio : Portfolio { + private val topologies = listOf( Topology("base"), Topology("rep-vel-ver-hom"), Topology("rep-vel-ver-het"), @@ -41,18 +41,25 @@ public class MoreVelocityPortfolio : Portfolio("more_velocity") { Topology("exp-vel-ver-het") ) - override val workload: Workload by anyOf( - Workload("solvinity", trace("solvinity").sampleByLoad(0.1)), - Workload("solvinity", trace("solvinity").sampleByLoad(0.25)), - Workload("solvinity", trace("solvinity").sampleByLoad(0.5)), - Workload("solvinity", trace("solvinity").sampleByLoad(1.0)) + private val workloads = listOf( + Workload("solvinity-10%", trace("solvinity").sampleByLoad(0.1)), + Workload("solvinity-25%", trace("solvinity").sampleByLoad(0.25)), + Workload("solvinity-50%", trace("solvinity").sampleByLoad(0.5)), + Workload("solvinity-100%", trace("solvinity").sampleByLoad(1.0)) ) - override val operationalPhenomena: OperationalPhenomena by anyOf( - OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) - ) + private val operationalPhenomena = OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) + private val allocationPolicy = "active-servers" - override val allocationPolicy: String by anyOf( - "active-servers" - ) + override val scenarios: Iterable<Scenario> = topologies.flatMap { topology -> + workloads.map { workload -> + Scenario( + topology, + workload, + operationalPhenomena, + allocationPolicy, + mapOf("topology" to topology.name, "workload" to workload.name) + ) + } + } } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/OperationalPhenomenaPortfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/OperationalPhenomenaPortfolio.kt index 7ab586b3..f9a9d681 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/OperationalPhenomenaPortfolio.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/OperationalPhenomenaPortfolio.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * 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 @@ -20,38 +20,35 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin +package org.opendc.experiments.capelin.portfolio import org.opendc.compute.workload.sampleByLoad import org.opendc.compute.workload.trace import org.opendc.experiments.capelin.model.OperationalPhenomena +import org.opendc.experiments.capelin.model.Scenario import org.opendc.experiments.capelin.model.Topology import org.opendc.experiments.capelin.model.Workload -import org.opendc.harness.dsl.anyOf /** * A [Portfolio] that explores the effect of operational phenomena on metrics. */ -public class OperationalPhenomenaPortfolio : Portfolio("operational_phenomena") { - override val topology: Topology by anyOf( - Topology("base") +public class OperationalPhenomenaPortfolio : Portfolio { + private val topology = Topology("base") + private val workloads = listOf( + Workload("solvinity-10%", trace("solvinity").sampleByLoad(0.1)), + Workload("solvinity-25%", trace("solvinity").sampleByLoad(0.25)), + Workload("solvinity-50%", trace("solvinity").sampleByLoad(0.5)), + Workload("solvinity-100%", trace("solvinity").sampleByLoad(1.0)) ) - override val workload: Workload by anyOf( - Workload("solvinity", trace("solvinity").sampleByLoad(0.1)), - Workload("solvinity", trace("solvinity").sampleByLoad(0.25)), - Workload("solvinity", trace("solvinity").sampleByLoad(0.5)), - Workload("solvinity", trace("solvinity").sampleByLoad(1.0)) - ) - - override val operationalPhenomena: OperationalPhenomena by anyOf( + private val phenomenas = listOf( OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true), OperationalPhenomena(failureFrequency = 0.0, hasInterference = true), OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = false), OperationalPhenomena(failureFrequency = 0.0, hasInterference = false) ) - override val allocationPolicy: String by anyOf( + private val allocationPolicies = listOf( "mem", "mem-inv", "core-mem", @@ -60,4 +57,19 @@ public class OperationalPhenomenaPortfolio : Portfolio("operational_phenomena") "active-servers-inv", "random" ) + + override val scenarios: Iterable<Scenario> = + workloads.flatMap { workload -> + phenomenas.flatMapIndexed { index, operationalPhenomena -> + allocationPolicies.map { allocationPolicy -> + Scenario( + topology, + workload, + operationalPhenomena, + allocationPolicy, + mapOf("workload" to workload.name, "scheduler" to allocationPolicy, "phenomena" to index.toString()) + ) + } + } + } } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/util/VmPlacementReader.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/Portfolio.kt index 67de2777..abf37a5f 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/util/VmPlacementReader.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/Portfolio.kt @@ -20,28 +20,16 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin.util +package org.opendc.experiments.capelin.portfolio -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import java.io.InputStream +import org.opendc.experiments.capelin.model.Scenario /** - * A parser for the JSON VM placement data files used for the TPDS article on Capelin. + * A portfolio represents a collection of scenarios are tested for the work. */ -class VmPlacementReader { +public interface Portfolio { /** - * The [ObjectMapper] to parse the placement. + * The scenarios that belong to this portfolio. */ - private val mapper = jacksonObjectMapper() - - /** - * Read the VM placements from the input. - */ - fun read(input: InputStream): Map<String, String> { - return mapper.readValue<Map<String, String>>(input) - .mapKeys { "vm__workload__${it.key}.txt" } - .mapValues { it.value.split("/")[1] } // Clusters have format XX0 / X00 - } + val scenarios: Iterable<Scenario> } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/TestPortfolio.kt b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/TestPortfolio.kt index 98eb989d..944e9f43 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/TestPortfolio.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/main/kotlin/org/opendc/experiments/capelin/portfolio/TestPortfolio.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 AtLarge Research + * 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 @@ -20,29 +20,24 @@ * SOFTWARE. */ -package org.opendc.experiments.capelin +package org.opendc.experiments.capelin.portfolio import org.opendc.compute.workload.trace import org.opendc.experiments.capelin.model.OperationalPhenomena +import org.opendc.experiments.capelin.model.Scenario import org.opendc.experiments.capelin.model.Topology import org.opendc.experiments.capelin.model.Workload -import org.opendc.harness.dsl.anyOf /** * A [Portfolio] to perform a simple test run. */ -public class TestPortfolio : Portfolio("test") { - override val topology: Topology by anyOf( - Topology("base") +public class TestPortfolio : Portfolio { + override val scenarios: Iterable<Scenario> = listOf( + Scenario( + Topology("base"), + Workload("solvinity", trace("solvinity")), + OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true), + "active-servers" + ) ) - - override val workload: Workload by anyOf( - Workload("solvinity", trace("solvinity")) - ) - - override val operationalPhenomena: OperationalPhenomena by anyOf( - OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) - ) - - override val allocationPolicy: String by anyOf("active-servers") } diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/resources/application.conf b/opendc-experiments/opendc-experiments-capelin/src/main/resources/application.conf deleted file mode 100644 index f0e0f2d3..00000000 --- a/opendc-experiments/opendc-experiments-capelin/src/main/resources/application.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Default configuration for the Capelin experiments -opendc.experiments.capelin { - env-path = input/environments/ - trace-path = input/traces/ - output-path = output -} diff --git a/opendc-experiments/opendc-experiments-capelin/src/main/resources/log4j2.xml b/opendc-experiments/opendc-experiments-capelin/src/main/resources/log4j2.xml index d46b50c3..e479f2ca 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/main/resources/log4j2.xml +++ b/opendc-experiments/opendc-experiments-capelin/src/main/resources/log4j2.xml @@ -30,13 +30,7 @@ </Console> </Appenders> <Loggers> - <Logger name="org.opendc" level="debug" additivity="false"> - <AppenderRef ref="Console"/> - </Logger> - <Logger name="org.opendc.experiments.capelin" level="info" additivity="false"> - <AppenderRef ref="Console"/> - </Logger> - <Logger name="org.opendc.experiments.vm.trace" level="debug" additivity="false"> + <Logger name="org.opendc" level="warn" additivity="false"> <AppenderRef ref="Console"/> </Logger> <Logger name="org.apache.hadoop" level="warn" additivity="false"> |
