diff options
10 files changed, 196 insertions, 33 deletions
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt index e2f6c9d0..36e413d9 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt @@ -32,8 +32,29 @@ public class ServiceRegistry(private val registry: MutableMap<String, MutableMap ): T? { val servicesForName = registry[name] ?: return null - @Suppress("UNCHECKED_CAST") - return servicesForName[type] as T? + val service = servicesForName[type] + + if (service == null) { + throw IllegalStateException("Service $type not registered for name $name") + } + + try { + @Suppress("UNCHECKED_CAST") + return service as T? + } catch (e: ClassCastException) { + throw IllegalStateException("Service $type registered for name $name is not of the given type") + } + } + + public fun <T : Any> hasService( + name: String, + type: Class<T>, + ): Boolean { + val servicesForName = registry[name] ?: return false + + servicesForName[type] ?: return false + + return true } public fun <T : Any> register( diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltTaskExportColumns.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltTaskExportColumns.kt index 5c3ef3bf..f862a843 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltTaskExportColumns.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltTaskExportColumns.kt @@ -80,7 +80,12 @@ public object DfltTaskExportColumns { Types.required(BINARY) .`as`(LogicalTypeAnnotation.stringType()) .named("host_name"), - ) { Binary.fromString(it.host?.name) } + ) { + if (it.hostInfo == null) { + return@ExportColumn Binary.fromString("") + } + return@ExportColumn Binary.fromString(it.hostInfo!!.name) + } public val MEM_CAPACITY: ExportColumn<TaskTableReader> = ExportColumn( @@ -168,7 +173,12 @@ public object DfltTaskExportColumns { Types.optional(BINARY) .`as`(LogicalTypeAnnotation.stringType()) .named("task_state"), - ) { Binary.fromString(it.taskState?.name) } + ) { + if (it.taskState == null) { + return@ExportColumn Binary.fromString("") + } + return@ExportColumn Binary.fromString(it.taskState!!.name) + } /** * The columns that are always included in the output file. diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReader.kt index 771ced37..8861eabb 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReader.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReader.kt @@ -58,7 +58,7 @@ public interface TaskTableReader : Exportable { /** * The [HostInfo] of the host on which the task is hosted or `null` if it has no host. */ - public val host: HostInfo? + public val hostInfo: HostInfo? /** * The uptime of the host since last time in ms. diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReaderImpl.kt index 881b9916..f6a52759 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReaderImpl.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/task/TaskTableReaderImpl.kt @@ -50,7 +50,7 @@ public class TaskTableReaderImpl( } override fun setValues(table: TaskTableReader) { - host = table.host + hostInfo = table.hostInfo _timestamp = table.timestamp _timestampAbsolute = table.timestampAbsolute @@ -90,8 +90,8 @@ public class TaskTableReaderImpl( /** * The [HostInfo] of the host on which the task is hosted. */ - override var host: HostInfo? = null - private var _host: SimHost? = null + override var hostInfo: HostInfo? = null + private var simHost: SimHost? = null private var _timestamp = Instant.MIN override val timestamp: Instant @@ -172,9 +172,9 @@ public class TaskTableReaderImpl( */ override fun record(now: Instant) { val newHost = service.lookupHost(task) - if (newHost != null && newHost.getName() != _host?.getName()) { - _host = newHost - host = + if (newHost != null && newHost.getName() != simHost?.getName()) { + simHost = newHost + hostInfo = HostInfo( newHost.getName(), newHost.getClusterName(), @@ -185,8 +185,8 @@ public class TaskTableReaderImpl( ) } - val cpuStats = _host?.getCpuStats(task) - val sysStats = _host?.getSystemStats(task) + val cpuStats = simHost?.getCpuStats(task) + val sysStats = simHost?.getSystemStats(task) _timestamp = now _timestampAbsolute = now + startTime @@ -221,7 +221,7 @@ public class TaskTableReaderImpl( previousCpuStealTime = _cpuStealTime previousCpuLostTime = _cpuLostTime - _host = null + simHost = null _cpuLimit = 0.0 } } 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 index f4df7991..d231b93b 100644 --- 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 @@ -43,12 +43,12 @@ internal class ExperimentCommand : CliktCommand(name = "experiment") { /** * The path to the environment directory. */ - private val scenarioPath by option("--experiment-path", help = "path to experiment file") + private val experimentPath by option("--experiment-path", help = "path to experiment file") .file(canBeDir = false, canBeFile = true) .defaultLazy { File("resources/experiment.json") } override fun run() { - val experiment = getExperiment(scenarioPath) + val experiment = getExperiment(experimentPath) runExperiment(experiment) } } 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 15445450..f7c444ea 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 @@ -131,23 +131,27 @@ public fun runScenario( service.setTasksExpected(workload.size) service.setMetricReader(provisioner.getMonitor()) - val carbonModel = provisioner.registry.resolve(serviceDomain, CarbonModel::class.java)!! - val computeScheduler = provisioner.registry.resolve(serviceDomain, ComputeScheduler::class.java)!! - if (computeScheduler is CarbonReceiver) { - carbonModel.addReceiver(computeScheduler) - } - carbonModel.addReceiver(service) - - if (scenario.allocationPolicySpec is TimeShiftAllocationPolicySpec) { - val taskStopper = - createTaskStopper( - scenario.allocationPolicySpec.taskStopper, - coroutineContext, - timeSource, - ) - if (taskStopper != null) { - taskStopper.setService(service) - carbonModel.addReceiver(taskStopper) + var carbonModel: CarbonModel? = null + if (provisioner.registry.hasService(serviceDomain, CarbonModel::class.java)) { + carbonModel = provisioner.registry.resolve(serviceDomain, CarbonModel::class.java)!! + + val computeScheduler = provisioner.registry.resolve(serviceDomain, ComputeScheduler::class.java)!! + if (computeScheduler is CarbonReceiver) { + carbonModel.addReceiver(computeScheduler) + carbonModel.addReceiver(service) + } + + if (scenario.allocationPolicySpec is TimeShiftAllocationPolicySpec) { + val taskStopper = + createTaskStopper( + scenario.allocationPolicySpec.taskStopper, + coroutineContext, + timeSource, + ) + if (taskStopper != null) { + taskStopper.setService(service) + carbonModel.addReceiver(taskStopper) + } } } diff --git a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ExperimentRunnerTest.kt b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ExperimentRunnerTest.kt new file mode 100644 index 00000000..6365f60d --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ExperimentRunnerTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 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 + +import org.junit.jupiter.api.Test +import org.opendc.experiments.base.runner.ExperimentCommand +import java.io.File + +/** + * An integration test suite for the Experiment Runner. + */ +class ExperimentRunnerTest { + /** + * ExperimentRunner test 1 + * This test runs the experiment defined in the experiment_1.json file. + * + * In this test, the bitbrains-small workload is executed with and without a carbon trace. + */ + @Test + fun testExperimentRunner1() { + ExperimentCommand().main(arrayOf("--experiment-path", "src/test/resources/experiments/experiment_1.json")) + + val someDir = File("output") + someDir.deleteRecursively() + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/experiments/experiment_1.json b/opendc-experiments/opendc-experiments-base/src/test/resources/experiments/experiment_1.json new file mode 100644 index 00000000..48ae75ce --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/experiments/experiment_1.json @@ -0,0 +1,23 @@ +{ + "topologies": [ + {"pathToFile": "src/test/resources/topologies/single_50_big.json"}, + {"pathToFile": "src/test/resources/topologies/single_50_big_BE.json"} + ], + "workloads": [{ + "pathToFile": "src/test/resources/workloadTraces/bitbrains-small", + "type": "ComputeWorkload", + "submissionTime": "2024-03-01T00:00:00" + }], + "allocationPolicies": [ + { + "type": "prefab", + "policyName": "Mem" + } + ], + "exportModels": [ + { + "exportInterval": 3600, + "printFrequency": 24 + } + ] +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/single_50_big.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/single_50_big.json new file mode 100644 index 00000000..676d4f3d --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/single_50_big.json @@ -0,0 +1,28 @@ +{ + "clusters": + [ + { + "name": "C01", + "hosts" : + [ + { + "name": "H01", + "cpu": + { + "coreCount": 64, + "coreSpeed": 2000 + }, + "memory": { + "memorySize": 140457600000 + }, + "powerModel": { + "modelType": "linear", + "power": 400.0, + "idlePower": 100.0, + "maxPower": 200.0 + } + } + ] + } + ] +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/single_50_big_BE.json b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/single_50_big_BE.json new file mode 100644 index 00000000..d2c19861 --- /dev/null +++ b/opendc-experiments/opendc-experiments-base/src/test/resources/topologies/single_50_big_BE.json @@ -0,0 +1,31 @@ +{ + "clusters": + [ + { + "name": "C01", + "hosts" : + [ + { + "name": "H01", + "cpu": + { + "coreCount": 64, + "coreSpeed": 2000 + }, + "memory": { + "memorySize": 140457600000 + }, + "powerModel": { + "modelType": "linear", + "power": 400.0, + "idlePower": 100.0, + "maxPower": 200.0 + } + } + ], + "powerSource": { + "carbonTracePath": "src/test/resources/carbonTraces/2022-01-01_2022-12-31_BE.parquet" + } + } + ] +} |
