summaryrefslogtreecommitdiff
path: root/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin
diff options
context:
space:
mode:
authorRadu Nicolae <rnicolae04@gmail.com>2025-06-16 18:01:07 +0200
committerGitHub <noreply@github.com>2025-06-16 18:01:07 +0200
commit0df3d9ced743ac3385dd710c7133a6cf369b051c (patch)
treeeff5d6d67c275643e229731ba08c5fe7dc4ccd0a /opendc-experiments/opendc-experiments-m3sa/src/main/kotlin
parentc7e303ad1b5217e2ff24cee9538ac841d6149706 (diff)
integrated M3SA, updated with tests and CpuPowerModels
Diffstat (limited to 'opendc-experiments/opendc-experiments-m3sa/src/main/kotlin')
-rw-r--r--opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/M3SAAnalyzer.kt (renamed from opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/M3saAnalyzer.kt)48
-rw-r--r--opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SACli.kt80
-rw-r--r--opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SARunner.kt33
3 files changed, 117 insertions, 44 deletions
diff --git a/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/M3saAnalyzer.kt b/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/M3SAAnalyzer.kt
index 545ed656..5cc7cb78 100644
--- a/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/M3saAnalyzer.kt
+++ b/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/M3SAAnalyzer.kt
@@ -20,38 +20,56 @@
* SOFTWARE.
*/
-package org.opendc.experiments.m3sa
-
-import kotlin.io.path.Path
+import java.nio.file.Files
+import java.nio.file.Paths
/**
* This constant variable should be changed depending on the root folder that is being run.
* PATH_TO_PYTHON_MAIN should point to the main python file, ran when the analysis starts.
*/
-public val ANALYSIS_SCRIPTS_DIRECTORY: String = "./opendc-experiments/opendc-experiments-m3sa/src/main/python"
-public val ABSOLUTE_SCRIPT_PATH: String =
- Path("$ANALYSIS_SCRIPTS_DIRECTORY/main.py").toAbsolutePath().normalize().toString()
-public val SCRIPT_LANGUAGE: String = Path("$ANALYSIS_SCRIPTS_DIRECTORY/venv/bin/python3").toAbsolutePath().normalize().toString()
-
public fun m3saAnalyze(
outputFolderPath: String,
m3saSetupPath: String,
+ m3saExecPath: String,
) {
+ // script to run
+ val scriptPath =
+ Paths.get(m3saExecPath, "main.py")
+ .toAbsolutePath()
+ .normalize()
+ .toString()
+
+ // look for venv python; if missing, use system python3
+ val venvPython =
+ Paths.get(m3saExecPath, "venv", "bin", "python3")
+ .toAbsolutePath()
+ .normalize()
+ val pythonBin =
+ if (Files.isRegularFile(venvPython) && Files.isExecutable(venvPython)) {
+ venvPython.toString()
+ } else {
+ "python3" // fallback
+ }
+
val process =
ProcessBuilder(
- SCRIPT_LANGUAGE,
- ABSOLUTE_SCRIPT_PATH,
- outputFolderPath,
+ pythonBin,
+ scriptPath,
m3saSetupPath,
- ).directory(Path(ANALYSIS_SCRIPTS_DIRECTORY).toFile())
+ "$outputFolderPath/raw-output",
+ "-o",
+ outputFolderPath,
+ )
+ .redirectErrorStream(true)
.start()
val exitCode = process.waitFor()
+ val output = process.inputStream.bufferedReader().readText()
if (exitCode == 0) {
- println("[M3SA says] M3SA operation(s) completed successfully.")
+ println("[M3SA says] Success:\n$output")
} else {
- val errors = process.errorStream.bufferedReader().readText()
- println("[M3SA says] Exit code $exitCode; Error(s): $errors")
+ println("[M3SA says] Exit code $exitCode; Output:\n$output")
+ throw RuntimeException("M3SA analysis failed with exit code $exitCode")
}
}
diff --git a/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SACli.kt b/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SACli.kt
index 4fe58d88..51919722 100644
--- a/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SACli.kt
+++ b/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SACli.kt
@@ -30,9 +30,8 @@ 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 m3saAnalyze
import org.opendc.experiments.base.experiment.getExperiment
-import org.opendc.experiments.base.runner.runExperiment
-import org.opendc.experiments.m3sa.m3saAnalyze
import org.opendc.experiments.m3sa.scenario.getOutputFolder
import java.io.File
@@ -52,35 +51,62 @@ internal class M3SACommand : CliktCommand(name = "experiment") {
.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)
-
private val m3saPath by option("-m", "--m3sa-setup-path", help = "path to m3sa setup file")
.file(canBeDir = false, canBeFile = true)
- .defaultLazy { File("") }
+
+ private val m3saExec by option("-e", "--m3sa-exec-path", help = "path to m3sa executable")
+ .file(canBeDir = true, canBeFile = false)
+ .defaultLazy { File("opendc-experiments/opendc-experiments-m3sa/src/main/python/") }
+
+ private val inputIterations by option("-i", "--iterations", help = "number of iterations to run")
+ .int()
+ .default(1)
override fun run() {
- println("The provided m3saPath is $m3saPath")
-
- val experiment = getExperiment(scenarioPath)
- runExperiment(experiment, parallelism)
-
- if (m3saPath.toString().isNotEmpty()) {
- m3saAnalyze(
- outputFolderPath = getOutputFolder(scenarioPath),
- m3saSetupPath = m3saPath.toString(),
- )
- } else {
- println(
- "\n" +
- "===================================================\n" +
- "|M3SA path is not provided. Skipping M3SA analysis.|\n" +
- "===================================================",
- )
+ val file = File("analysis.txt")
+ if (!file.exists()) {
+ file.createNewFile()
}
+
+ var iterations = inputIterations
+ var currentIteration = 1
+
+ while (iterations > 0) {
+ val startTime = System.currentTimeMillis()
+ val experiment = getExperiment(scenarioPath)
+ org.opendc.experiments.base.runner.runExperiment(experiment)
+ val simulationEnd = System.currentTimeMillis()
+ println("Simulation time: ${(simulationEnd - startTime) / 1000} ms")
+
+ if (m3saPath != null) {
+ m3saAnalyze(
+ outputFolderPath = getOutputFolder(scenarioPath),
+ m3saSetupPath = m3saPath.toString(),
+ m3saExecPath = m3saExec.toString(),
+ )
+ } else {
+ println(
+ "\n" +
+ "===================================================\n" +
+ "|M3SA path is not provided. Skipping M3SA analysis.|\n" +
+ "===================================================",
+ )
+ }
+
+ val endTime = System.currentTimeMillis()
+ println("OpenDC time: ${(simulationEnd - startTime) / 1000.0} s")
+ println("M3SA time: ${(endTime - simulationEnd) / 1000.0} s")
+ println("Total operation time: ${(endTime - startTime) / 1000.0} s")
+
+ file.appendText("$currentIteration. OpenDC time: ${(simulationEnd - startTime) / 1000.0} s\n")
+ file.appendText("$currentIteration. M3SA time: ${(endTime - simulationEnd) / 1000.0} s\n")
+ file.appendText("$currentIteration. Total operation time: ${(endTime - startTime) / 1000.0} s\n\n")
+
+ iterations -= 1
+ currentIteration += 1
+ }
+
+ file.appendText("===================================================\n")
+ println("Finished $scenarioPath")
}
}
diff --git a/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SARunner.kt b/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SARunner.kt
index 49bbdb96..9bc7045f 100644
--- a/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SARunner.kt
+++ b/opendc-experiments/opendc-experiments-m3sa/src/main/kotlin/org/opendc/experiments/m3sa/runner/M3SARunner.kt
@@ -25,7 +25,10 @@
package org.opendc.experiments.m3sa.runner
import org.opendc.experiments.base.experiment.Scenario
+import org.opendc.experiments.base.runner.runScenario
import org.opendc.experiments.base.runner.setupOutputFolderStructure
+import java.io.File
+import java.util.Optional
/**
* Run scenario when no pool is available for parallel execution
@@ -35,9 +38,35 @@ import org.opendc.experiments.base.runner.setupOutputFolderStructure
*/
public fun runExperiment(
experiment: List<Scenario>,
- parallelism: Int,
+ extraSimDataPath: Optional<String>,
) {
+ val ansiReset = "\u001B[0m"
+ val ansiGreen = "\u001B[32m"
+ val ansiBlue = "\u001B[34m"
+
setupOutputFolderStructure(experiment[0].outputFolder)
- runExperiment(experiment, parallelism)
+ var latestScenarioId = experiment.map { it.id }.maxOrNull() ?: 0
+
+ for (scenario in experiment) {
+ println(
+ "\n\n$ansiGreen================================================================================$ansiReset",
+ )
+ println("$ansiBlue Running scenario: ${scenario.name} $ansiReset")
+ println("$ansiGreen================================================================================$ansiReset")
+ runScenario(
+ scenario,
+ )
+ }
+
+ if (extraSimDataPath.isEmpty) return
+
+ for (directory in File(extraSimDataPath.get()).listFiles()!!) {
+ if (!directory.isDirectory) continue
+ latestScenarioId += 1
+
+ val copyPath = "${experiment[0].outputFolder}/raw-output/$latestScenarioId"
+ File(copyPath).mkdirs()
+ directory.copyRecursively(File(copyPath), true)
+ }
}