summaryrefslogtreecommitdiff
path: root/opendc-experiments/opendc-experiments-base
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-experiments/opendc-experiments-base')
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt34
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/Scenario.kt2
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioFactories.kt61
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioWriter.kt67
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenarioSpec.kt8
5 files changed, 145 insertions, 27 deletions
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 bf5188a2..d6ee5d72 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
@@ -58,9 +58,10 @@ public fun runScenarios(
val ansiReset = "\u001B[0m"
val ansiGreen = "\u001B[32m"
val ansiBlue = "\u001B[34m"
- clearOutputFolder(scenarios[0].outputFolder)
- for (scenario in scenarios) {
+ setupOutputFolderStructure(scenarios[0].outputFolder)
+
+ for ((i, scenario) in scenarios.withIndex()) {
val pool = ForkJoinPool(parallelism)
println(
"\n\n$ansiGreen================================================================================$ansiReset",
@@ -70,6 +71,7 @@ public fun runScenarios(
runScenario(
scenario,
pool,
+ i,
)
}
}
@@ -84,6 +86,7 @@ public fun runScenarios(
public fun runScenario(
scenario: Scenario,
pool: ForkJoinPool,
+ index: Int = -1,
) {
val pb =
ProgressBarBuilder().setInitialMax(scenario.runs.toLong()).setStyle(ProgressBarStyle.ASCII)
@@ -91,7 +94,7 @@ public fun runScenario(
pool.submit {
LongStream.range(0, scenario.runs.toLong()).parallel().forEach {
- runScenario(scenario, scenario.initialSeed + it)
+ runScenario(scenario, scenario.initialSeed + it, index)
pb.step()
}
pb.close()
@@ -107,6 +110,7 @@ public fun runScenario(
public fun runScenario(
scenario: Scenario,
seed: Long,
+ index: Int = 0,
): Unit =
runSimulation {
val serviceDomain = "compute.opendc.org"
@@ -126,7 +130,7 @@ public fun runScenario(
val carbonTrace = getCarbonTrace(scenario.carbonTracePath)
val startTime = Duration.ofMillis(vms.minOf { it.startTime }.toEpochMilli())
- saveInOutputFolder(provisioner, serviceDomain, scenario, seed, startTime, carbonTrace)
+ addExportModel(provisioner, serviceDomain, scenario, seed, startTime, carbonTrace, index)
val service = provisioner.registry.resolve(serviceDomain, ComputeService::class.java)!!
service.replay(timeSource, vms, failureModelSpec = scenario.failureModel, seed = seed)
@@ -143,19 +147,20 @@ public fun runScenario(
* @param startTime The start time of the simulation given by the workload trace.
* @param carbonTrace The carbon trace used to determine carbon emissions.
*/
-public fun saveInOutputFolder(
+public fun addExportModel(
provisioner: Provisioner,
serviceDomain: String,
scenario: Scenario,
seed: Long,
startTime: Duration,
carbonTrace: CarbonTrace,
+ index: Int,
) {
provisioner.runStep(
registerComputeMonitor(
serviceDomain,
ParquetComputeMonitor(
- File("${scenario.outputFolder}/${scenario.name}"),
+ File("${scenario.outputFolder}/raw-output/$index"),
"seed=$seed",
bufferSize = 4096,
),
@@ -173,3 +178,20 @@ public fun saveInOutputFolder(
public fun clearOutputFolder(outputFolderPath: String) {
if (File(outputFolderPath).exists()) File(outputFolderPath).deleteRecursively()
}
+
+/**
+ * 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) {
+ val trackrPath = folderPath + "/trackr.json"
+ val simulationAnalysisPath = folderPath + "/simulation-analysis/"
+ val energyAnalysisPath = simulationAnalysisPath + "/power_draw/"
+ val emissionsAnalysisPath = simulationAnalysisPath + "/carbon_emission/"
+
+ File(folderPath).mkdir()
+ File(trackrPath).createNewFile()
+ File(simulationAnalysisPath).mkdir()
+ File(energyAnalysisPath).mkdir()
+ File(emissionsAnalysisPath).mkdir()
+}
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/Scenario.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/Scenario.kt
index 4f3fcd4f..7f0308fc 100644
--- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/Scenario.kt
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/Scenario.kt
@@ -41,7 +41,9 @@ import WorkloadSpec
* @property runs The Int representing the number of runs of the scenario. It defaults to 1.
* @property initialSeed The Int representing the initial seed of the scenario. It defaults to 0.
*/
+
public data class Scenario(
+ var id: Int = -1,
val topology: ScenarioTopologySpec,
val workload: WorkloadSpec,
val allocationPolicy: AllocationPolicySpec,
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
index 010c8845..19f8ebf0 100644
--- 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
@@ -22,13 +22,12 @@
package org.opendc.experiments.base.scenario
-import AllocationPolicySpec
import ScenarioTopologySpec
-import WorkloadSpec
import org.opendc.experiments.base.scenario.specs.ScenarioSpec
import java.io.File
private val scenarioReader = ScenarioReader()
+private val scenarioWriter = ScenarioWriter()
/**
* Returns a list of Scenarios from a given file path (input).
@@ -58,7 +57,14 @@ public fun getScenarios(file: File): List<Scenario> {
* @return A list of Scenarios.
*/
public fun getScenarios(scenarioSpec: ScenarioSpec): List<Scenario> {
+ val outputFolder = scenarioSpec.outputFolder + "/" + scenarioSpec.name
+ File(outputFolder).mkdirs()
+
+ val trackrPath = outputFolder + "/trackr.json"
+ File(trackrPath).createNewFile()
+
val scenarios = mutableListOf<Scenario>()
+ var scenarioID = 0
for (scenarioTopologySpec in scenarioSpec.topologies) {
for (workloadSpec in scenarioSpec.workloads) {
@@ -68,18 +74,21 @@ public fun getScenarios(scenarioSpec: ScenarioSpec): List<Scenario> {
for (exportModelSpec in scenarioSpec.exportModels) {
val scenario =
Scenario(
+ id = scenarioID,
topology = scenarioTopologySpec,
workload = workloadSpec,
allocationPolicy = allocationPolicySpec,
failureModel = failureModelSpec,
carbonTracePath = carbonTracePath,
exportModel = exportModelSpec,
- outputFolder = scenarioSpec.outputFolder,
- name = getOutputFolderName(scenarioSpec, scenarioTopologySpec, workloadSpec, allocationPolicySpec),
+ outputFolder = outputFolder,
+ name = scenarioID.toString(),
runs = scenarioSpec.runs,
initialSeed = scenarioSpec.initialSeed,
)
+ trackScenario(scenarioSpec, outputFolder, scenario, scenarioTopologySpec)
scenarios.add(scenario)
+ scenarioID++
}
}
}
@@ -91,22 +100,38 @@ public fun getScenarios(scenarioSpec: ScenarioSpec): List<Scenario> {
}
/**
- * Returns a string representing the output folder name for a given ScenarioSpec, CpuPowerModel, AllocationPolicySpec, and topology path.
+ * Writes a ScenarioSpec to a file.
*
* @param scenarioSpec The ScenarioSpec.
- * @param topology The specification of the topology used
- * @param workload The specification of the workload
- * @param allocationPolicy The allocation policy used
- * @return A string representing the output folder name.
+ * @param outputFolder The output folder path.
+ * @param scenario The Scenario.
+ * @param topologySpec The TopologySpec.
+
*/
-public fun getOutputFolderName(
+public fun trackScenario(
scenarioSpec: ScenarioSpec,
- topology: ScenarioTopologySpec,
- workload: WorkloadSpec,
- allocationPolicy: AllocationPolicySpec,
-): String {
- return "scenario=${scenarioSpec.name}" +
- "-topology=${topology.name}" +
- "-workload=${workload.name}" +
- "-allocation=${allocationPolicy.name}"
+ outputFolder: String,
+ scenario: Scenario,
+ topologySpec: ScenarioTopologySpec,
+) {
+ val trackrPath = outputFolder + "/trackr.json"
+ scenarioWriter.write(
+ ScenarioSpec(
+ id = scenario.id,
+ name = scenarioSpec.name,
+ topologies = listOf(topologySpec),
+ workloads = listOf(scenario.workload),
+ allocationPolicies = listOf(scenario.allocationPolicy),
+ // when implemented, add failure models here
+ carbonTracePaths = listOf(scenario.carbonTracePath),
+ exportModels = listOf(scenario.exportModel),
+ outputFolder = scenario.outputFolder,
+ initialSeed = scenario.initialSeed,
+ runs = scenario.runs,
+ ),
+ 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/ScenarioWriter.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioWriter.kt
new file mode 100644
index 00000000..8d99647a
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/ScenarioWriter.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 ScenarioWriter {
+ private var jsonText = "["
+ private val json = Json { prettyPrint = true }
+
+ /**
+ * Write the given [scenarioSpec] 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/ScenarioSpec.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/scenario/specs/ScenarioSpec.kt
index cfbb913c..876a62cf 100644
--- 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
@@ -28,6 +28,7 @@ import FailureModelSpec
import ScenarioTopologySpec
import WorkloadSpec
import kotlinx.serialization.Serializable
+import java.util.UUID
/**
* specification describing a scenario
@@ -43,6 +44,8 @@ import kotlinx.serialization.Serializable
*/
@Serializable
public data class ScenarioSpec(
+ var id: Int = -1,
+ var name: String = "",
val topologies: List<ScenarioTopologySpec>,
val workloads: List<WorkloadSpec>,
val allocationPolicies: List<AllocationPolicySpec>,
@@ -52,7 +55,6 @@ public data class ScenarioSpec(
val outputFolder: String = "output",
val initialSeed: Int = 0,
val runs: Int = 1,
- var name: String = "",
) {
init {
require(runs > 0) { "The number of runs should always be positive" }
@@ -60,8 +62,8 @@ public data class ScenarioSpec(
// generate name if not provided
// TODO: improve this
if (name == "") {
- name =
- "workload=${workloads[0].name}_topology=${topologies[0].name}_allocationPolicy=${allocationPolicies[0].name}"
+ name = "unnamed-simulation-${UUID.randomUUID().toString().substring(0, 4)}"
+// "workload=${workloads[0].name}_topology=${topologies[0].name}_allocationPolicy=${allocationPolicies[0].name}"
}
}
}