From fa6e850b11bf09947c4afc03f4af18f488436bbd Mon Sep 17 00:00:00 2001 From: Dante Niewenhuis Date: Thu, 29 Aug 2024 10:05:46 +0200 Subject: Renamed Scenario to Experiment. A Scenario is now defined as a single setup. An experiment is a set of Scenarios. (#247) --- .../experiments/base/runner/ExperimentCli.kt | 63 ++++++++++ .../experiments/base/runner/ExperimentRunner.kt | 56 +++++++++ .../opendc/experiments/base/runner/ScenarioCli.kt | 65 ----------- .../experiments/base/runner/ScenarioRunner.kt | 32 +---- .../base/scenario/ExperimentFactories.kt | 115 ++++++++++++++++++ .../experiments/base/scenario/ExperimentReader.kt | 54 +++++++++ .../experiments/base/scenario/ExperimentWriter.kt | 67 +++++++++++ .../experiments/base/scenario/ScenarioFactories.kt | 115 ------------------ .../experiments/base/scenario/ScenarioReader.kt | 54 --------- .../experiments/base/scenario/ScenarioWriter.kt | 67 ----------- .../base/scenario/specs/ExperimentSpec.kt | 115 ++++++++++++++++++ .../base/scenario/specs/ScenarioSpec.kt | 41 +++++++ .../base/scenario/specs/ScenariosSpec.kt | 130 --------------------- 13 files changed, 512 insertions(+), 462 deletions(-) create mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt create mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt delete mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioCli.kt create mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentFactories.kt create mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentReader.kt create mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentWriter.kt delete mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioFactories.kt delete mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioReader.kt delete mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioWriter.kt create mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ExperimentSpec.kt create mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenarioSpec.kt delete mode 100644 opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenariosSpec.kt (limited to 'opendc-experiments/opendc-experiments-base/src') diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt new file mode 100644 index 00000000..28ebe45c --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt @@ -0,0 +1,63 @@ +/* + * 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("ExperimentCli") + +package org.opendc.experiments.base.runner + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.options.default +import com.github.ajalt.clikt.parameters.options.defaultLazy +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.types.file +import com.github.ajalt.clikt.parameters.types.int +import org.opendc.experiments.base.scenario.getExperiment +import java.io.File + +/** + * Main entrypoint of the application. + */ +public fun main(args: Array): Unit = ExperimentCommand().main(args) + +/** + * Represents the command for the Scenario experiments. + */ +internal class ExperimentCommand : CliktCommand(name = "experiment") { + /** + * The path to the environment directory. + */ + private val scenarioPath by option("--experiment-path", help = "path to experiment file") + .file(canBeDir = false, canBeFile = true) + .defaultLazy { File("resources/experiment.json") } + + /** + * 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) + + override fun run() { + val experiment = getExperiment(scenarioPath) + runExperiment(experiment, parallelism) + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt new file mode 100644 index 00000000..076cfb9f --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt @@ -0,0 +1,56 @@ +/* + * 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.runner + +import org.opendc.experiments.base.scenario.Scenario +import java.util.concurrent.ForkJoinPool + +/** + * Run scenario when no pool is available for parallel execution + * + * @param experiment The scenarios to run + * @param parallelism The number of scenarios that can be run in parallel + */ +public fun runExperiment( + experiment: List, + parallelism: Int, +) { + val ansiReset = "\u001B[0m" + val ansiGreen = "\u001B[32m" + val ansiBlue = "\u001B[34m" + + setupOutputFolderStructure(experiment[0].outputFolder) + + for (scenario in experiment) { + val pool = ForkJoinPool(parallelism) + println( + "\n\n$ansiGreen================================================================================$ansiReset", + ) + println("$ansiBlue Running scenario: ${scenario.name} $ansiReset") + println("$ansiGreen================================================================================$ansiReset") + runScenario( + scenario, + pool, + ) + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioCli.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioCli.kt deleted file mode 100644 index abf9ad46..00000000 --- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioCli.kt +++ /dev/null @@ -1,65 +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. - */ - -@file:JvmName("ScenarioCli") - -package org.opendc.experiments.base.runner - -import com.github.ajalt.clikt.core.CliktCommand -import com.github.ajalt.clikt.parameters.options.default -import com.github.ajalt.clikt.parameters.options.defaultLazy -import com.github.ajalt.clikt.parameters.options.option -import com.github.ajalt.clikt.parameters.types.file -import com.github.ajalt.clikt.parameters.types.int -import org.opendc.experiments.base.scenario.getScenarios -import java.io.File - -/** - * Main entrypoint of the application. - */ -public fun main(args: Array): Unit = ScenarioCommand().main(args) - -/** - * Represents the command for the Scenario experiments. - */ -internal class ScenarioCommand : CliktCommand(name = "scenario") { - /** - * The path to the environment directory. - */ - private val scenarioPath by option("--scenario-path", help = "path to scenario file") - .file(canBeDir = false, canBeFile = true) - .defaultLazy { File("resources/scenario.json") } - - /** - * 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) - - override fun run() { - val scenarios = getScenarios(scenarioPath) - runScenarios(scenarios, parallelism) - - // TODO: implement outputResults(scenario) // this will take the results, from a folder, and output them visually - } -} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt index abd359ff..5462b406 100644 --- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt @@ -44,36 +44,6 @@ import java.util.Random import java.util.concurrent.ForkJoinPool import java.util.stream.LongStream -/** - * Run scenario when no pool is available for parallel execution - * - * @param scenarios The scenarios to run - * @param parallelism The number of scenarios that can be run in parallel - */ -public fun runScenarios( - scenarios: List, - parallelism: Int, -) { - val ansiReset = "\u001B[0m" - val ansiGreen = "\u001B[32m" - val ansiBlue = "\u001B[34m" - - setupOutputFolderStructure(scenarios[0].outputFolder) - - for (scenario in scenarios) { - val pool = ForkJoinPool(parallelism) - println( - "\n\n$ansiGreen================================================================================$ansiReset", - ) - println("$ansiBlue Running scenario: ${scenario.name} $ansiReset") - println("$ansiGreen================================================================================$ansiReset") - runScenario( - scenario, - pool, - ) - } -} - /** * Run scenario when a pool is available for parallel execution * The scenario is run multiple times based on the user input @@ -180,7 +150,7 @@ public fun clearOutputFolder(outputFolderPath: String) { * Utility function to create the output folder structure for the simulation results. * @param folderPath The path to the output folder */ -private fun setupOutputFolderStructure(folderPath: String) { +public fun setupOutputFolderStructure(folderPath: String) { val trackrPath = "$folderPath/trackr.json" val simulationAnalysisPath = "$folderPath/simulation-analysis/" val energyAnalysisPath = "$simulationAnalysisPath/power_draw/" diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentFactories.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentFactories.kt new file mode 100644 index 00000000..b364ffe6 --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentFactories.kt @@ -0,0 +1,115 @@ +/* + * 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.scenario + +import org.opendc.experiments.base.scenario.specs.ExperimentSpec +import org.opendc.experiments.base.scenario.specs.ScenarioSpec +import java.io.File + +private val experimentReader = ExperimentReader() +private val experimentWriter = ExperimentWriter() + +/** + * Returns a list of Scenarios from a given file path (input). + * + * @param filePath The path to the file containing the scenario specifications. + * @return A list of Scenarios. + */ +public fun getExperiment(filePath: String): List { + return getExperiment(File(filePath)) +} + +/** + * Returns a list of Scenarios from a given file. Reads and decodes the contents of the (JSON) file. + * + * @param file The file containing the scenario specifications. + * @return A list of Scenarios. + */ +public fun getExperiment(file: File): List { + return getExperiment(experimentReader.read(file)) +} + +/** + * Returns a list of Scenarios from a given ScenarioSpec by generating all possible combinations of + * workloads, allocation policies, failure models, and export models within a topology. + * + * @param experimentSpec The ScenarioSpec containing the scenario specifications. + * @return A list of Scenarios. + */ +public fun getExperiment(experimentSpec: ExperimentSpec): List { + val outputFolder = experimentSpec.outputFolder + "/" + experimentSpec.name + File(outputFolder).mkdirs() + + val trackrPath = "$outputFolder/trackr.json" + File(trackrPath).createNewFile() + + val scenarios = mutableListOf() + + val cartesianInput = experimentSpec.getCartesian() + + for ((scenarioID, scenarioSpec) in cartesianInput.withIndex()) { + val scenario = + Scenario( + id = scenarioID, + topologySpec = scenarioSpec.topology, + workloadSpec = scenarioSpec.workload, + allocationPolicySpec = scenarioSpec.allocationPolicy, + failureModelSpec = scenarioSpec.failureModel, + checkpointModelSpec = scenarioSpec.checkpointModel, + carbonTracePath = scenarioSpec.carbonTracePath, + exportModelSpec = scenarioSpec.exportModel, + outputFolder = outputFolder, + name = scenarioID.toString(), + runs = experimentSpec.runs, + initialSeed = experimentSpec.initialSeed, + computeExportConfig = scenarioSpec.computeExportConfig, + ) + trackScenario(scenarioSpec, outputFolder) + scenarios.add(scenario) + } + + return scenarios +} + +/** + * Writes a ScenarioSpec to a file. + * + * @param scenariosSpec The ScenarioSpec. + * @param outputFolder The output folder path. + * @param scenario The Scenario. + * @param topologySpec The TopologySpec. + + */ +public fun trackScenario( + scenarioSpec: ScenarioSpec, + outputFolder: String, +) { + val trackrPath = "$outputFolder/trackr.json" + experimentWriter.write( + scenarioSpec, + File(trackrPath), + ) + + // remove the last comma + File(trackrPath).writeText(File(trackrPath).readText().dropLast(3) + "]") +} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentReader.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentReader.kt new file mode 100644 index 00000000..00b57602 --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentReader.kt @@ -0,0 +1,54 @@ +/* + * 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.scenario + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream +import org.opendc.compute.telemetry.export.parquet.ComputeExportConfig +import org.opendc.experiments.base.scenario.specs.ExperimentSpec +import java.io.File +import java.io.InputStream +import java.nio.file.Path +import kotlin.io.path.inputStream + +public class ExperimentReader { +// private val jsonReader = Json { serializersModule = failureModule } + private val jsonReader = Json + + public fun read(file: File): ExperimentSpec = read(file.inputStream()) + + public fun read(path: Path): ExperimentSpec = read(path.inputStream()) + + /** + * Read the specified [input]. + */ + @OptIn(ExperimentalSerializationApi::class) + public fun read(input: InputStream): ExperimentSpec { + // Loads the default parquet output fields, + // so that they can be deserialized + ComputeExportConfig.loadDfltColumns() + + return jsonReader.decodeFromStream(input) + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentWriter.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentWriter.kt new file mode 100644 index 00000000..6afe6031 --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ExperimentWriter.kt @@ -0,0 +1,67 @@ +/* + * 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.scenario + +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import org.opendc.experiments.base.scenario.specs.ScenarioSpec +import java.io.File + +/** + * A writer for writing scenarios to a file. + * @param jsonText The JSON text to write to the file, which is constantly updated during the writing process. + * @param json The JSON object used to encode the scenario specification. + */ +public class ExperimentWriter { + private var jsonText = "[" + private val json = Json { prettyPrint = true } + + /** + * Write the given [scenariosSpec] to the given [file]. + */ + public fun write( + scenarioSpec: ScenarioSpec, + file: File, + ) { + openArray(file) + val jsonString = json.encodeToString(scenarioSpec) + "," + jsonText += jsonString + "\n" + file.writeText(jsonText) + closeArray(file) + } + + /** + * Delete the last character of the file. + */ + private fun openArray(file: File) { + val text = file.readText() + file.writeText(text.dropLast(0)) + } + + /** + * Add the closing bracket to the file. + */ + private fun closeArray(file: File) { + file.appendText("]") + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioFactories.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioFactories.kt deleted file mode 100644 index fb43f102..00000000 --- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioFactories.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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.scenario - -import org.opendc.experiments.base.scenario.specs.ScenarioSpec -import org.opendc.experiments.base.scenario.specs.ScenariosSpec -import java.io.File - -private val scenarioReader = ScenarioReader() -private val scenarioWriter = ScenarioWriter() - -/** - * Returns a list of Scenarios from a given file path (input). - * - * @param filePath The path to the file containing the scenario specifications. - * @return A list of Scenarios. - */ -public fun getScenarios(filePath: String): List { - return getScenarios(File(filePath)) -} - -/** - * Returns a list of Scenarios from a given file. Reads and decodes the contents of the (JSON) file. - * - * @param file The file containing the scenario specifications. - * @return A list of Scenarios. - */ -public fun getScenarios(file: File): List { - return getScenarios(scenarioReader.read(file)) -} - -/** - * Returns a list of Scenarios from a given ScenarioSpec by generating all possible combinations of - * workloads, allocation policies, failure models, and export models within a topology. - * - * @param scenariosSpec The ScenarioSpec containing the scenario specifications. - * @return A list of Scenarios. - */ -public fun getScenarios(scenariosSpec: ScenariosSpec): List { - val outputFolder = scenariosSpec.outputFolder + "/" + scenariosSpec.name - File(outputFolder).mkdirs() - - val trackrPath = "$outputFolder/trackr.json" - File(trackrPath).createNewFile() - - val scenarios = mutableListOf() - - val cartesianInput = scenariosSpec.getCartesian() - - for ((scenarioID, scenarioSpec) in cartesianInput.withIndex()) { - val scenario = - Scenario( - id = scenarioID, - topologySpec = scenarioSpec.topology, - workloadSpec = scenarioSpec.workload, - allocationPolicySpec = scenarioSpec.allocationPolicy, - failureModelSpec = scenarioSpec.failureModel, - checkpointModelSpec = scenarioSpec.checkpointModel, - carbonTracePath = scenarioSpec.carbonTracePath, - exportModelSpec = scenarioSpec.exportModel, - outputFolder = outputFolder, - name = scenarioID.toString(), - runs = scenariosSpec.runs, - initialSeed = scenariosSpec.initialSeed, - computeExportConfig = scenarioSpec.computeExportConfig, - ) - trackScenario(scenarioSpec, outputFolder) - scenarios.add(scenario) - } - - return scenarios -} - -/** - * Writes a ScenarioSpec to a file. - * - * @param scenariosSpec The ScenarioSpec. - * @param outputFolder The output folder path. - * @param scenario The Scenario. - * @param topologySpec The TopologySpec. - - */ -public fun trackScenario( - scenarioSpec: ScenarioSpec, - outputFolder: String, -) { - val trackrPath = "$outputFolder/trackr.json" - scenarioWriter.write( - scenarioSpec, - File(trackrPath), - ) - - // remove the last comma - File(trackrPath).writeText(File(trackrPath).readText().dropLast(3) + "]") -} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioReader.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioReader.kt deleted file mode 100644 index 1fba71d1..00000000 --- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioReader.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.scenario - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream -import org.opendc.compute.telemetry.export.parquet.ComputeExportConfig -import org.opendc.experiments.base.scenario.specs.ScenariosSpec -import java.io.File -import java.io.InputStream -import java.nio.file.Path -import kotlin.io.path.inputStream - -public class ScenarioReader { -// private val jsonReader = Json { serializersModule = failureModule } - private val jsonReader = Json - - public fun read(file: File): ScenariosSpec = read(file.inputStream()) - - public fun read(path: Path): ScenariosSpec = read(path.inputStream()) - - /** - * Read the specified [input]. - */ - @OptIn(ExperimentalSerializationApi::class) - public fun read(input: InputStream): ScenariosSpec { - // Loads the default parquet output fields, - // so that they can be deserialized - ComputeExportConfig.loadDfltColumns() - - return jsonReader.decodeFromStream(input) - } -} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioWriter.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioWriter.kt deleted file mode 100644 index a582d140..00000000 --- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioWriter.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.scenario - -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import org.opendc.experiments.base.scenario.specs.ScenarioSpec -import java.io.File - -/** - * A writer for writing scenarios to a file. - * @param jsonText The JSON text to write to the file, which is constantly updated during the writing process. - * @param json The JSON object used to encode the scenario specification. - */ -public class ScenarioWriter { - private var jsonText = "[" - private val json = Json { prettyPrint = true } - - /** - * Write the given [scenariosSpec] to the given [file]. - */ - public fun write( - scenarioSpec: ScenarioSpec, - file: File, - ) { - openArray(file) - val jsonString = json.encodeToString(scenarioSpec) + "," - jsonText += jsonString + "\n" - file.writeText(jsonText) - closeArray(file) - } - - /** - * Delete the last character of the file. - */ - private fun openArray(file: File) { - val text = file.readText() - file.writeText(text.dropLast(0)) - } - - /** - * Add the closing bracket to the file. - */ - private fun closeArray(file: File) { - file.appendText("]") - } -} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ExperimentSpec.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ExperimentSpec.kt new file mode 100644 index 00000000..db26849e --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ExperimentSpec.kt @@ -0,0 +1,115 @@ +/* + * 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.scenario.specs + +import kotlinx.serialization.Serializable +import org.opendc.common.logger.infoNewLine +import org.opendc.common.logger.logger +import org.opendc.compute.telemetry.export.parquet.ComputeExportConfig +import java.util.UUID + +/** + * specification describing a scenario + * + * @property topologies + * @property workloads + * @property allocationPolicies + * @property failureModels + * @property exportModels + * @property outputFolder + * @property initialSeed + * @property runs + * @property computeExportConfig configures which parquet columns are to + * be included in the output files. + */ +@Serializable +public data class ExperimentSpec( + var id: Int = -1, + var name: String = "", + val outputFolder: String = "output", + val initialSeed: Int = 0, + val runs: Int = 1, + val topologies: Set, + val workloads: Set, + val allocationPolicies: Set = setOf(AllocationPolicySpec()), + val exportModels: Set = setOf(ExportModelSpec()), + val failureModels: Set = setOf(null), + val checkpointModels: Set = setOf(null), + val carbonTracePaths: Set = setOf(null), + val computeExportConfig: ComputeExportConfig = ComputeExportConfig.ALL_COLUMNS, +) { + init { + require(runs > 0) { "The number of runs should always be positive" } + + // generate name if not provided + // TODO: improve this + if (name == "") { + name = "unnamed-simulation-${UUID.randomUUID().toString().substring(0, 4)}" +// "workload=${workloads[0].name}_topology=${topologies[0].name}_allocationPolicy=${allocationPolicies[0].name}" + } + + LOG.infoNewLine(computeExportConfig.fmt()) + } + + public fun getCartesian(): Sequence { + return sequence { + val checkpointDiv = carbonTracePaths.size + val failureDiv = checkpointDiv * checkpointModels.size + val exportDiv = failureDiv * failureModels.size + val allocationDiv = exportDiv * exportModels.size + val workloadDiv = allocationDiv * allocationPolicies.size + val topologyDiv = workloadDiv * workloads.size + val numScenarios = topologyDiv * topologies.size + + val topologyList = topologies.toList() + val workloadList = workloads.toList() + val allocationPolicyList = allocationPolicies.toList() + val exportModelList = exportModels.toList() + val failureModelList = failureModels.toList() + val checkpointModelList = checkpointModels.toList() + val carbonTracePathList = carbonTracePaths.toList() + + for (i in 0 until numScenarios) { + yield( + ScenarioSpec( + id, + name, + outputFolder, + computeExportConfig = computeExportConfig, + topologyList[(i / topologyDiv) % topologyList.size], + workloadList[(i / workloadDiv) % workloadList.size], + allocationPolicyList[(i / allocationDiv) % allocationPolicyList.size], + exportModelList[(i / exportDiv) % exportModelList.size], + failureModelList[(i / failureDiv) % failureModelList.size], + checkpointModelList[(i / checkpointDiv) % checkpointModelList.size], + carbonTracePathList[i % carbonTracePathList.size], + ), + ) + } + } + } + + internal companion object { + private val LOG by logger() + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenarioSpec.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenarioSpec.kt new file mode 100644 index 00000000..41e9a885 --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenarioSpec.kt @@ -0,0 +1,41 @@ +/* + * 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.scenario.specs + +import kotlinx.serialization.Serializable +import org.opendc.compute.telemetry.export.parquet.ComputeExportConfig + +@Serializable +public data class ScenarioSpec( + var id: Int = -1, + var name: String = "", + val outputFolder: String = "output", + val computeExportConfig: ComputeExportConfig, + val topology: ScenarioTopologySpec, + val workload: WorkloadSpec, + val allocationPolicy: AllocationPolicySpec = AllocationPolicySpec(), + val exportModel: ExportModelSpec = ExportModelSpec(), + val failureModel: FailureModelSpec? = null, + val checkpointModel: CheckpointModelSpec? = null, + val carbonTracePath: String? = null, +) diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenariosSpec.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenariosSpec.kt deleted file mode 100644 index cb4491b6..00000000 --- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenariosSpec.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.scenario.specs - -import kotlinx.serialization.Serializable -import org.opendc.common.logger.infoNewLine -import org.opendc.common.logger.logger -import org.opendc.compute.telemetry.export.parquet.ComputeExportConfig -import java.util.UUID - -@Serializable -public data class ScenarioSpec( - var id: Int = -1, - var name: String = "", - val outputFolder: String = "output", - val computeExportConfig: ComputeExportConfig, - val topology: ScenarioTopologySpec, - val workload: WorkloadSpec, - val allocationPolicy: AllocationPolicySpec = AllocationPolicySpec(), - val exportModel: ExportModelSpec = ExportModelSpec(), - val failureModel: FailureModelSpec? = null, - val checkpointModel: CheckpointModelSpec? = null, - val carbonTracePath: String? = null, -) - -/** - * specification describing a scenario - * - * @property topologies - * @property workloads - * @property allocationPolicies - * @property failureModels - * @property exportModels - * @property outputFolder - * @property initialSeed - * @property runs - * @property computeExportConfig configures which parquet columns are to - * be included in the output files. - */ -@Serializable -public data class ScenariosSpec( - var id: Int = -1, - var name: String = "", - val outputFolder: String = "output", - val initialSeed: Int = 0, - val runs: Int = 1, - val topologies: Set, - val workloads: Set, - val allocationPolicies: Set = setOf(AllocationPolicySpec()), - val exportModels: Set = setOf(ExportModelSpec()), - val failureModels: Set = setOf(null), - val checkpointModels: Set = setOf(null), - val carbonTracePaths: Set = setOf(null), - val computeExportConfig: ComputeExportConfig = ComputeExportConfig.ALL_COLUMNS, -) { - init { - require(runs > 0) { "The number of runs should always be positive" } - - // generate name if not provided - // TODO: improve this - if (name == "") { - name = "unnamed-simulation-${UUID.randomUUID().toString().substring(0, 4)}" -// "workload=${workloads[0].name}_topology=${topologies[0].name}_allocationPolicy=${allocationPolicies[0].name}" - } - - LOG.infoNewLine(computeExportConfig.fmt()) - } - - public fun getCartesian(): Sequence { - return sequence { - val checkpointDiv = carbonTracePaths.size - val failureDiv = checkpointDiv * checkpointModels.size - val exportDiv = failureDiv * failureModels.size - val allocationDiv = exportDiv * exportModels.size - val workloadDiv = allocationDiv * allocationPolicies.size - val topologyDiv = workloadDiv * workloads.size - val numScenarios = topologyDiv * topologies.size - - val topologyList = topologies.toList() - val workloadList = workloads.toList() - val allocationPolicyList = allocationPolicies.toList() - val exportModelList = exportModels.toList() - val failureModelList = failureModels.toList() - val checkpointModelList = checkpointModels.toList() - val carbonTracePathList = carbonTracePaths.toList() - - for (i in 0 until numScenarios) { - yield( - ScenarioSpec( - id, - name, - outputFolder, - computeExportConfig = computeExportConfig, - topologyList[(i / topologyDiv) % topologyList.size], - workloadList[(i / workloadDiv) % workloadList.size], - allocationPolicyList[(i / allocationDiv) % allocationPolicyList.size], - exportModelList[(i / exportDiv) % exportModelList.size], - failureModelList[(i / failureDiv) % failureModelList.size], - checkpointModelList[(i / checkpointDiv) % checkpointModelList.size], - carbonTracePathList[i % carbonTracePathList.size], - ), - ) - } - } - } - - internal companion object { - private val LOG by logger() - } -} -- cgit v1.2.3