summaryrefslogtreecommitdiff
path: root/simulator
diff options
context:
space:
mode:
Diffstat (limited to 'simulator')
-rw-r--r--simulator/opendc-compute/build.gradle.kts21
-rw-r--r--simulator/opendc-compute/opendc-compute-core/build.gradle.kts41
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Flavor.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/Flavor.kt)0
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Server.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/Server.kt)0
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt)10
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerState.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ServerState.kt)0
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt)3
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/Image.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/Image.kt)11
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Metadata.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/Metadata.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Node.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/Node.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeEvent.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/NodeEvent.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeState.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/NodeState.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/driver/BareMetalDriver.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/BareMetalDriver.kt)8
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/ProvisioningService.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/service/ProvisioningService.kt)6
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/SimpleProvisioningService.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/service/SimpleProvisioningService.kt)6
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/Hypervisor.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/Hypervisor.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/HypervisorEvent.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/HypervisorEvent.kt)4
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/InsufficientMemoryOnServerException.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/InsufficientMemoryOnServerException.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/VirtDriver.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/VirtDriver.kt)7
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningEvent.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningEvent.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningService.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningService.kt)13
-rw-r--r--simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt)4
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts42
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ComputeSimExecutionContext.kt36
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/HypervisorView.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/HypervisorView.kt)4
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt246
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt206
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt38
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/SimpleVirtProvisioningService.kt)123
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadImage.kt43
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AllocationPolicy.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AllocationPolicy.kt)10
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableCoreMemoryAllocationPolicy.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AvailableCoreMemoryAllocationPolicy.kt)4
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableMemoryAllocationPolicy.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AvailableMemoryAllocationPolicy.kt)4
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ComparableAllocationPolicyLogic.kt)13
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/NumberOfActiveServersAllocationPolicy.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/NumberOfActiveServersAllocationPolicy.kt)4
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ProvisionedCoresAllocationPolicy.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ProvisionedCoresAllocationPolicy.kt)4
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/RandomAllocationPolicy.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/RandomAllocationPolicy.kt)11
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ReplayAllocationPolicy.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ReplayAllocationPolicy.kt)12
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModel.kt (renamed from simulator/opendc-core/src/main/kotlin/org/opendc/core/power/PowerModel.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModels.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/power/PowerModels.kt)5
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/Powerable.kt (renamed from simulator/opendc-core/src/main/kotlin/org/opendc/core/power/Powerable.kt)2
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt (renamed from simulator/opendc-compute/src/test/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt)46
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt (renamed from simulator/opendc-compute/src/test/kotlin/org/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt)36
-rw-r--r--simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt145
-rw-r--r--simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ShutdownException.kt52
-rw-r--r--simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/FlopsHistoryFragment.kt3
-rw-r--r--simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt475
-rw-r--r--simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/HypervisorImage.kt55
-rw-r--r--simulator/opendc-compute/src/test/kotlin/org/opendc/compute/virt/HypervisorTest.kt169
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts7
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt2
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts5
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.kt3
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt47
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.kt5
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ExperimentMonitor.kt4
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ParquetExperimentMonitor.kt6
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt14
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt22
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt40
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.kt14
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.kt9
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml2
-rw-r--r--simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.kt22
-rw-r--r--simulator/opendc-format/build.gradle.kts6
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt18
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt31
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt20
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt2
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt32
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt5
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt9
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt29
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt45
-rw-r--r--simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/wtf/WtfTraceReader.kt7
-rw-r--r--simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/swf/SwfTraceReaderTest.kt10
-rw-r--r--simulator/opendc-runner-web/build.gradle.kts5
-rw-r--r--simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt6
-rw-r--r--simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt25
-rw-r--r--simulator/opendc-simulator/build.gradle.kts32
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/build.gradle.kts (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerManagementContext.kt)27
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt281
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimExecutionContext.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerContext.kt)32
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimpleVirtDriver.kt)419
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt48
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt34
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/PerformanceInterferenceModel.kt)124
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/MemoryUnit.kt)6
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ProcessingNode.kt)6
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ProcessingUnit.kt)6
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/FlopsApplicationImage.kt)26
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt (renamed from simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/VmImage.kt)35
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt41
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt129
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt83
-rw-r--r--simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt (renamed from simulator/opendc-compute/src/test/kotlin/org/opendc/compute/core/image/FlopsApplicationImageTest.kt)37
-rw-r--r--simulator/opendc-simulator/opendc-simulator-core/build.gradle.kts32
-rw-r--r--simulator/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt (renamed from simulator/opendc-simulator/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt)0
-rw-r--r--simulator/opendc-simulator/opendc-simulator-failures/build.gradle.kts31
-rw-r--r--simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/CorrelatedFaultInjector.kt (renamed from simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/CorrelatedFaultInjector.kt)2
-rw-r--r--simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FailureDomain.kt (renamed from simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/FailureDomain.kt)2
-rw-r--r--simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FaultInjector.kt (renamed from simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/FaultInjector.kt)2
-rw-r--r--simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/UncorrelatedFaultInjector.kt (renamed from simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/UncorrelatedFaultInjector.kt)2
-rw-r--r--simulator/opendc-workflows/build.gradle.kts8
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt4
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt2
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt2
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt2
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt2
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt2
-rw-r--r--simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt2
-rw-r--r--simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt2
-rw-r--r--simulator/settings.gradle.kts7
113 files changed, 2208 insertions, 1652 deletions
diff --git a/simulator/opendc-compute/build.gradle.kts b/simulator/opendc-compute/build.gradle.kts
index dfdd6f35..bf920306 100644
--- a/simulator/opendc-compute/build.gradle.kts
+++ b/simulator/opendc-compute/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 AtLarge Research
+ * 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
@@ -20,21 +20,4 @@
* SOFTWARE.
*/
-description = "Cloud computing fabric simulation model"
-
-/* Build configuration */
-plugins {
- `kotlin-library-convention`
-}
-
-dependencies {
- api(project(":opendc-core"))
- implementation(project(":opendc-utils"))
- implementation("io.github.microutils:kotlin-logging:1.7.9")
-
- testImplementation(project(":opendc-simulator"))
- testRuntimeOnly("org.slf4j:slf4j-simple:${Library.SLF4J}")
- testImplementation("org.junit.jupiter:junit-jupiter-api:${Library.JUNIT_JUPITER}")
- testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Library.JUNIT_JUPITER}")
- testImplementation("org.junit.platform:junit-platform-launcher:${Library.JUNIT_PLATFORM}")
-}
+description = "Cloud computing fabric controller of OpenDC"
diff --git a/simulator/opendc-compute/opendc-compute-core/build.gradle.kts b/simulator/opendc-compute/opendc-compute-core/build.gradle.kts
new file mode 100644
index 00000000..9682b50f
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-core/build.gradle.kts
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+description = "Core implementation of the OpenDC Compute service"
+
+/* Build configuration */
+plugins {
+ `kotlin-library-convention`
+}
+
+dependencies {
+ api(project(":opendc-core"))
+ implementation(project(":opendc-utils"))
+ implementation("io.github.microutils:kotlin-logging:1.7.9")
+
+ testImplementation(project(":opendc-simulator:opendc-simulator-core"))
+ testImplementation(project(":opendc-compute:opendc-compute-simulator"))
+ testRuntimeOnly("org.slf4j:slf4j-simple:${Library.SLF4J}")
+ testImplementation("org.junit.jupiter:junit-jupiter-api:${Library.JUNIT_JUPITER}")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Library.JUNIT_JUPITER}")
+ testImplementation("org.junit.platform:junit-platform-launcher:${Library.JUNIT_PLATFORM}")
+}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/Flavor.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Flavor.kt
index e5ca115f..e5ca115f 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/Flavor.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Flavor.kt
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/Server.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Server.kt
index 948f622f..948f622f 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/Server.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Server.kt
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt
index fbef8a7d..e9212832 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt
@@ -22,8 +22,6 @@
package org.opendc.compute.core
-import org.opendc.core.services.ServiceKey
-
/**
* An event that is emitted by a [Server].
*/
@@ -40,12 +38,4 @@ public sealed class ServerEvent {
* @property previousState The previous state of the server.
*/
public data class StateChanged(override val server: Server, val previousState: ServerState) : ServerEvent()
-
- /**
- * This event is emitted when a server publishes a service.
- *
- * @property server The server that published the service.
- * @property key The service key of the service that was published.
- */
- public data class ServicePublished(override val server: Server, val key: ServiceKey<*>) : ServerEvent()
}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ServerState.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerState.kt
index 4b9d7c13..4b9d7c13 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ServerState.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerState.kt
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt
index 2b9158bf..01f86a1b 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt
@@ -22,7 +22,6 @@
package org.opendc.compute.core.image
-import org.opendc.compute.core.execution.ServerContext
import org.opendc.core.resource.TagContainer
import java.util.UUID
@@ -33,6 +32,4 @@ public object EmptyImage : Image {
override val uid: UUID = UUID.randomUUID()
override val name: String = "empty"
override val tags: TagContainer = emptyMap()
-
- override suspend fun invoke(ctx: ServerContext) {}
}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/Image.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/Image.kt
index d04920c3..e481fcc3 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/Image.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/Image.kt
@@ -22,7 +22,6 @@
package org.opendc.compute.core.image
-import org.opendc.compute.core.execution.ServerContext
import org.opendc.core.resource.Resource
/**
@@ -33,12 +32,4 @@ import org.opendc.core.resource.Resource
* useful for backup purposes or for producing “gold” server images if you plan to deploy a particular server
* configuration frequently.
*/
-public interface Image : Resource {
- /**
- * Launch the machine image in the specified [ServerContext].
- *
- * This method should encapsulate and characterize the runtime behavior of the instance resulting from launching
- * the image on some machine, in terms of the resource consumption on the machine.
- */
- public suspend operator fun invoke(ctx: ServerContext)
-}
+public interface Image : Resource
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/Metadata.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Metadata.kt
index 61a992b2..11eadd87 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/Metadata.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Metadata.kt
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal
+package org.opendc.compute.core.metal
/*
* Common metadata keys for bare-metal nodes.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/Node.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Node.kt
index 5cb4be1a..6d9506f1 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/Node.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Node.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal
+package org.opendc.compute.core.metal
import kotlinx.coroutines.flow.Flow
import org.opendc.compute.core.Server
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/NodeEvent.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeEvent.kt
index d367f2e6..4423e2bf 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/NodeEvent.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeEvent.kt
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal
+package org.opendc.compute.core.metal
/**
* An event that is emitted by a [Node].
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/NodeState.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeState.kt
index e76e0b43..bdc4841e 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/NodeState.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeState.kt
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal
+package org.opendc.compute.core.metal
/**
* An enumeration describing the possible states of a bare-metal compute node.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/BareMetalDriver.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/driver/BareMetalDriver.kt
index 5d8521ae..9db57127 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/BareMetalDriver.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/driver/BareMetalDriver.kt
@@ -20,21 +20,19 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal.driver
+package org.opendc.compute.core.metal.driver
import kotlinx.coroutines.flow.Flow
import org.opendc.compute.core.Server
import org.opendc.compute.core.image.Image
-import org.opendc.compute.metal.Node
-import org.opendc.core.failure.FailureDomain
-import org.opendc.core.power.Powerable
+import org.opendc.compute.core.metal.Node
import org.opendc.core.services.AbstractServiceKey
import java.util.UUID
/**
* A driver interface for the management interface of a bare-metal compute node.
*/
-public interface BareMetalDriver : Powerable, FailureDomain {
+public interface BareMetalDriver {
/**
* The [Node] that is controlled by this driver.
*/
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/service/ProvisioningService.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/ProvisioningService.kt
index c8b38912..bad5b47c 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/service/ProvisioningService.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/ProvisioningService.kt
@@ -20,11 +20,11 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal.service
+package org.opendc.compute.core.metal.service
import org.opendc.compute.core.image.Image
-import org.opendc.compute.metal.Node
-import org.opendc.compute.metal.driver.BareMetalDriver
+import org.opendc.compute.core.metal.Node
+import org.opendc.compute.core.metal.driver.BareMetalDriver
import org.opendc.core.services.AbstractServiceKey
import java.util.UUID
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/service/SimpleProvisioningService.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/SimpleProvisioningService.kt
index 3d126ba1..5222f2fb 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/service/SimpleProvisioningService.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/SimpleProvisioningService.kt
@@ -20,12 +20,12 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal.service
+package org.opendc.compute.core.metal.service
import kotlinx.coroutines.CancellationException
import org.opendc.compute.core.image.Image
-import org.opendc.compute.metal.Node
-import org.opendc.compute.metal.driver.BareMetalDriver
+import org.opendc.compute.core.metal.Node
+import org.opendc.compute.core.metal.driver.BareMetalDriver
/**
* A very basic implementation of the [ProvisioningService].
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/Hypervisor.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/Hypervisor.kt
index 5dd98bbc..1ae52baa 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/Hypervisor.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/Hypervisor.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt
+package org.opendc.compute.core.virt
import kotlinx.coroutines.flow.Flow
import org.opendc.core.Identity
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/HypervisorEvent.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/HypervisorEvent.kt
index 1e2e285c..9fb437de 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/HypervisorEvent.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/HypervisorEvent.kt
@@ -20,10 +20,10 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt
+package org.opendc.compute.core.virt
import org.opendc.compute.core.Server
-import org.opendc.compute.virt.driver.VirtDriver
+import org.opendc.compute.core.virt.driver.VirtDriver
/**
* An event that is emitted by a [VirtDriver].
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/InsufficientMemoryOnServerException.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/InsufficientMemoryOnServerException.kt
index 83dd70d4..6fe84ea6 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/InsufficientMemoryOnServerException.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/InsufficientMemoryOnServerException.kt
@@ -1,3 +1,3 @@
-package org.opendc.compute.virt.driver
+package org.opendc.compute.core.virt.driver
public class InsufficientMemoryOnServerException : IllegalStateException("Insufficient memory left on server.")
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/VirtDriver.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/VirtDriver.kt
index 9663f4da..5ecfd357 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/VirtDriver.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/VirtDriver.kt
@@ -20,13 +20,12 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.driver
+package org.opendc.compute.core.virt.driver
import kotlinx.coroutines.flow.Flow
-import org.opendc.compute.core.Flavor
import org.opendc.compute.core.Server
import org.opendc.compute.core.image.Image
-import org.opendc.compute.virt.HypervisorEvent
+import org.opendc.compute.core.virt.HypervisorEvent
import org.opendc.core.services.AbstractServiceKey
import java.util.UUID
@@ -51,7 +50,7 @@ public interface VirtDriver {
public suspend fun spawn(
name: String,
image: Image,
- flavor: Flavor
+ flavor: org.opendc.compute.core.Flavor
): Server
public companion object Key : AbstractServiceKey<VirtDriver>(UUID.randomUUID(), "virtual-driver")
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningEvent.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningEvent.kt
index 31f5d2c9..abd2fc95 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningEvent.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningEvent.kt
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service
+package org.opendc.compute.core.virt.service
/**
* An event that is emitted by the [VirtProvisioningService].
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningService.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningService.kt
index 7ed577c4..ab96e0a3 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/VirtProvisioningService.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningService.kt
@@ -20,25 +20,18 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service
+package org.opendc.compute.core.virt.service
import kotlinx.coroutines.flow.Flow
-import org.opendc.compute.core.Flavor
import org.opendc.compute.core.Server
import org.opendc.compute.core.image.Image
-import org.opendc.compute.virt.driver.VirtDriver
-import org.opendc.compute.virt.service.allocation.AllocationPolicy
+import org.opendc.compute.core.virt.driver.VirtDriver
/**
* A service for VM provisioning on a cloud.
*/
public interface VirtProvisioningService {
/**
- * The policy used for allocating a VM on the available hypervisors.
- */
- public val allocationPolicy: AllocationPolicy
-
- /**
* The events emitted by the service.
*/
public val events: Flow<VirtProvisioningEvent>
@@ -58,7 +51,7 @@ public interface VirtProvisioningService {
public suspend fun deploy(
name: String,
image: Image,
- flavor: Flavor
+ flavor: org.opendc.compute.core.Flavor
): Server
/**
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt
index 6ab8da2a..6c724277 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt
+++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt
@@ -22,7 +22,7 @@
package org.opendc.compute.core.workload
-import org.opendc.compute.core.image.VmImage
+import org.opendc.compute.core.image.Image
import org.opendc.core.User
import org.opendc.core.workload.Workload
import java.util.UUID
@@ -39,7 +39,7 @@ public data class VmWorkload(
override val uid: UUID,
override val name: String,
override val owner: User,
- val image: VmImage
+ val image: Image
) : Workload {
override fun equals(other: Any?): Boolean = other is VmWorkload && uid == other.uid
diff --git a/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts b/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts
new file mode 100644
index 00000000..d7570e54
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+description = "Simulator for OpenDC Compute"
+
+/* Build configuration */
+plugins {
+ `kotlin-library-convention`
+}
+
+dependencies {
+ api(project(":opendc-compute:opendc-compute-core"))
+ implementation(project(":opendc-utils"))
+ implementation("io.github.microutils:kotlin-logging:1.7.9")
+ implementation(project(":opendc-simulator:opendc-simulator-compute"))
+ api(project(":opendc-simulator:opendc-simulator-failures"))
+
+ testImplementation(project(":opendc-simulator:opendc-simulator-core"))
+ testRuntimeOnly("org.slf4j:slf4j-simple:${Library.SLF4J}")
+ testImplementation("org.junit.jupiter:junit-jupiter-api:${Library.JUNIT_JUPITER}")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Library.JUNIT_JUPITER}")
+ testImplementation("org.junit.platform:junit-platform-launcher:${Library.JUNIT_PLATFORM}")
+}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ComputeSimExecutionContext.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ComputeSimExecutionContext.kt
new file mode 100644
index 00000000..153a86b3
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ComputeSimExecutionContext.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.compute.simulator
+
+import org.opendc.compute.core.Server
+import org.opendc.simulator.compute.SimExecutionContext
+
+/**
+ * Extended [SimExecutionContext] in which workloads within the OpenDC Compute module run.
+ */
+public interface ComputeSimExecutionContext : SimExecutionContext {
+ /**
+ * The server on which the image runs.
+ */
+ public val server: Server
+}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/HypervisorView.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/HypervisorView.kt
index cf6b4487..1a79523e 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/HypervisorView.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/HypervisorView.kt
@@ -20,10 +20,10 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service
+package org.opendc.compute.simulator
import org.opendc.compute.core.Server
-import org.opendc.compute.virt.driver.VirtDriver
+import org.opendc.compute.core.virt.driver.VirtDriver
import java.util.UUID
public class HypervisorView(
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt
new file mode 100644
index 00000000..97f550ba
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt
@@ -0,0 +1,246 @@
+/*
+ * 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.compute.simulator
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.Flow
+import org.opendc.compute.core.Flavor
+import org.opendc.compute.core.Server
+import org.opendc.compute.core.ServerEvent
+import org.opendc.compute.core.ServerState
+import org.opendc.compute.core.image.EmptyImage
+import org.opendc.compute.core.image.Image
+import org.opendc.compute.core.metal.Node
+import org.opendc.compute.core.metal.NodeEvent
+import org.opendc.compute.core.metal.NodeState
+import org.opendc.compute.core.metal.driver.BareMetalDriver
+import org.opendc.compute.simulator.power.ConstantPowerModel
+import org.opendc.compute.simulator.power.PowerModel
+import org.opendc.compute.simulator.power.Powerable
+import org.opendc.core.services.ServiceRegistry
+import org.opendc.simulator.compute.SimBareMetalMachine
+import org.opendc.simulator.compute.SimExecutionContext
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.workload.SimWorkload
+import org.opendc.simulator.failures.FailureDomain
+import org.opendc.utils.flow.EventFlow
+import org.opendc.utils.flow.StateFlow
+import java.time.Clock
+import java.util.UUID
+import kotlin.random.Random
+
+/**
+ * A basic implementation of the [BareMetalDriver] that simulates an [Image] running on a bare-metal machine.
+ *
+ * @param coroutineScope The [CoroutineScope] the driver runs in.
+ * @param clock The virtual clock to keep track of time.
+ * @param uid The unique identifier of the machine.
+ * @param name An optional name of the machine.
+ * @param metadata The initial metadata of the node.
+ * @param machine The machine model to simulate.
+ * @param powerModel The power model of this machine.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+public class SimBareMetalDriver(
+ private val coroutineScope: CoroutineScope,
+ private val clock: Clock,
+ uid: UUID,
+ name: String,
+ metadata: Map<String, Any>,
+ machine: SimMachineModel,
+ powerModel: PowerModel<SimBareMetalDriver> = ConstantPowerModel(0.0)
+) : BareMetalDriver, FailureDomain, Powerable {
+ /**
+ * The flavor that corresponds to this machine.
+ */
+ private val flavor = Flavor(
+ machine.cpus.size,
+ machine.memory.map { it.size }.sum()
+ )
+
+ /**
+ * The events of the machine.
+ */
+ private val events = EventFlow<NodeEvent>()
+
+ /**
+ * The machine state.
+ */
+ private val nodeState =
+ StateFlow(Node(uid, name, metadata + ("driver" to this), NodeState.SHUTOFF, EmptyImage, null, events))
+
+ /**
+ * The [SimBareMetalMachine] we use to run the workload.
+ */
+ private val machine = SimBareMetalMachine(coroutineScope, clock, machine)
+
+ override val node: Flow<Node> = nodeState
+
+ override val usage: Flow<Double>
+ get() = this.machine.usage
+
+ override val powerDraw: Flow<Double> = powerModel(this)
+
+ /**
+ * The internal random instance.
+ */
+ private val random = Random(uid.leastSignificantBits xor uid.mostSignificantBits)
+
+ /**
+ * The [Job] that runs the simulated workload.
+ */
+ private var job: Job? = null
+
+ /**
+ * The event stream to publish to for the server.
+ */
+ private var serverEvents: EventFlow<ServerEvent>? = null
+
+ override suspend fun init(): Node {
+ return nodeState.value
+ }
+
+ override suspend fun start(): Node {
+ val node = nodeState.value
+ if (node.state != NodeState.SHUTOFF) {
+ return node
+ }
+
+ val events = EventFlow<ServerEvent>()
+ serverEvents = events
+ val server = Server(
+ UUID(random.nextLong(), random.nextLong()),
+ node.name,
+ emptyMap(),
+ flavor,
+ node.image,
+ ServerState.BUILD,
+ ServiceRegistry().put(BareMetalDriver, this@SimBareMetalDriver),
+ events
+ )
+
+ // Wrap the workload to pass in a ComputeSimExecutionContext
+ val workload = object : SimWorkload {
+ override suspend fun run(ctx: SimExecutionContext) {
+ val wrappedCtx = object : ComputeSimExecutionContext, SimExecutionContext by ctx {
+ override val server: Server
+ get() = nodeState.value.server!!
+ }
+ (node.image as SimWorkloadImage).workload.run(wrappedCtx)
+ }
+ }
+
+ job = coroutineScope.launch {
+ delay(1) // TODO Introduce boot time
+ initMachine()
+ try {
+ machine.run(workload)
+ exitMachine(null)
+ } catch (_: CancellationException) {
+ // Ignored
+ } catch (cause: Throwable) {
+ exitMachine(cause)
+ }
+ }
+
+ setNode(node.copy(state = NodeState.BOOT, server = server))
+ return nodeState.value
+ }
+
+ private fun initMachine() {
+ val server = nodeState.value.server?.copy(state = ServerState.ACTIVE)
+ setNode(nodeState.value.copy(state = NodeState.ACTIVE, server = server))
+ }
+
+ private fun exitMachine(cause: Throwable?) {
+ val newServerState =
+ if (cause == null)
+ ServerState.SHUTOFF
+ else
+ ServerState.ERROR
+ val newNodeState =
+ if (cause == null)
+ nodeState.value.state
+ else
+ NodeState.ERROR
+ val server = nodeState.value.server?.copy(state = newServerState)
+ setNode(nodeState.value.copy(state = newNodeState, server = server))
+
+ serverEvents?.close()
+ serverEvents = null
+ }
+
+ override suspend fun stop(): Node {
+ val node = nodeState.value
+ if (node.state == NodeState.SHUTOFF) {
+ return node
+ }
+
+ job?.cancelAndJoin()
+ setNode(node.copy(state = NodeState.SHUTOFF, server = null))
+ return node
+ }
+
+ override suspend fun reboot(): Node {
+ stop()
+ return start()
+ }
+
+ override suspend fun setImage(image: Image): Node {
+ setNode(nodeState.value.copy(image = image))
+ return nodeState.value
+ }
+
+ override suspend fun refresh(): Node = nodeState.value
+
+ private fun setNode(value: Node) {
+ val field = nodeState.value
+ if (field.state != value.state) {
+ events.emit(NodeEvent.StateChanged(value, field.state))
+ }
+
+ val oldServer = field.server
+ val newServer = value.server
+
+ if (oldServer != null && newServer != null && oldServer.state != newServer.state) {
+ serverEvents?.emit(ServerEvent.StateChanged(newServer, oldServer.state))
+ }
+
+ nodeState.value = value
+ }
+
+ override val scope: CoroutineScope
+ get() = coroutineScope
+
+ override suspend fun fail() {
+ val server = nodeState.value.server?.copy(state = ServerState.ERROR)
+ setNode(nodeState.value.copy(state = NodeState.ERROR, server = server))
+ }
+
+ override suspend fun recover() {
+ val server = nodeState.value.server?.copy(state = ServerState.ACTIVE)
+ setNode(nodeState.value.copy(state = NodeState.ACTIVE, server = server))
+ }
+
+ override fun toString(): String = "SimBareMetalDriver(node = ${nodeState.value.uid})"
+}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt
new file mode 100644
index 00000000..09eec1ef
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt
@@ -0,0 +1,206 @@
+/*
+ * 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.compute.simulator
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.launch
+import org.opendc.compute.core.*
+import org.opendc.compute.core.image.Image
+import org.opendc.compute.core.virt.HypervisorEvent
+import org.opendc.compute.core.virt.driver.InsufficientMemoryOnServerException
+import org.opendc.compute.core.virt.driver.VirtDriver
+import org.opendc.core.services.ServiceRegistry
+import org.opendc.simulator.compute.SimExecutionContext
+import org.opendc.simulator.compute.SimHypervisor
+import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+import org.opendc.simulator.compute.workload.SimWorkload
+import org.opendc.utils.flow.EventFlow
+import java.time.Clock
+import java.util.*
+
+/**
+ * A [VirtDriver] that is simulates virtual machines on a physical machine using [SimHypervisor].
+ */
+public class SimVirtDriver(
+ private val coroutineScope: CoroutineScope,
+ clock: Clock,
+ private val ctx: SimExecutionContext
+) : VirtDriver {
+
+ /**
+ * The server hosting this hypervisor.
+ */
+ public val server: Server
+ get() = (ctx as ComputeSimExecutionContext).server
+
+ /**
+ * The [EventFlow] to emit the events.
+ */
+ internal val eventFlow = EventFlow<HypervisorEvent>()
+
+ override val events: Flow<HypervisorEvent> = eventFlow
+
+ /**
+ * Current total memory use of the images on this hypervisor.
+ */
+ private var availableMemory: Long = ctx.machine.memory.map { it.size }.sum()
+
+ /**
+ * The hypervisor to run multiple workloads.
+ */
+ private val hypervisor = SimHypervisor(
+ coroutineScope,
+ clock,
+ object : SimHypervisor.Listener {
+ override fun onSliceFinish(
+ hypervisor: SimHypervisor,
+ requestedBurst: Long,
+ grantedBurst: Long,
+ overcommissionedBurst: Long,
+ interferedBurst: Long,
+ cpuUsage: Double,
+ cpuDemand: Double
+ ) {
+ eventFlow.emit(
+ HypervisorEvent.SliceFinished(
+ this@SimVirtDriver,
+ requestedBurst,
+ grantedBurst,
+ overcommissionedBurst,
+ interferedBurst,
+ cpuUsage,
+ cpuDemand,
+ vms.size,
+ (ctx as ComputeSimExecutionContext).server
+ )
+ )
+ }
+ }
+ )
+
+ /**
+ * The virtual machines running on the hypervisor.
+ */
+ private val vms = HashSet<VirtualMachine>()
+
+ override suspend fun spawn(name: String, image: Image, flavor: Flavor): Server {
+ val requiredMemory = flavor.memorySize
+ if (availableMemory - requiredMemory < 0) {
+ throw InsufficientMemoryOnServerException()
+ }
+ require(flavor.cpuCount <= ctx.machine.cpus.size) { "Machine does not fit" }
+
+ val events = EventFlow<ServerEvent>()
+ val server = Server(
+ UUID.randomUUID(),
+ name,
+ emptyMap(),
+ flavor,
+ image,
+ ServerState.BUILD,
+ ServiceRegistry(),
+ events
+ )
+ availableMemory -= requiredMemory
+ val vm = VirtualMachine(server, events, hypervisor.createMachine(ctx.machine))
+ vms.add(vm)
+ vmStarted(vm)
+ eventFlow.emit(HypervisorEvent.VmsUpdated(this, vms.size, availableMemory))
+ return server
+ }
+
+ private fun vmStarted(vm: VirtualMachine) {
+ vms.forEach { it ->
+ vm.performanceInterferenceModel?.onStart(it.server.image.name)
+ }
+ }
+
+ private fun vmStopped(vm: VirtualMachine) {
+ vms.forEach { it ->
+ vm.performanceInterferenceModel?.onStop(it.server.image.name)
+ }
+ }
+
+ /**
+ * A virtual machine instance that the driver manages.
+ */
+ private inner class VirtualMachine(server: Server, val events: EventFlow<ServerEvent>, machine: SimMachine) {
+ val performanceInterferenceModel: PerformanceInterferenceModel? = server.image.tags[IMAGE_PERF_INTERFERENCE_MODEL] as? PerformanceInterferenceModel?
+
+ val job = coroutineScope.launch {
+ val workload = object : SimWorkload {
+ override suspend fun run(ctx: SimExecutionContext) {
+ val wrappedCtx = object : ComputeSimExecutionContext, SimExecutionContext by ctx {
+ override val server: Server
+ get() = this@VirtualMachine.server
+ }
+ (server.image as SimWorkloadImage).workload.run(wrappedCtx)
+ }
+ }
+
+ delay(1) // TODO Introduce boot time
+ init()
+ try {
+ machine.run(workload)
+ exit(null)
+ } catch (cause: Throwable) {
+ exit(cause)
+ }
+ }
+
+ var server: Server = server
+ set(value) {
+ if (field.state != value.state) {
+ events.emit(ServerEvent.StateChanged(value, field.state))
+ }
+
+ field = value
+ }
+
+ private fun init() {
+ server = server.copy(state = ServerState.ACTIVE)
+ }
+
+ private fun exit(cause: Throwable?) {
+ val serverState =
+ if (cause == null)
+ ServerState.SHUTOFF
+ else
+ ServerState.ERROR
+ server = server.copy(state = serverState)
+ availableMemory += server.flavor.memorySize
+ vms.remove(this)
+ vmStopped(this)
+ eventFlow.emit(HypervisorEvent.VmsUpdated(this@SimVirtDriver, vms.size, availableMemory))
+ events.close()
+ }
+ }
+
+ public suspend fun run() {
+ hypervisor.run(ctx)
+ }
+}
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt
new file mode 100644
index 00000000..58b9408a
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.compute.simulator
+
+import kotlinx.coroutines.coroutineScope
+import org.opendc.simulator.compute.SimExecutionContext
+import org.opendc.simulator.compute.workload.SimWorkload
+
+public class SimVirtDriverWorkload : SimWorkload {
+ public lateinit var driver: SimVirtDriver
+
+ override suspend fun run(ctx: SimExecutionContext) {
+ coroutineScope {
+ driver = SimVirtDriver(this, ctx.clock, ctx)
+ driver.run()
+ }
+ }
+}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/SimpleVirtProvisioningService.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt
index 3141529f..e83370d7 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/SimpleVirtProvisioningService.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service
+package org.opendc.compute.simulator
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
@@ -32,30 +32,33 @@ import org.opendc.compute.core.Server
import org.opendc.compute.core.ServerEvent
import org.opendc.compute.core.ServerState
import org.opendc.compute.core.image.Image
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.metal.service.ProvisioningService
-import org.opendc.compute.virt.HypervisorEvent
-import org.opendc.compute.virt.HypervisorImage
-import org.opendc.compute.virt.driver.InsufficientMemoryOnServerException
-import org.opendc.compute.virt.driver.VirtDriver
-import org.opendc.compute.virt.service.allocation.AllocationPolicy
-import org.opendc.core.services.ServiceKey
+import org.opendc.compute.core.metal.service.ProvisioningService
+import org.opendc.compute.core.virt.HypervisorEvent
+import org.opendc.compute.core.virt.driver.InsufficientMemoryOnServerException
+import org.opendc.compute.core.virt.driver.VirtDriver
+import org.opendc.compute.core.virt.service.VirtProvisioningEvent
+import org.opendc.compute.core.virt.service.VirtProvisioningService
+import org.opendc.compute.simulator.allocation.AllocationPolicy
import org.opendc.utils.flow.EventFlow
import java.time.Clock
+import java.util.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.math.max
-private val logger = KotlinLogging.logger {}
-
@OptIn(ExperimentalCoroutinesApi::class)
-public class SimpleVirtProvisioningService(
+public class SimVirtProvisioningService(
private val coroutineScope: CoroutineScope,
private val clock: Clock,
private val provisioningService: ProvisioningService,
- override val allocationPolicy: AllocationPolicy
+ public val allocationPolicy: AllocationPolicy
) : VirtProvisioningService {
/**
+ * The logger instance to use.
+ */
+ private val logger = KotlinLogging.logger {}
+
+ /**
* The hypervisors that have been launched by the service.
*/
private val hypervisors: MutableMap<Server, HypervisorView> = mutableMapOf()
@@ -100,14 +103,26 @@ public class SimpleVirtProvisioningService(
coroutineScope.launch {
val provisionedNodes = provisioningService.nodes()
provisionedNodes.forEach { node ->
- val hypervisorImage = HypervisorImage
- val node = provisioningService.deploy(node, hypervisorImage)
- node.server!!.events.onEach { event ->
- when (event) {
- is ServerEvent.StateChanged -> stateChanged(event.server)
- is ServerEvent.ServicePublished -> servicePublished(event.server, event.key)
- }
- }.launchIn(this)
+ val workload = SimVirtDriverWorkload()
+ val hypervisorImage = SimWorkloadImage(UUID.randomUUID(), "vmm", emptyMap(), workload)
+ launch {
+ var init = false
+ val deployedNode = provisioningService.deploy(node, hypervisorImage)
+ val server = deployedNode.server!!
+ server.events.onEach { event ->
+ when (event) {
+ is ServerEvent.StateChanged -> {
+ if (!init) {
+ init = true
+ }
+ stateChanged(event.server)
+ }
+ }
+ }.launchIn(this)
+
+ delay(1)
+ onHypervisorAvailable(server, workload.driver)
+ }
}
}
}
@@ -123,7 +138,7 @@ public class SimpleVirtProvisioningService(
): Server {
eventFlow.emit(
VirtProvisioningEvent.MetricsAvailable(
- this@SimpleVirtProvisioningService,
+ this@SimVirtProvisioningService,
hypervisors.size,
availableHypervisors.size,
++submittedVms,
@@ -161,7 +176,7 @@ public class SimpleVirtProvisioningService(
val call = coroutineScope.launch {
delay(delay)
- this@SimpleVirtProvisioningService.call = null
+ this@SimVirtProvisioningService.call = null
schedule()
}
this.call = call
@@ -171,14 +186,14 @@ public class SimpleVirtProvisioningService(
val imagesToBeScheduled = incomingImages.toSet()
for (imageInstance in imagesToBeScheduled) {
- val requiredMemory = (imageInstance.image as VmImage).requiredMemory
+ val requiredMemory = imageInstance.image.tags["required-memory"] as Long
val selectedHv = allocationLogic.select(availableHypervisors, imageInstance)
if (selectedHv == null) {
if (requiredMemory > maxMemory || imageInstance.flavor.cpuCount > maxCores) {
eventFlow.emit(
VirtProvisioningEvent.MetricsAvailable(
- this@SimpleVirtProvisioningService,
+ this@SimVirtProvisioningService,
hypervisors.size,
availableHypervisors.size,
submittedVms,
@@ -218,7 +233,7 @@ public class SimpleVirtProvisioningService(
eventFlow.emit(
VirtProvisioningEvent.MetricsAvailable(
- this@SimpleVirtProvisioningService,
+ this@SimVirtProvisioningService,
hypervisors.size,
availableHypervisors.size,
submittedVms,
@@ -239,7 +254,7 @@ public class SimpleVirtProvisioningService(
eventFlow.emit(
VirtProvisioningEvent.MetricsAvailable(
- this@SimpleVirtProvisioningService,
+ this@SimVirtProvisioningService,
hypervisors.size,
availableHypervisors.size,
submittedVms,
@@ -297,7 +312,7 @@ public class SimpleVirtProvisioningService(
eventFlow.emit(
VirtProvisioningEvent.MetricsAvailable(
- this@SimpleVirtProvisioningService,
+ this@SimVirtProvisioningService,
hypervisors.size,
availableHypervisors.size,
submittedVms,
@@ -320,7 +335,7 @@ public class SimpleVirtProvisioningService(
eventFlow.emit(
VirtProvisioningEvent.MetricsAvailable(
- this@SimpleVirtProvisioningService,
+ this@SimVirtProvisioningService,
hypervisors.size,
availableHypervisors.size,
submittedVms,
@@ -339,35 +354,33 @@ public class SimpleVirtProvisioningService(
}
}
- private fun servicePublished(server: Server, key: ServiceKey<*>) {
- if (key == VirtDriver.Key) {
- val hv = hypervisors[server] ?: return
- hv.driver = server.services[VirtDriver]
- availableHypervisors += hv
-
- eventFlow.emit(
- VirtProvisioningEvent.MetricsAvailable(
- this@SimpleVirtProvisioningService,
- hypervisors.size,
- availableHypervisors.size,
- submittedVms,
- runningVms,
- finishedVms,
- queuedVms,
- unscheduledVms
- )
+ private fun onHypervisorAvailable(server: Server, hypervisor: SimVirtDriver) {
+ val hv = hypervisors[server] ?: return
+ hv.driver = hypervisor
+ availableHypervisors += hv
+
+ eventFlow.emit(
+ VirtProvisioningEvent.MetricsAvailable(
+ this@SimVirtProvisioningService,
+ hypervisors.size,
+ availableHypervisors.size,
+ submittedVms,
+ runningVms,
+ finishedVms,
+ queuedVms,
+ unscheduledVms
)
+ )
- hv.driver.events
- .onEach { event ->
- if (event is HypervisorEvent.VmsUpdated) {
- hv.numberOfActiveServers = event.numberOfActiveServers
- hv.availableMemory = event.availableMemory
- }
- }.launchIn(coroutineScope)
+ hv.driver.events
+ .onEach { event ->
+ if (event is HypervisorEvent.VmsUpdated) {
+ hv.numberOfActiveServers = event.numberOfActiveServers
+ hv.availableMemory = event.availableMemory
+ }
+ }.launchIn(coroutineScope)
- requestCycle()
- }
+ requestCycle()
}
public data class ImageView(
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadImage.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadImage.kt
new file mode 100644
index 00000000..b48de1d5
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadImage.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.compute.simulator
+
+import org.opendc.compute.core.image.Image
+import org.opendc.core.resource.TagContainer
+import org.opendc.simulator.compute.workload.SimWorkload
+import java.util.*
+
+/**
+ * An application [Image] that runs a [SimWorkload].
+ *
+ * @property uid The unique identifier of this image.
+ * @property name The name of this image.
+ * @property tags The tags attached to the image.
+ * @property workload The workload to run for this image.
+ */
+public data class SimWorkloadImage(
+ public override val uid: UUID,
+ public override val name: String,
+ public override val tags: TagContainer,
+ public val workload: SimWorkload
+) : Image
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AllocationPolicy.kt
index 099d1740..2018b9f2 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AllocationPolicy.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AllocationPolicy.kt
@@ -20,11 +20,11 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
-import org.opendc.compute.metal.Node
-import org.opendc.compute.virt.service.HypervisorView
-import org.opendc.compute.virt.service.SimpleVirtProvisioningService
+import org.opendc.compute.core.metal.Node
+import org.opendc.compute.simulator.HypervisorView
+import org.opendc.compute.simulator.SimVirtProvisioningService
/**
* A policy for selecting the [Node] an image should be deployed to,
@@ -39,7 +39,7 @@ public interface AllocationPolicy {
*/
public fun select(
hypervisors: Set<HypervisorView>,
- image: SimpleVirtProvisioningService.ImageView
+ image: SimVirtProvisioningService.ImageView
): HypervisorView?
}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AvailableCoreMemoryAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableCoreMemoryAllocationPolicy.kt
index cfbf3cd3..38a07b2b 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AvailableCoreMemoryAllocationPolicy.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableCoreMemoryAllocationPolicy.kt
@@ -20,9 +20,9 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
-import org.opendc.compute.virt.service.HypervisorView
+import org.opendc.compute.simulator.HypervisorView
/**
* An [AllocationPolicy] that selects the machine with the highest/lowest amount of memory per core.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AvailableMemoryAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableMemoryAllocationPolicy.kt
index 48172765..e87abd7b 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/AvailableMemoryAllocationPolicy.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableMemoryAllocationPolicy.kt
@@ -20,9 +20,9 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
-import org.opendc.compute.virt.service.HypervisorView
+import org.opendc.compute.simulator.HypervisorView
/**
* Allocation policy that selects the node with the most available memory.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ComparableAllocationPolicyLogic.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt
index 8803009d..8defe8b7 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ComparableAllocationPolicyLogic.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt
@@ -20,11 +20,10 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.virt.service.HypervisorView
-import org.opendc.compute.virt.service.SimpleVirtProvisioningService
+import org.opendc.compute.simulator.HypervisorView
+import org.opendc.compute.simulator.SimVirtProvisioningService
/**
* The logic for an [AllocationPolicy] that uses a [Comparator] to select the appropriate node.
@@ -37,14 +36,14 @@ public interface ComparableAllocationPolicyLogic : AllocationPolicy.Logic {
override fun select(
hypervisors: Set<HypervisorView>,
- image: SimpleVirtProvisioningService.ImageView
+ image: SimVirtProvisioningService.ImageView
): HypervisorView? {
return hypervisors.asSequence()
.filter { hv ->
- val fitsMemory = hv.availableMemory >= (image.image as VmImage).requiredMemory
+ val fitsMemory = hv.availableMemory >= (image.image.tags["required-memory"] as Long)
val fitsCpu = hv.server.flavor.cpuCount >= image.flavor.cpuCount
fitsMemory && fitsCpu
}
- .minWith(comparator.thenBy { it.server.uid })
+ .minWithOrNull(comparator.thenBy { it.server.uid })
}
}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/NumberOfActiveServersAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/NumberOfActiveServersAllocationPolicy.kt
index 63ba64ce..5e2b895c 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/NumberOfActiveServersAllocationPolicy.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/NumberOfActiveServersAllocationPolicy.kt
@@ -20,9 +20,9 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
-import org.opendc.compute.virt.service.HypervisorView
+import org.opendc.compute.simulator.HypervisorView
/**
* Allocation policy that selects the node with the least amount of active servers.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ProvisionedCoresAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ProvisionedCoresAllocationPolicy.kt
index d76e9c82..4344d979 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ProvisionedCoresAllocationPolicy.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ProvisionedCoresAllocationPolicy.kt
@@ -20,9 +20,9 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
-import org.opendc.compute.virt.service.HypervisorView
+import org.opendc.compute.simulator.HypervisorView
/**
* An [AllocationPolicy] that takes into account the number of vCPUs that have been provisioned on this machine
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/RandomAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/RandomAllocationPolicy.kt
index d143ffe6..ac34f410 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/RandomAllocationPolicy.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/RandomAllocationPolicy.kt
@@ -20,11 +20,10 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.virt.service.HypervisorView
-import org.opendc.compute.virt.service.SimpleVirtProvisioningService
+import org.opendc.compute.simulator.HypervisorView
+import org.opendc.compute.simulator.SimVirtProvisioningService
import kotlin.random.Random
/**
@@ -35,11 +34,11 @@ public class RandomAllocationPolicy(private val random: Random = Random(0)) : Al
override fun invoke(): AllocationPolicy.Logic = object : AllocationPolicy.Logic {
override fun select(
hypervisors: Set<HypervisorView>,
- image: SimpleVirtProvisioningService.ImageView
+ image: SimVirtProvisioningService.ImageView
): HypervisorView? {
return hypervisors.asIterable()
.filter { hv ->
- val fitsMemory = hv.availableMemory >= (image.image as VmImage).requiredMemory
+ val fitsMemory = hv.availableMemory >= (image.image.tags["required-memory"] as Long)
val fitsCpu = hv.server.flavor.cpuCount >= image.flavor.cpuCount
fitsMemory && fitsCpu
}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ReplayAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ReplayAllocationPolicy.kt
index a623633d..5312f4da 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/service/allocation/ReplayAllocationPolicy.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ReplayAllocationPolicy.kt
@@ -20,11 +20,11 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.service.allocation
+package org.opendc.compute.simulator.allocation
import mu.KotlinLogging
-import org.opendc.compute.virt.service.HypervisorView
-import org.opendc.compute.virt.service.SimpleVirtProvisioningService
+import org.opendc.compute.simulator.HypervisorView
+import org.opendc.compute.simulator.SimVirtProvisioningService
private val logger = KotlinLogging.logger {}
@@ -38,7 +38,7 @@ public class ReplayAllocationPolicy(private val vmPlacements: Map<String, String
override fun invoke(): AllocationPolicy.Logic = object : AllocationPolicy.Logic {
override fun select(
hypervisors: Set<HypervisorView>,
- image: SimpleVirtProvisioningService.ImageView
+ image: SimVirtProvisioningService.ImageView
): HypervisorView? {
val clusterName = vmPlacements[image.name]
?: throw IllegalStateException("Could not find placement data in VM placement file for VM ${image.name}")
@@ -46,10 +46,10 @@ public class ReplayAllocationPolicy(private val vmPlacements: Map<String, String
if (machinesInCluster.isEmpty()) {
logger.info { "Could not find any machines belonging to cluster $clusterName for image ${image.name}, assigning randomly." }
- return hypervisors.maxBy { it.availableMemory }
+ return hypervisors.maxByOrNull { it.availableMemory }
}
- return machinesInCluster.maxBy { it.availableMemory }
+ return machinesInCluster.maxByOrNull { it.availableMemory }
?: throw IllegalStateException("Cloud not find any machine and could not randomly assign")
}
}
diff --git a/simulator/opendc-core/src/main/kotlin/org/opendc/core/power/PowerModel.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModel.kt
index e93023d8..174a510b 100644
--- a/simulator/opendc-core/src/main/kotlin/org/opendc/core/power/PowerModel.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModel.kt
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.opendc.core.power
+package org.opendc.compute.simulator.power
import kotlinx.coroutines.flow.Flow
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/power/PowerModels.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModels.kt
index 9286626c..651eba6e 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/power/PowerModels.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModels.kt
@@ -20,12 +20,11 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal.power
+package org.opendc.compute.simulator.power
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import org.opendc.compute.metal.driver.BareMetalDriver
-import org.opendc.core.power.PowerModel
+import org.opendc.compute.core.metal.driver.BareMetalDriver
/**
* A power model which emits a single value.
diff --git a/simulator/opendc-core/src/main/kotlin/org/opendc/core/power/Powerable.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/Powerable.kt
index 4b73ad92..dcf74468 100644
--- a/simulator/opendc-core/src/main/kotlin/org/opendc/core/power/Powerable.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/Powerable.kt
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.opendc.core.power
+package org.opendc.compute.simulator.power
import kotlinx.coroutines.flow.Flow
diff --git a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt
index 9c9dc864..0f1bd444 100644
--- a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt
@@ -20,55 +20,62 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal.driver
+package org.opendc.compute.simulator
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.withContext
import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
-import org.opendc.compute.core.ProcessingNode
-import org.opendc.compute.core.ProcessingUnit
import org.opendc.compute.core.ServerEvent
import org.opendc.compute.core.ServerState
-import org.opendc.compute.core.image.FlopsApplicationImage
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.compute.workload.SimFlopsWorkload
import org.opendc.simulator.utils.DelayControllerClockAdapter
import java.util.UUID
@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimpleBareMetalDriverTest {
- /**
- * A smoke test for the bare-metal driver.
- */
+internal class SimBareMetalDriverTest {
+ private lateinit var machineModel: SimMachineModel
+
+ @BeforeEach
+ fun setUp() {
+ val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4)
+
+ machineModel = SimMachineModel(
+ cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 2000.0) },
+ memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
+ )
+ }
+
@Test
- fun smoke() {
+ fun testFlopsWorkload() {
val testScope = TestCoroutineScope()
val clock = DelayControllerClockAdapter(testScope)
var finalState: ServerState = ServerState.BUILD
+ var finalTime = 0L
+
testScope.launch {
- val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4)
- val cpus = List(4) { ProcessingUnit(cpuNode, it, 2400.0) }
- val driver = SimpleBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList())
- val image = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1_000, 2)
+ val driver = SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel)
+ val image = SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(4_000, 2, utilization = 1.0))
// Batch driver commands
withContext(coroutineContext) {
driver.init()
driver.setImage(image)
val server = driver.start().server!!
- driver.usage
- .onEach { println("${clock.millis()} $it") }
- .launchIn(this)
server.events.collect { event ->
when (event) {
is ServerEvent.StateChanged -> {
- println("${clock.millis()} $event")
finalState = event.server.state
+ finalTime = clock.millis()
}
}
}
@@ -77,5 +84,6 @@ internal class SimpleBareMetalDriverTest {
testScope.advanceUntilIdle()
assertEquals(ServerState.SHUTOFF, finalState)
+ assertEquals(1001, finalTime)
}
}
diff --git a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt
index 91d4787c..def78ce7 100644
--- a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt
@@ -20,18 +20,21 @@
* SOFTWARE.
*/
-package org.opendc.compute.metal.service
+package org.opendc.compute.simulator
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
-import org.opendc.compute.core.ProcessingNode
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.core.image.FlopsApplicationImage
-import org.opendc.compute.metal.driver.SimpleBareMetalDriver
+import org.opendc.compute.core.metal.service.SimpleProvisioningService
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.compute.workload.SimFlopsWorkload
import org.opendc.simulator.utils.DelayControllerClockAdapter
import java.util.UUID
@@ -39,21 +42,30 @@ import java.util.UUID
* Test suite for the [SimpleProvisioningService].
*/
@OptIn(ExperimentalCoroutinesApi::class)
-internal class SimpleProvisioningServiceTest {
+internal class SimProvisioningServiceTest {
+ private lateinit var machineModel: SimMachineModel
+
+ @BeforeEach
+ fun setUp() {
+ val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4)
+
+ machineModel = SimMachineModel(
+ cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 2000.0) },
+ memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
+ )
+ }
+
/**
* A basic smoke test.
*/
@Test
- fun smoke() {
+ fun testSmoke() {
val testScope = TestCoroutineScope()
val clock = DelayControllerClockAdapter(testScope)
testScope.launch {
- val image = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1000, 2)
-
- val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4)
- val cpus = List(4) { ProcessingUnit(cpuNode, it, 2400.0) }
- val driver = SimpleBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList())
+ val image = SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(1000, 2))
+ val driver = SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel)
val provisioner = SimpleProvisioningService()
provisioner.create(driver)
diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt
new file mode 100644
index 00000000..a0c61f29
--- /dev/null
+++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.compute.simulator
+
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertAll
+import org.opendc.compute.core.Flavor
+import org.opendc.compute.core.virt.HypervisorEvent
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.compute.workload.SimTraceWorkload
+import org.opendc.simulator.utils.DelayControllerClockAdapter
+import java.time.Clock
+import java.util.UUID
+
+/**
+ * Basic test-suite for the hypervisor.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+internal class SimVirtDriverTest {
+ private lateinit var scope: TestCoroutineScope
+ private lateinit var clock: Clock
+ private lateinit var machineModel: SimMachineModel
+
+ @BeforeEach
+ fun setUp() {
+ scope = TestCoroutineScope()
+ clock = DelayControllerClockAdapter(scope)
+
+ val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2)
+
+ machineModel = SimMachineModel(
+ cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) },
+ memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
+ )
+ }
+
+ /**
+ * Test overcommissioning of a hypervisor.
+ */
+ @Test
+ fun overcommission() {
+ var requestedBurst = 0L
+ var grantedBurst = 0L
+ var overcommissionedBurst = 0L
+
+ scope.launch {
+ val virtDriverWorkload = SimVirtDriverWorkload()
+ val vmm = SimWorkloadImage(UUID.randomUUID(), "vmm", emptyMap(), virtDriverWorkload)
+ val duration = 5 * 60L
+ val vmImageA = SimWorkloadImage(
+ UUID.randomUUID(),
+ "<unnamed>",
+ emptyMap(),
+ SimTraceWorkload(
+ sequenceOf(
+ SimTraceWorkload.Fragment(0, 28L * duration, duration * 1000, 28.0, 2),
+ SimTraceWorkload.Fragment(0, 3500L * duration, duration * 1000, 3500.0, 2),
+ SimTraceWorkload.Fragment(0, 0, duration * 1000, 0.0, 2),
+ SimTraceWorkload.Fragment(0, 183L * duration, duration * 1000, 183.0, 2)
+ ),
+ )
+ )
+ val vmImageB = SimWorkloadImage(
+ UUID.randomUUID(),
+ "<unnamed>",
+ emptyMap(),
+ SimTraceWorkload(
+ sequenceOf(
+ SimTraceWorkload.Fragment(0, 28L * duration, duration * 1000, 28.0, 2),
+ SimTraceWorkload.Fragment(0, 3100L * duration, duration * 1000, 3100.0, 2),
+ SimTraceWorkload.Fragment(0, 0, duration * 1000, 0.0, 2),
+ SimTraceWorkload.Fragment(0, 73L * duration, duration * 1000, 73.0, 2)
+ )
+ ),
+ )
+
+ val metalDriver =
+ SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel)
+
+ metalDriver.init()
+ metalDriver.setImage(vmm)
+ metalDriver.start()
+
+ delay(5)
+
+ val flavor = Flavor(2, 0)
+ val vmDriver = virtDriverWorkload.driver
+ vmDriver.events
+ .onEach { event ->
+ when (event) {
+ is HypervisorEvent.SliceFinished -> {
+ requestedBurst += event.requestedBurst
+ grantedBurst += event.grantedBurst
+ overcommissionedBurst += event.overcommissionedBurst
+ }
+ }
+ }
+ .launchIn(this)
+
+ vmDriver.spawn("a", vmImageA, flavor)
+ vmDriver.spawn("b", vmImageB, flavor)
+ }
+
+ scope.advanceUntilIdle()
+
+ assertAll(
+ { assertEquals(emptyList<Throwable>(), scope.uncaughtExceptions, "No errors") },
+ { assertEquals(2073600, requestedBurst, "Requested Burst does not match") },
+ { assertEquals(2013600, grantedBurst, "Granted Burst does not match") },
+ { assertEquals(60000, overcommissionedBurst, "Overcommissioned Burst does not match") },
+ { assertEquals(1200007, scope.currentTime) }
+ )
+ }
+}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ShutdownException.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ShutdownException.kt
deleted file mode 100644
index d751fb5e..00000000
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ShutdownException.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.compute.core.execution
-
-import kotlinx.coroutines.CancellationException
-
-/**
- * This exception is thrown by the underlying [ServerContext] to indicate that a shutdown flow
- * has been sent to the server.
- */
-public class ShutdownException(message: String? = null, override val cause: Throwable? = null) :
- CancellationException(message)
-
-/**
- * This method terminates the current active coroutine if the specified [CancellationException] is caused
- * by a shutdown.
- */
-public fun CancellationException.assertShutdown() {
- if (this is ShutdownException) {
- throw this
- }
-}
-
-/**
- * This method terminates the current active coroutine if the specified [CancellationException] is caused
- * by a failure.
- */
-public fun CancellationException.assertFailure() {
- if (this is ShutdownException && cause != null) {
- throw this
- }
-}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/FlopsHistoryFragment.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/FlopsHistoryFragment.kt
deleted file mode 100644
index 5472e4e0..00000000
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/FlopsHistoryFragment.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package org.opendc.compute.core.image
-
-public data class FlopsHistoryFragment(val tick: Long, val flops: Long, val duration: Long, val usage: Double, val cores: Int)
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt
deleted file mode 100644
index 817528f6..00000000
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/metal/driver/SimpleBareMetalDriver.kt
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * 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.compute.metal.driver
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Delay
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.FlowPreview
-import kotlinx.coroutines.InternalCoroutinesApi
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.intrinsics.startCoroutineCancellable
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.selects.SelectClause0
-import kotlinx.coroutines.selects.SelectInstance
-import org.opendc.compute.core.Flavor
-import org.opendc.compute.core.MemoryUnit
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.core.Server
-import org.opendc.compute.core.ServerEvent
-import org.opendc.compute.core.ServerState
-import org.opendc.compute.core.execution.ServerContext
-import org.opendc.compute.core.execution.ServerManagementContext
-import org.opendc.compute.core.execution.ShutdownException
-import org.opendc.compute.core.image.EmptyImage
-import org.opendc.compute.core.image.Image
-import org.opendc.compute.metal.Node
-import org.opendc.compute.metal.NodeEvent
-import org.opendc.compute.metal.NodeState
-import org.opendc.compute.metal.power.ConstantPowerModel
-import org.opendc.core.power.PowerModel
-import org.opendc.core.services.ServiceKey
-import org.opendc.core.services.ServiceRegistry
-import org.opendc.utils.flow.EventFlow
-import org.opendc.utils.flow.StateFlow
-import java.lang.Exception
-import java.time.Clock
-import java.util.UUID
-import kotlin.coroutines.ContinuationInterceptor
-import kotlin.math.ceil
-import kotlin.math.max
-import kotlin.math.min
-import kotlin.random.Random
-
-/**
- * A basic implementation of the [BareMetalDriver] that simulates an [Image] running on a bare-metal machine.
- *
- * @param coroutineScope The [CoroutineScope] the driver runs in.
- * @param clock The virtual clock to keep track of time.
- * @param uid The unique identifier of the machine.
- * @param name An optional name of the machine.
- * @param metadata The initial metadata of the node.
- * @param cpus The CPUs available to the bare metal machine.
- * @param memoryUnits The memory units in this machine.
- * @param powerModel The power model of this machine.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-public class SimpleBareMetalDriver(
- private val coroutineScope: CoroutineScope,
- private val clock: Clock,
- uid: UUID,
- name: String,
- metadata: Map<String, Any>,
- private val cpus: List<ProcessingUnit>,
- private val memoryUnits: List<MemoryUnit>,
- powerModel: PowerModel<SimpleBareMetalDriver> = ConstantPowerModel(
- 0.0
- )
-) : BareMetalDriver {
- /**
- * The flavor that corresponds to this machine.
- */
- private val flavor = Flavor(cpus.size, memoryUnits.map { it.size }.sum())
-
- /**
- * The current active server context.
- */
- private var serverContext: BareMetalServerContext? = null
-
- /**
- * The events of the machine.
- */
- private val events = EventFlow<NodeEvent>()
-
- /**
- * The flow containing the load of the server.
- */
- private val usageState = MutableStateFlow(0.0)
-
- /**
- * The machine state.
- */
- private val nodeState =
- StateFlow(Node(uid, name, metadata + ("driver" to this), NodeState.SHUTOFF, EmptyImage, null, events))
-
- override val node: Flow<Node> = nodeState
-
- @OptIn(FlowPreview::class)
- override val usage: Flow<Double> = usageState
-
- override val powerDraw: Flow<Double> = powerModel(this)
-
- /**
- * The internal random instance.
- */
- private val random = Random(uid.leastSignificantBits xor uid.mostSignificantBits)
-
- override suspend fun init(): Node {
- return nodeState.value
- }
-
- override suspend fun start(): Node {
- val node = nodeState.value
- if (node.state != NodeState.SHUTOFF) {
- return node
- }
-
- val events = EventFlow<ServerEvent>()
- val server = Server(
- UUID(random.nextLong(), random.nextLong()),
- node.name,
- emptyMap(),
- flavor,
- node.image,
- ServerState.BUILD,
- ServiceRegistry().put(BareMetalDriver, this@SimpleBareMetalDriver),
- events
- )
-
- setNode(node.copy(state = NodeState.BOOT, server = server))
- serverContext = BareMetalServerContext(events)
- return nodeState.value
- }
-
- override suspend fun stop(): Node {
- val node = nodeState.value
- if (node.state == NodeState.SHUTOFF) {
- return node
- }
-
- // We terminate the image running on the machine
- serverContext!!.cancel(fail = false)
- serverContext = null
-
- setNode(node.copy(state = NodeState.SHUTOFF, server = null))
- return node
- }
-
- override suspend fun reboot(): Node {
- stop()
- return start()
- }
-
- override suspend fun setImage(image: Image): Node {
- setNode(nodeState.value.copy(image = image))
- return nodeState.value
- }
-
- override suspend fun refresh(): Node = nodeState.value
-
- private fun setNode(value: Node) {
- val field = nodeState.value
- if (field.state != value.state) {
- events.emit(NodeEvent.StateChanged(value, field.state))
- }
-
- if (field.server != null && value.server != null && field.server.state != value.server.state) {
- serverContext!!.events.emit(ServerEvent.StateChanged(value.server, field.server.state))
- }
-
- nodeState.value = value
- }
-
- private inner class BareMetalServerContext(val events: EventFlow<ServerEvent>) : ServerManagementContext {
- private var finalized: Boolean = false
-
- // A state in which the machine is still available, but does not run any of the work requested by the
- // image
- var unavailable = false
-
- override val cpus: List<ProcessingUnit> = this@SimpleBareMetalDriver.cpus
-
- override val server: Server
- get() = nodeState.value.server!!
-
- override val clock: Clock
- get() = this@SimpleBareMetalDriver.clock
-
- private val job = coroutineScope.launch {
- delay(1) // TODO Introduce boot time
- init()
- try {
- server.image(this@BareMetalServerContext)
- exit()
- } catch (cause: Throwable) {
- exit(cause)
- }
- }
-
- /**
- * Cancel the image running on the machine.
- */
- suspend fun cancel(fail: Boolean) {
- if (fail)
- job.cancel(ShutdownException(cause = Exception("Random failure")))
- else
- job.cancel(ShutdownException())
- job.join()
- }
-
- override suspend fun <T : Any> publishService(key: ServiceKey<T>, service: T) {
- val server = server.copy(services = server.services.put(key, service))
- setNode(nodeState.value.copy(server = server))
- events.emit(ServerEvent.ServicePublished(server, key))
- }
-
- override suspend fun init() {
- assert(!finalized) { "Machine is already finalized" }
-
- val server = server.copy(state = ServerState.ACTIVE)
- setNode(nodeState.value.copy(state = NodeState.ACTIVE, server = server))
- }
-
- override suspend fun exit(cause: Throwable?) {
- finalized = true
-
- val newServerState =
- if (cause == null || (cause is ShutdownException && cause.cause == null))
- ServerState.SHUTOFF
- else
- ServerState.ERROR
- val newNodeState =
- if (cause == null || (cause is ShutdownException && cause.cause != null))
- nodeState.value.state
- else
- NodeState.ERROR
- val server = server.copy(state = newServerState)
- setNode(nodeState.value.copy(state = newNodeState, server = server))
- }
-
- /**
- * A disposable to prevent resetting the usage state for subsequent calls to onRun.
- */
- private var usageFlush: DisposableHandle? = null
-
- /**
- * Cache the [Delay] instance for timing.
- *
- * XXX We need to cache this before the call to [onRun] since doing this in [onRun] is too heavy.
- * XXX Note however that this is an ugly hack which may break in the future.
- */
- @OptIn(InternalCoroutinesApi::class)
- private val delay = coroutineScope.coroutineContext[ContinuationInterceptor] as Delay
-
- @OptIn(InternalCoroutinesApi::class)
- override fun onRun(
- batch: Sequence<ServerContext.Slice>,
- triggerMode: ServerContext.TriggerMode,
- merge: (ServerContext.Slice, ServerContext.Slice) -> ServerContext.Slice
- ): SelectClause0 {
- assert(!finalized) { "Server instance is already finalized" }
-
- return object : SelectClause0 {
- @InternalCoroutinesApi
- override fun <R> registerSelectClause0(select: SelectInstance<R>, block: suspend () -> R) {
- // Do not reset the usage state: we will set it ourselves
- usageFlush?.dispose()
- usageFlush = null
-
- val queue = batch.iterator()
- var start = Long.MIN_VALUE
- var currentWork: SliceWork? = null
- var currentDisposable: DisposableHandle? = null
-
- fun schedule(slice: ServerContext.Slice) {
- start = clock.millis()
-
- val isLastSlice = !queue.hasNext()
- val work = SliceWork(slice)
- val candidateDuration = when (triggerMode) {
- ServerContext.TriggerMode.FIRST -> work.minExit
- ServerContext.TriggerMode.LAST -> work.maxExit
- ServerContext.TriggerMode.DEADLINE -> slice.deadline - start
- }
-
- // Check whether the deadline is exceeded during the run of the slice.
- val duration = min(candidateDuration, slice.deadline - start)
-
- val action = Runnable {
- currentWork = null
-
- // Flush all the work that was performed
- val hasFinished = work.stop(duration)
-
- if (!isLastSlice) {
- val candidateSlice = queue.next()
- val nextSlice =
- // If our previous slice exceeds its deadline, merge it with the next candidate slice
- if (hasFinished)
- candidateSlice
- else
- merge(candidateSlice, slice)
- schedule(nextSlice)
- } else if (select.trySelect()) {
- block.startCoroutineCancellable(select.completion)
- }
- }
-
- // Schedule the flush after the entire slice has finished
- currentDisposable = delay.invokeOnTimeout(duration, action)
-
- // Start the slice work
- currentWork = work
- work.start()
- }
-
- // Schedule the first work
- if (queue.hasNext()) {
- schedule(queue.next())
-
- // A DisposableHandle to flush the work in case the call is cancelled
- val disposable = DisposableHandle {
- val end = clock.millis()
- val duration = end - start
-
- currentWork?.stop(duration)
- currentDisposable?.dispose()
-
- // Schedule reset the usage of the machine since the call is returning
- usageFlush = delay.invokeOnTimeout(1) {
- usageState.value = 0.0
- usageFlush = null
- }
- }
-
- select.disposeOnSelect(disposable)
- } else if (select.trySelect()) {
- // No work has been given: select immediately
- block.startCoroutineCancellable(select.completion)
- }
- }
- }
- }
-
- /**
- * A slice to be processed.
- */
- private inner class SliceWork(val slice: ServerContext.Slice) {
- /**
- * The duration after which the first processor finishes processing this slice.
- */
- public val minExit: Long
-
- /**
- * The duration after which the last processor finishes processing this slice.
- */
- public val maxExit: Long
-
- /**
- * A flag to indicate that the slice will exceed the deadline.
- */
- public val exceedsDeadline: Boolean
- get() = slice.deadline < maxExit
-
- /**
- * The total amount of CPU usage.
- */
- public val totalUsage: Double
-
- /**
- * A flag to indicate that this slice is empty.
- */
- public val isEmpty: Boolean
-
- init {
- var totalUsage = 0.0
- var minExit = Long.MAX_VALUE
- var maxExit = 0L
- var nonEmpty = false
-
- // Determine the duration of the first/last CPU to finish
- for (i in 0 until min(cpus.size, slice.burst.size)) {
- val cpu = cpus[i]
- val usage = min(slice.limit[i], cpu.frequency)
- val cpuDuration =
- ceil(slice.burst[i] / usage * 1000).toLong() // Convert from seconds to milliseconds
-
- totalUsage += usage / cpu.frequency
-
- if (cpuDuration != 0L) { // We only wait for processor cores with a non-zero burst
- minExit = min(minExit, cpuDuration)
- maxExit = max(maxExit, cpuDuration)
- nonEmpty = true
- }
- }
-
- this.isEmpty = !nonEmpty
- this.totalUsage = totalUsage
- this.minExit = minExit
- this.maxExit = maxExit
- }
-
- /**
- * Indicate that the work on the slice has started.
- */
- public fun start() {
- usageState.value = totalUsage / cpus.size
- }
-
- /**
- * Flush the work performed on the slice.
- */
- public fun stop(duration: Long): Boolean {
- var hasFinished = true
-
- // Only flush the work if the machine is available
- if (!unavailable) {
- for (i in 0 until min(cpus.size, slice.burst.size)) {
- val usage = min(slice.limit[i], cpus[i].frequency)
- val granted = ceil(duration / 1000.0 * usage).toLong()
- val res = max(0, slice.burst[i] - granted)
- slice.burst[i] = res
-
- if (res != 0L) {
- hasFinished = false
- }
- }
- }
-
- return hasFinished
- }
- }
- }
-
- override val scope: CoroutineScope
- get() = coroutineScope
-
- override suspend fun fail() {
- serverContext?.unavailable = true
-
- val server = nodeState.value.server?.copy(state = ServerState.ERROR)
- setNode(nodeState.value.copy(state = NodeState.ERROR, server = server))
- }
-
- override suspend fun recover() {
- serverContext?.unavailable = false
-
- val server = nodeState.value.server?.copy(state = ServerState.ACTIVE)
- setNode(nodeState.value.copy(state = NodeState.ACTIVE, server = server))
- }
-
- override fun toString(): String = "SimpleBareMetalDriver(node = ${nodeState.value.uid})"
-}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/HypervisorImage.kt b/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/HypervisorImage.kt
deleted file mode 100644
index ff88f0dc..00000000
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/HypervisorImage.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.compute.virt
-
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.suspendCancellableCoroutine
-import org.opendc.compute.core.execution.ServerContext
-import org.opendc.compute.core.image.Image
-import org.opendc.compute.virt.driver.SimpleVirtDriver
-import org.opendc.compute.virt.driver.VirtDriver
-import org.opendc.core.resource.TagContainer
-import java.util.UUID
-
-/**
- * A hypervisor managing the VMs of a node.
- */
-public object HypervisorImage : Image {
- override val uid: UUID = UUID.randomUUID()
- override val name: String = "vmm"
- override val tags: TagContainer = emptyMap()
-
- override suspend fun invoke(ctx: ServerContext) {
- coroutineScope {
- val driver = SimpleVirtDriver(ctx, this)
- ctx.publishService(VirtDriver.Key, driver)
-
- // Suspend image until it is cancelled
- try {
- suspendCancellableCoroutine<Unit> {}
- } finally {
- driver.cancel()
- }
- }
- }
-}
diff --git a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/virt/HypervisorTest.kt b/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/virt/HypervisorTest.kt
deleted file mode 100644
index 68efb1a3..00000000
--- a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/virt/HypervisorTest.kt
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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.compute.virt
-
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestCoroutineScope
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Disabled
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertAll
-import org.opendc.compute.core.Flavor
-import org.opendc.compute.core.ProcessingNode
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.core.image.FlopsApplicationImage
-import org.opendc.compute.core.image.FlopsHistoryFragment
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.metal.driver.SimpleBareMetalDriver
-import org.opendc.compute.virt.driver.VirtDriver
-import org.opendc.simulator.utils.DelayControllerClockAdapter
-import java.util.UUID
-
-/**
- * Basic test-suite for the hypervisor.
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-internal class HypervisorTest {
- /**
- * A smoke test for the bare-metal driver.
- */
- @OptIn(ExperimentalCoroutinesApi::class)
- @Test
- @Disabled
- fun smoke() {
- val testScope = TestCoroutineScope()
- val clock = DelayControllerClockAdapter(testScope)
-
- testScope.launch {
- val vmm = HypervisorImage
- val workloadA = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1_000, 1)
- val workloadB = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 2_000, 1)
-
- val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1)
- val cpus = List(1) { ProcessingUnit(cpuNode, it, 2000.0) }
- val metalDriver =
- SimpleBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList())
-
- metalDriver.init()
- metalDriver.setImage(vmm)
- val node = metalDriver.start()
- node.server?.events?.onEach { println(it) }?.launchIn(this)
-
- delay(5)
-
- val flavor = Flavor(1, 0)
- val vmDriver = metalDriver.refresh().server!!.services[VirtDriver]
- vmDriver.events.onEach { println(it) }.launchIn(this)
- val vmA = vmDriver.spawn("a", workloadA, flavor)
- vmA.events.onEach { println(it) }.launchIn(this)
- val vmB = vmDriver.spawn("b", workloadB, flavor)
- vmB.events.onEach { println(it) }.launchIn(this)
- }
-
- testScope.advanceUntilIdle()
- }
-
- /**
- * Test overcommissioning of a hypervisor.
- */
- @Test
- fun overcommission() {
- val testScope = TestCoroutineScope()
- val clock = DelayControllerClockAdapter(testScope)
-
- var requestedBurst = 0L
- var grantedBurst = 0L
- var overcommissionedBurst = 0L
-
- testScope.launch {
- val vmm = HypervisorImage
- val duration = 5 * 60L
- val vmImageA = VmImage(
- UUID.randomUUID(),
- "<unnamed>",
- emptyMap(),
- sequenceOf(
- FlopsHistoryFragment(0, 28L * duration, duration * 1000, 28.0, 2),
- FlopsHistoryFragment(0, 3500L * duration, duration * 1000, 3500.0, 2),
- FlopsHistoryFragment(0, 0, duration * 1000, 0.0, 2),
- FlopsHistoryFragment(0, 183L * duration, duration * 1000, 183.0, 2)
- ),
- 2,
- 0
- )
- val vmImageB = VmImage(
- UUID.randomUUID(),
- "<unnamed>",
- emptyMap(),
- sequenceOf(
- FlopsHistoryFragment(0, 28L * duration, duration * 1000, 28.0, 2),
- FlopsHistoryFragment(0, 3100L * duration, duration * 1000, 3100.0, 2),
- FlopsHistoryFragment(0, 0, duration * 1000, 0.0, 2),
- FlopsHistoryFragment(0, 73L * duration, duration * 1000, 73.0, 2)
- ),
- 2,
- 0
- )
-
- val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2)
- val cpus = List(2) { ProcessingUnit(cpuNode, it, 3200.0) }
- val metalDriver =
- SimpleBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList())
-
- metalDriver.init()
- metalDriver.setImage(vmm)
- metalDriver.start()
-
- delay(5)
-
- val flavor = Flavor(2, 0)
- val vmDriver = metalDriver.refresh().server!!.services[VirtDriver]
- vmDriver.events
- .onEach { event ->
- when (event) {
- is HypervisorEvent.SliceFinished -> {
- requestedBurst += event.requestedBurst
- grantedBurst += event.grantedBurst
- overcommissionedBurst += event.overcommissionedBurst
- }
- }
- }
- .launchIn(this)
-
- vmDriver.spawn("a", vmImageA, flavor)
- vmDriver.spawn("b", vmImageB, flavor)
- }
-
- testScope.advanceUntilIdle()
-
- assertAll(
- { assertEquals(2073600, requestedBurst, "Requested Burst does not match") },
- { assertEquals(2013600, grantedBurst, "Granted Burst does not match") },
- { assertEquals(60000, overcommissionedBurst, "Overcommissioned Burst does not match") }
- )
- }
-}
diff --git a/simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts b/simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts
index 393fd0d0..9cf72f18 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts
+++ b/simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts
@@ -36,8 +36,11 @@ dependencies {
api(project(":opendc-core"))
implementation(project(":opendc-format"))
implementation(project(":opendc-workflows"))
- implementation(project(":opendc-simulator"))
- implementation(kotlin("stdlib"))
+ implementation(project(":opendc-simulator:opendc-simulator-core"))
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8") {
+ exclude("org.jetbrains.kotlin", module = "kotlin-reflect")
+ }
+ implementation(kotlin("reflect"))
testImplementation("org.junit.jupiter:junit-jupiter-api:${Library.JUNIT_JUPITER}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Library.JUNIT_JUPITER}")
diff --git a/simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt b/simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt
index 4aef5be3..3786eebf 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt
@@ -27,7 +27,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestCoroutineScope
-import org.opendc.compute.metal.service.ProvisioningService
+import org.opendc.compute.core.metal.service.ProvisioningService
import org.opendc.format.environment.sc18.Sc18EnvironmentReader
import org.opendc.format.trace.gwf.GwfTraceReader
import org.opendc.simulator.utils.DelayControllerClockAdapter
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts b/simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts
index 4bfe21d2..3b682668 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts
@@ -36,7 +36,10 @@ application {
dependencies {
api(project(":opendc-core"))
implementation(project(":opendc-format"))
- implementation(project(":opendc-simulator"))
+ implementation(project(":opendc-simulator:opendc-simulator-core"))
+ implementation(project(":opendc-simulator:opendc-simulator-compute"))
+ implementation(project(":opendc-simulator:opendc-simulator-failures"))
+ implementation(project(":opendc-compute:opendc-compute-simulator"))
implementation("com.github.ajalt:clikt:2.6.0")
implementation("me.tongfei:progressbar:0.8.1")
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.kt
index b7bb0c23..8916261b 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.kt
@@ -41,7 +41,6 @@ import org.opendc.experiments.sc20.runner.internal.DefaultExperimentRunner
import org.opendc.format.trace.sc20.Sc20PerformanceInterferenceReader
import org.opendc.format.trace.sc20.Sc20VmPlacementReader
import java.io.File
-import java.io.InputStream
/**
* The logger for this experiment.
@@ -74,7 +73,7 @@ public class ExperimentCli : CliktCommand(name = "sc20-experiment") {
help = "path to the performance interference file"
)
.file(canBeDir = false)
- .convert { it.inputStream() as InputStream }
+ .convert { it.inputStream() }
/**
* The path to the original VM placements file.
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt
index 97d7d5da..09f44199 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt
@@ -34,23 +34,24 @@ import kotlinx.coroutines.launch
import mu.KotlinLogging
import org.opendc.compute.core.Flavor
import org.opendc.compute.core.ServerEvent
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
+import org.opendc.compute.core.metal.NODE_CLUSTER
+import org.opendc.compute.core.metal.driver.BareMetalDriver
+import org.opendc.compute.core.metal.service.ProvisioningService
+import org.opendc.compute.core.virt.HypervisorEvent
+import org.opendc.compute.core.virt.service.VirtProvisioningEvent
import org.opendc.compute.core.workload.VmWorkload
-import org.opendc.compute.metal.NODE_CLUSTER
-import org.opendc.compute.metal.driver.BareMetalDriver
-import org.opendc.compute.metal.service.ProvisioningService
-import org.opendc.compute.virt.HypervisorEvent
-import org.opendc.compute.virt.driver.SimpleVirtDriver
-import org.opendc.compute.virt.service.SimpleVirtProvisioningService
-import org.opendc.compute.virt.service.VirtProvisioningEvent
-import org.opendc.compute.virt.service.allocation.AllocationPolicy
-import org.opendc.core.failure.CorrelatedFaultInjector
-import org.opendc.core.failure.FailureDomain
-import org.opendc.core.failure.FaultInjector
+import org.opendc.compute.simulator.SimBareMetalDriver
+import org.opendc.compute.simulator.SimVirtDriver
+import org.opendc.compute.simulator.SimVirtProvisioningService
+import org.opendc.compute.simulator.allocation.AllocationPolicy
import org.opendc.experiments.sc20.experiment.monitor.ExperimentMonitor
import org.opendc.experiments.sc20.trace.Sc20StreamingParquetTraceReader
import org.opendc.format.environment.EnvironmentReader
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+import org.opendc.simulator.failures.CorrelatedFaultInjector
+import org.opendc.simulator.failures.FailureDomain
+import org.opendc.simulator.failures.FaultInjector
import java.io.File
import java.time.Clock
import kotlin.math.ln
@@ -140,14 +141,14 @@ public suspend fun createProvisioner(
clock: Clock,
environmentReader: EnvironmentReader,
allocationPolicy: AllocationPolicy
-): Pair<ProvisioningService, SimpleVirtProvisioningService> {
+): Pair<ProvisioningService, SimVirtProvisioningService> {
val environment = environmentReader.use { it.construct(coroutineScope, clock) }
val bareMetalProvisioner = environment.platforms[0].zones[0].services[ProvisioningService]
// Wait for the bare metal nodes to be spawned
delay(10)
- val scheduler = SimpleVirtProvisioningService(coroutineScope, clock, bareMetalProvisioner, allocationPolicy)
+ val scheduler = SimVirtProvisioningService(coroutineScope, clock, bareMetalProvisioner, allocationPolicy)
// Wait for the hypervisors to be spawned
delay(10)
@@ -162,7 +163,7 @@ public suspend fun createProvisioner(
public suspend fun attachMonitor(
coroutineScope: CoroutineScope,
clock: Clock,
- scheduler: SimpleVirtProvisioningService,
+ scheduler: SimVirtProvisioningService,
monitor: ExperimentMonitor
) {
@@ -171,8 +172,9 @@ public suspend fun attachMonitor(
// Monitor hypervisor events
for (hypervisor in hypervisors) {
// TODO Do not expose VirtDriver directly but use Hypervisor class.
- monitor.reportHostStateChange(clock.millis(), hypervisor, (hypervisor as SimpleVirtDriver).server)
- hypervisor.server.events
+ val server = (hypervisor as SimVirtDriver).server
+ monitor.reportHostStateChange(clock.millis(), hypervisor, server)
+ server.events
.onEach { event ->
val time = clock.millis()
when (event) {
@@ -200,7 +202,7 @@ public suspend fun attachMonitor(
}
.launchIn(coroutineScope)
- val driver = hypervisor.server.services[BareMetalDriver.Key]
+ val driver = hypervisor.server.services[BareMetalDriver.Key] as SimBareMetalDriver
driver.powerDraw
.onEach { monitor.reportPowerConsumption(hypervisor.server, it) }
.launchIn(coroutineScope)
@@ -223,10 +225,9 @@ public suspend fun processTrace(
coroutineScope: CoroutineScope,
clock: Clock,
reader: TraceReader<VmWorkload>,
- scheduler: SimpleVirtProvisioningService,
+ scheduler: SimVirtProvisioningService,
chan: Channel<Unit>,
- monitor: ExperimentMonitor,
- vmPlacements: Map<String, String> = emptyMap()
+ monitor: ExperimentMonitor
) {
try {
var submitted = 0
@@ -242,8 +243,8 @@ public suspend fun processTrace(
workload.image.name,
workload.image,
Flavor(
- workload.image.maxCores,
- workload.image.requiredMemory
+ workload.image.tags["cores"] as Int,
+ workload.image.tags["required-memory"] as Long
)
)
// Monitor server events
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.kt
index 95987d07..660fc882 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.kt
@@ -28,7 +28,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScope
import mu.KotlinLogging
-import org.opendc.compute.virt.service.allocation.*
+import org.opendc.compute.simulator.allocation.*
import org.opendc.experiments.sc20.experiment.model.CompositeWorkload
import org.opendc.experiments.sc20.experiment.monitor.ParquetExperimentMonitor
import org.opendc.experiments.sc20.runner.TrialExperimentDescriptor
@@ -131,8 +131,7 @@ public data class Run(override val parent: Scenario, val id: Int, val seed: Int)
trace,
scheduler,
chan,
- monitor,
- experiment.vmPlacements
+ monitor
)
logger.debug("SUBMIT=${scheduler.submittedVms}")
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ExperimentMonitor.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ExperimentMonitor.kt
index 0ac532a4..18ba2c33 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ExperimentMonitor.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ExperimentMonitor.kt
@@ -23,8 +23,8 @@
package org.opendc.experiments.sc20.experiment.monitor
import org.opendc.compute.core.Server
-import org.opendc.compute.virt.driver.VirtDriver
-import org.opendc.compute.virt.service.VirtProvisioningEvent
+import org.opendc.compute.core.virt.driver.VirtDriver
+import org.opendc.compute.core.virt.service.VirtProvisioningEvent
import java.io.Closeable
/**
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ParquetExperimentMonitor.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ParquetExperimentMonitor.kt
index bb512ef7..3eb9362c 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ParquetExperimentMonitor.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ParquetExperimentMonitor.kt
@@ -24,8 +24,8 @@ package org.opendc.experiments.sc20.experiment.monitor
import mu.KotlinLogging
import org.opendc.compute.core.Server
-import org.opendc.compute.virt.driver.VirtDriver
-import org.opendc.compute.virt.service.VirtProvisioningEvent
+import org.opendc.compute.core.virt.driver.VirtDriver
+import org.opendc.compute.core.virt.service.VirtProvisioningEvent
import org.opendc.experiments.sc20.telemetry.HostEvent
import org.opendc.experiments.sc20.telemetry.ProvisionerEvent
import org.opendc.experiments.sc20.telemetry.parquet.ParquetHostEventWriter
@@ -57,7 +57,7 @@ public class ParquetExperimentMonitor(base: File, partition: String, bufferSize:
startTime = time
// Update timestamp of initial event
- currentHostEvent.replaceAll { k, v -> v.copy(timestamp = startTime) }
+ currentHostEvent.replaceAll { _, v -> v.copy(timestamp = startTime) }
}
}
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt
index 5a336865..d735ea4b 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt
@@ -22,14 +22,14 @@
package org.opendc.experiments.sc20.trace
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
import org.opendc.compute.core.workload.VmWorkload
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.experiments.sc20.experiment.model.CompositeWorkload
import org.opendc.experiments.sc20.experiment.model.Workload
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
import java.util.TreeSet
/**
@@ -73,13 +73,11 @@ public class Sc20ParquetTraceReader(
performanceInterferenceModel[id] ?: PerformanceInterferenceModel(TreeSet())
val newImage =
- VmImage(
+ SimWorkloadImage(
image.uid,
image.name,
- mapOf(IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems),
- image.flopsHistory,
- image.maxCores,
- image.requiredMemory
+ image.tags + mapOf(IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems),
+ (image as SimWorkloadImage).workload
)
val newWorkload = entry.workload.copy(image = newImage)
Sc20RawParquetTraceReader.TraceEntryImpl(entry.submissionTime, newWorkload)
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt
index 8965cf43..9bc1a58e 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt
@@ -26,12 +26,12 @@ import mu.KotlinLogging
import org.apache.avro.generic.GenericData
import org.apache.hadoop.fs.Path
import org.apache.parquet.avro.AvroParquetReader
-import org.opendc.compute.core.image.FlopsHistoryFragment
-import org.opendc.compute.core.image.VmImage
import org.opendc.compute.core.workload.VmWorkload
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.core.User
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.workload.SimTraceWorkload
import java.io.File
import java.util.UUID
@@ -47,12 +47,12 @@ public class Sc20RawParquetTraceReader(private val path: File) {
/**
* Read the fragments into memory.
*/
- private fun parseFragments(path: File): Map<String, List<FlopsHistoryFragment>> {
+ private fun parseFragments(path: File): Map<String, List<SimTraceWorkload.Fragment>> {
val reader = AvroParquetReader.builder<GenericData.Record>(Path(path.absolutePath, "trace.parquet"))
.disableCompatibility()
.build()
- val fragments = mutableMapOf<String, MutableList<FlopsHistoryFragment>>()
+ val fragments = mutableMapOf<String, MutableList<SimTraceWorkload.Fragment>>()
return try {
while (true) {
@@ -65,7 +65,7 @@ public class Sc20RawParquetTraceReader(private val path: File) {
val cpuUsage = record["cpuUsage"] as Double
val flops = record["flops"] as Long
- val fragment = FlopsHistoryFragment(
+ val fragment = SimTraceWorkload.Fragment(
tick,
flops,
duration,
@@ -85,7 +85,7 @@ public class Sc20RawParquetTraceReader(private val path: File) {
/**
* Read the metadata into a workload.
*/
- private fun parseMeta(path: File, fragments: Map<String, List<FlopsHistoryFragment>>): List<TraceEntryImpl> {
+ private fun parseMeta(path: File, fragments: Map<String, List<SimTraceWorkload.Fragment>>): List<TraceEntryImpl> {
val metaReader = AvroParquetReader.builder<GenericData.Record>(Path(path.absolutePath, "meta.parquet"))
.disableCompatibility()
.build()
@@ -114,17 +114,17 @@ public class Sc20RawParquetTraceReader(private val path: File) {
uid,
id,
UnnamedUser,
- VmImage(
+ SimWorkloadImage(
uid,
id,
mapOf(
"submit-time" to submissionTime,
"end-time" to endTime,
- "total-load" to totalLoad
+ "total-load" to totalLoad,
+ "cores" to maxCores,
+ "required-memory" to requiredMemory
),
- vmFragments,
- maxCores,
- requiredMemory
+ SimTraceWorkload(vmFragments)
)
)
entries.add(TraceEntryImpl(submissionTime, vmWorkload))
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt
index 41dc4b49..edef276c 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt
@@ -31,14 +31,14 @@ import org.apache.parquet.filter2.predicate.FilterApi
import org.apache.parquet.filter2.predicate.Statistics
import org.apache.parquet.filter2.predicate.UserDefinedPredicate
import org.apache.parquet.io.api.Binary
-import org.opendc.compute.core.image.FlopsHistoryFragment
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
import org.opendc.compute.core.workload.VmWorkload
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.core.User
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+import org.opendc.simulator.compute.workload.SimTraceWorkload
import java.io.File
import java.io.Serializable
import java.util.SortedSet
@@ -71,7 +71,7 @@ public class Sc20StreamingParquetTraceReader(
/**
* The intermediate buffer to store the read records in.
*/
- private val queue = ArrayBlockingQueue<Pair<String, FlopsHistoryFragment>>(1024)
+ private val queue = ArrayBlockingQueue<Pair<String, SimTraceWorkload.Fragment>>(1024)
/**
* An optional filter for filtering the selected VMs
@@ -92,7 +92,7 @@ public class Sc20StreamingParquetTraceReader(
/**
* A poisonous fragment.
*/
- private val poison = Pair("\u0000", FlopsHistoryFragment(0, 0, 0, 0.0, 0))
+ private val poison = Pair("\u0000", SimTraceWorkload.Fragment(0, 0, 0, 0.0, 0))
/**
* The thread to read the records in.
@@ -119,7 +119,7 @@ public class Sc20StreamingParquetTraceReader(
val cpuUsage = record["cpuUsage"] as Double
val flops = record["flops"] as Long
- val fragment = FlopsHistoryFragment(
+ val fragment = SimTraceWorkload.Fragment(
tick,
flops,
duration,
@@ -139,12 +139,12 @@ public class Sc20StreamingParquetTraceReader(
/**
* Fill the buffers with the VMs
*/
- private fun pull(buffers: Map<String, List<MutableList<FlopsHistoryFragment>>>) {
+ private fun pull(buffers: Map<String, List<MutableList<SimTraceWorkload.Fragment>>>) {
if (!hasNext) {
return
}
- val fragments = mutableListOf<Pair<String, FlopsHistoryFragment>>()
+ val fragments = mutableListOf<Pair<String, SimTraceWorkload.Fragment>>()
queue.drainTo(fragments)
for ((id, fragment) in fragments) {
@@ -167,7 +167,7 @@ public class Sc20StreamingParquetTraceReader(
init {
val takenIds = mutableSetOf<UUID>()
val entries = mutableMapOf<String, GenericData.Record>()
- val buffers = mutableMapOf<String, MutableList<MutableList<FlopsHistoryFragment>>>()
+ val buffers = mutableMapOf<String, MutableList<MutableList<SimTraceWorkload.Fragment>>>()
val metaReader = AvroParquetReader.builder<GenericData.Record>(Path(traceFile.absolutePath, "meta.parquet"))
.disableCompatibility()
@@ -200,10 +200,10 @@ public class Sc20StreamingParquetTraceReader(
logger.info("Processing VM $id")
- val internalBuffer = mutableListOf<FlopsHistoryFragment>()
- val externalBuffer = mutableListOf<FlopsHistoryFragment>()
+ val internalBuffer = mutableListOf<SimTraceWorkload.Fragment>()
+ val externalBuffer = mutableListOf<SimTraceWorkload.Fragment>()
buffers.getOrPut(id) { mutableListOf() }.add(externalBuffer)
- val fragments = sequence<FlopsHistoryFragment> {
+ val fragments = sequence {
repeat@ while (true) {
if (externalBuffer.isEmpty()) {
if (hasNext) {
@@ -220,7 +220,7 @@ public class Sc20StreamingParquetTraceReader(
for (fragment in internalBuffer) {
yield(fragment)
- if (fragment.tick >= endTime) {
+ if (fragment.time >= endTime) {
break@repeat
}
}
@@ -239,13 +239,15 @@ public class Sc20StreamingParquetTraceReader(
uid,
"VM Workload $id",
UnnamedUser,
- VmImage(
+ SimWorkloadImage(
uid,
id,
- mapOf(IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems),
- fragments,
- maxCores,
- requiredMemory
+ mapOf(
+ IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems,
+ "cores" to maxCores,
+ "required-memory" to requiredMemory
+ ),
+ SimTraceWorkload(fragments),
)
)
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.kt
index dd6b15d0..bb2a75ee 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.kt
@@ -187,11 +187,11 @@ public class SolvinityConversion : TraceConversion("Solvinity") {
.filterNot { it.isDirectory }
.filter { it.extension == "csv" || it.extension == "txt" }
.toList()
- .forEach { vmFile ->
+ .forEach file@{ vmFile ->
BufferedReader(FileReader(vmFile)).use { reader ->
reader.lineSequence()
.chunked(128)
- .forEachIndexed { idx, lines ->
+ .forEach { lines ->
for (line in lines) {
// Ignore comments in the trace
if (line.startsWith("#") || line.isBlank()) {
@@ -212,7 +212,7 @@ public class SolvinityConversion : TraceConversion("Solvinity") {
if (timestamp < minTimestamp) {
minTimestamp = timestamp
}
- return@forEach
+ return@file
}
}
}
@@ -229,13 +229,13 @@ public class SolvinityConversion : TraceConversion("Solvinity") {
.filterNot { it.isDirectory }
.filter { it.extension == "csv" || it.extension == "txt" }
.toList()
- .forEachIndexed { idx, vmFile ->
+ .forEach { vmFile ->
println(vmFile)
var vmId = ""
var maxCores = -1
var requiredMemory = -1L
- var cores = -1
+ var cores: Int
var minTime = Long.MAX_VALUE
val flopsFragments = sequence {
@@ -353,13 +353,13 @@ public class BitbrainsConversion : TraceConversion("Bitbrains") {
.filterNot { it.isDirectory }
.filter { it.extension == "csv" || it.extension == "txt" }
.toList()
- .forEachIndexed { idx, vmFile ->
+ .forEach { vmFile ->
println(vmFile)
var vmId = ""
var maxCores = -1
var requiredMemory = -1L
- var cores = -1
+ var cores: Int
var minTime = Long.MAX_VALUE
val flopsFragments = sequence {
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.kt
index 19da97bb..a8b83aef 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.kt
@@ -23,8 +23,8 @@
package org.opendc.experiments.sc20.trace
import mu.KotlinLogging
-import org.opendc.compute.core.image.VmImage
import org.opendc.compute.core.workload.VmWorkload
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.experiments.sc20.experiment.model.CompositeWorkload
import org.opendc.experiments.sc20.experiment.model.SamplingStrategy
import org.opendc.experiments.sc20.experiment.model.Workload
@@ -143,7 +143,6 @@ public fun sampleHpcWorkload(
if (sampleOnLoad) {
var currentLoad = 0.0
- var i = 0
for (entry in hpcSequence) {
val entryLoad = entry.workload.image.tags.getValue("total-load") as Double
if ((currentLoad + entryLoad) / totalLoad > fraction) {
@@ -197,13 +196,11 @@ public fun sampleHpcWorkload(
*/
private fun sample(entry: TraceEntry<VmWorkload>, i: Int): TraceEntry<VmWorkload> {
val id = UUID.nameUUIDFromBytes("${entry.workload.image.uid}-$i".toByteArray())
- val image = VmImage(
+ val image = SimWorkloadImage(
id,
entry.workload.image.name,
entry.workload.image.tags,
- entry.workload.image.flopsHistory,
- entry.workload.image.maxCores,
- entry.workload.image.requiredMemory
+ (entry.workload.image as SimWorkloadImage).workload
)
val vmWorkload = entry.workload.copy(uid = id, image = image, name = entry.workload.name)
return VmTraceEntry(vmWorkload, entry.submissionTime)
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml
index 5ce99dfb..8029092e 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml
@@ -30,7 +30,7 @@
</Console>
</Appenders>
<Loggers>
- <Logger name="org.opendc" level="warn" additivity="false">
+ <Logger name="org.opendc" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.opendc.experiments.sc20" level="info" additivity="false">
diff --git a/simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.kt
index 230e7f36..9c44edfc 100644
--- a/simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.kt
+++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.kt
@@ -34,8 +34,8 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import org.opendc.compute.core.Server
import org.opendc.compute.core.workload.VmWorkload
-import org.opendc.compute.virt.service.SimpleVirtProvisioningService
-import org.opendc.compute.virt.service.allocation.AvailableCoreMemoryAllocationPolicy
+import org.opendc.compute.simulator.SimVirtProvisioningService
+import org.opendc.compute.simulator.allocation.AvailableCoreMemoryAllocationPolicy
import org.opendc.experiments.sc20.experiment.attachMonitor
import org.opendc.experiments.sc20.experiment.createFailureDomain
import org.opendc.experiments.sc20.experiment.createProvisioner
@@ -96,7 +96,7 @@ class Sc20IntegrationTest {
val allocationPolicy = AvailableCoreMemoryAllocationPolicy()
val traceReader = createTestTraceReader()
val environmentReader = createTestEnvironmentReader()
- lateinit var scheduler: SimpleVirtProvisioningService
+ lateinit var scheduler: SimVirtProvisioningService
testScope.launch {
val res = createProvisioner(
@@ -142,12 +142,14 @@ class Sc20IntegrationTest {
runSimulation()
// Note that these values have been verified beforehand
- assertEquals(50, scheduler.submittedVms, "The trace contains 50 VMs")
- assertEquals(50, scheduler.finishedVms, "All VMs should finish after a run")
- assertEquals(207379117949, monitor.totalRequestedBurst)
- assertEquals(203388071813, monitor.totalGrantedBurst)
- assertEquals(3991046136, monitor.totalOvercommissionedBurst)
- assertEquals(0, monitor.totalInterferedBurst)
+ assertAll(
+ { assertEquals(50, scheduler.submittedVms, "The trace contains 50 VMs") },
+ { assertEquals(50, scheduler.finishedVms, "All VMs should finish after a run") },
+ { assertEquals(207379117949, monitor.totalRequestedBurst) },
+ { assertEquals(203388071813, monitor.totalGrantedBurst) },
+ { assertEquals(3991046136, monitor.totalOvercommissionedBurst) },
+ { assertEquals(0, monitor.totalInterferedBurst) }
+ )
}
@Test
@@ -157,7 +159,7 @@ class Sc20IntegrationTest {
val allocationPolicy = AvailableCoreMemoryAllocationPolicy()
val traceReader = createTestTraceReader(0.5, seed)
val environmentReader = createTestEnvironmentReader("single")
- lateinit var scheduler: SimpleVirtProvisioningService
+ lateinit var scheduler: SimVirtProvisioningService
testScope.launch {
val res = createProvisioner(
diff --git a/simulator/opendc-format/build.gradle.kts b/simulator/opendc-format/build.gradle.kts
index 38fcb329..30aafc90 100644
--- a/simulator/opendc-format/build.gradle.kts
+++ b/simulator/opendc-format/build.gradle.kts
@@ -29,9 +29,11 @@ plugins {
dependencies {
api(project(":opendc-core"))
- api(project(":opendc-compute"))
+ api(project(":opendc-compute:opendc-compute-core"))
api(project(":opendc-workflows"))
- api("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8") {
+ implementation(project(":opendc-simulator:opendc-simulator-compute"))
+ implementation(project(":opendc-compute:opendc-compute-simulator"))
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8") {
exclude("org.jetbrains.kotlin", module = "kotlin-reflect")
}
implementation(kotlin("reflect"))
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt
index 027548a8..2e3e4a73 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt
@@ -26,17 +26,18 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import kotlinx.coroutines.CoroutineScope
-import org.opendc.compute.core.MemoryUnit
-import org.opendc.compute.core.ProcessingNode
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.metal.driver.SimpleBareMetalDriver
-import org.opendc.compute.metal.service.ProvisioningService
-import org.opendc.compute.metal.service.SimpleProvisioningService
+import org.opendc.compute.core.metal.service.ProvisioningService
+import org.opendc.compute.core.metal.service.SimpleProvisioningService
+import org.opendc.compute.simulator.SimBareMetalDriver
import org.opendc.core.Environment
import org.opendc.core.Platform
import org.opendc.core.Zone
import org.opendc.core.services.ServiceRegistry
import org.opendc.format.environment.EnvironmentReader
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
import java.io.InputStream
import java.time.Clock
import java.util.*
@@ -74,14 +75,13 @@ public class Sc18EnvironmentReader(input: InputStream, mapper: ObjectMapper = ja
else -> throw IllegalArgumentException("The cpu id $id is not recognized")
}
}
- SimpleBareMetalDriver(
+ SimBareMetalDriver(
coroutineScope,
clock,
UUID.randomUUID(),
"node-${counter++}",
emptyMap(),
- cores,
- listOf(MemoryUnit("", "", 2300.0, 16000))
+ SimMachineModel(cores, listOf(MemoryUnit("", "", 2300.0, 16000)))
)
}
}
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt
index 634d5de6..b4c71c4e 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt
@@ -23,19 +23,20 @@
package org.opendc.format.environment.sc20
import kotlinx.coroutines.CoroutineScope
-import org.opendc.compute.core.MemoryUnit
-import org.opendc.compute.core.ProcessingNode
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.metal.NODE_CLUSTER
-import org.opendc.compute.metal.driver.SimpleBareMetalDriver
-import org.opendc.compute.metal.power.LinearLoadPowerModel
-import org.opendc.compute.metal.service.ProvisioningService
-import org.opendc.compute.metal.service.SimpleProvisioningService
+import org.opendc.compute.core.metal.NODE_CLUSTER
+import org.opendc.compute.core.metal.service.ProvisioningService
+import org.opendc.compute.core.metal.service.SimpleProvisioningService
+import org.opendc.compute.simulator.SimBareMetalDriver
+import org.opendc.compute.simulator.power.LinearLoadPowerModel
import org.opendc.core.Environment
import org.opendc.core.Platform
import org.opendc.core.Zone
import org.opendc.core.services.ServiceRegistry
import org.opendc.format.environment.EnvironmentReader
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
@@ -68,7 +69,7 @@ public class Sc20ClusterEnvironmentReader(
var memoryPerHost: Long
var coresPerHost: Int
- val nodes = mutableListOf<SimpleBareMetalDriver>()
+ val nodes = mutableListOf<SimBareMetalDriver>()
val random = Random(0)
input.bufferedReader().use { reader ->
@@ -102,19 +103,21 @@ public class Sc20ClusterEnvironmentReader(
repeat(numberOfHosts) {
nodes.add(
- SimpleBareMetalDriver(
+ SimBareMetalDriver(
coroutineScope,
clock,
UUID(random.nextLong(), random.nextLong()),
"node-$clusterId-$it",
mapOf(NODE_CLUSTER to clusterId),
- List(coresPerHost) { coreId ->
- ProcessingUnit(unknownProcessingNode, coreId, speed)
- },
+ SimMachineModel(
+ List(coresPerHost) { coreId ->
+ ProcessingUnit(unknownProcessingNode, coreId, speed)
+ },
+ listOf(unknownMemoryUnit)
+ ),
// For now we assume a simple linear load model with an idle draw of ~200W and a maximum
// power draw of 350W.
// Source: https://stackoverflow.com/questions/6128960
- listOf(unknownMemoryUnit),
LinearLoadPowerModel(200.0, 350.0)
)
)
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt
index 9fd38d13..94237cb9 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt
@@ -26,18 +26,19 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import kotlinx.coroutines.CoroutineScope
-import org.opendc.compute.core.MemoryUnit
-import org.opendc.compute.core.ProcessingNode
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.metal.driver.SimpleBareMetalDriver
-import org.opendc.compute.metal.power.LinearLoadPowerModel
-import org.opendc.compute.metal.service.ProvisioningService
-import org.opendc.compute.metal.service.SimpleProvisioningService
+import org.opendc.compute.core.metal.service.ProvisioningService
+import org.opendc.compute.core.metal.service.SimpleProvisioningService
+import org.opendc.compute.simulator.SimBareMetalDriver
+import org.opendc.compute.simulator.power.LinearLoadPowerModel
import org.opendc.core.Environment
import org.opendc.core.Platform
import org.opendc.core.Zone
import org.opendc.core.services.ServiceRegistry
import org.opendc.format.environment.EnvironmentReader
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
import java.io.InputStream
import java.time.Clock
import java.util.*
@@ -80,17 +81,16 @@ public class Sc20EnvironmentReader(input: InputStream, mapper: ObjectMapper = ja
else -> throw IllegalArgumentException("The cpu id $id is not recognized")
}
}
- SimpleBareMetalDriver(
+ SimBareMetalDriver(
coroutineScope,
clock,
UUID.randomUUID(),
"node-${counter++}",
emptyMap(),
- cores,
+ SimMachineModel(cores, memories),
// For now we assume a simple linear load model with an idle draw of ~200W and a maximum
// power draw of 350W.
// Source: https://stackoverflow.com/questions/6128960
- memories,
LinearLoadPowerModel(200.0, 350.0)
)
}
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt
index 7f60cd90..f30e64cf 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt
@@ -22,7 +22,7 @@
package org.opendc.format.trace
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
import java.io.Closeable
import kotlin.random.Random
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt
index 89d4246d..9353ef28 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt
@@ -22,14 +22,14 @@
package org.opendc.format.trace.bitbrains
-import org.opendc.compute.core.image.FlopsHistoryFragment
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
import org.opendc.compute.core.workload.VmWorkload
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.core.User
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+import org.opendc.simulator.compute.workload.SimTraceWorkload
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
@@ -66,7 +66,7 @@ public class BitbrainsTraceReader(
.filterNot { it.isDirectory }
.forEach { vmFile ->
println(vmFile)
- val flopsHistory = mutableListOf<FlopsHistoryFragment>()
+ val flopsHistory = mutableListOf<SimTraceWorkload.Fragment>()
var vmId = -1L
var cores = -1
var requiredMemory = -1L
@@ -99,11 +99,11 @@ public class BitbrainsTraceReader(
val flops: Long = (cpuUsage * 5 * 60 * cores).toLong()
if (flopsHistory.isEmpty()) {
- flopsHistory.add(FlopsHistoryFragment(timestamp, flops, traceInterval, cpuUsage, cores))
+ flopsHistory.add(SimTraceWorkload.Fragment(timestamp, flops, traceInterval, cpuUsage, cores))
} else {
if (flopsHistory.last().flops != flops) {
flopsHistory.add(
- FlopsHistoryFragment(
+ SimTraceWorkload.Fragment(
timestamp,
flops,
traceInterval,
@@ -114,8 +114,8 @@ public class BitbrainsTraceReader(
} else {
val oldFragment = flopsHistory.removeAt(flopsHistory.size - 1)
flopsHistory.add(
- FlopsHistoryFragment(
- oldFragment.tick,
+ SimTraceWorkload.Fragment(
+ oldFragment.time,
oldFragment.flops + flops,
oldFragment.duration + traceInterval,
cpuUsage,
@@ -139,17 +139,19 @@ public class BitbrainsTraceReader(
uuid,
"VM Workload $vmId",
UnnamedUser,
- VmImage(
+ SimWorkloadImage(
uuid,
vmId.toString(),
- mapOf(IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems),
- flopsHistory.asSequence(),
- cores,
- requiredMemory
+ mapOf(
+ IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems,
+ "cores" to cores,
+ "required-memory" to requiredMemory
+ ),
+ SimTraceWorkload(flopsHistory.asSequence())
)
)
entries[vmId] = TraceEntryImpl(
- flopsHistory.firstOrNull()?.tick ?: -1,
+ flopsHistory.firstOrNull()?.time ?: -1,
vmWorkload
)
}
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt
index 9f8fb558..a20b4f29 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt
@@ -22,10 +22,11 @@
package org.opendc.format.trace.gwf
-import org.opendc.compute.core.image.FlopsApplicationImage
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.core.User
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.workload.SimFlopsWorkload
import org.opendc.workflows.workload.Job
import org.opendc.workflows.workload.Task
import org.opendc.workflows.workload.WORKFLOW_TASK_DEADLINE
@@ -137,7 +138,7 @@ public class GwfTraceReader(reader: BufferedReader) : TraceReader<Job> {
val task = Task(
UUID(0L, taskId),
"<unnamed>",
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), flops, cores),
+ SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(flops, cores)),
HashSet(),
mapOf(WORKFLOW_TASK_DEADLINE to runtime)
)
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt
index fd8cdfce..4267737d 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt
@@ -25,9 +25,8 @@ package org.opendc.format.trace.sc20
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
-import org.opendc.compute.core.workload.PerformanceInterferenceModelItem
import org.opendc.format.trace.PerformanceInterferenceModelReader
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
import java.io.InputStream
import java.util.*
import kotlin.random.Random
@@ -43,13 +42,13 @@ public class Sc20PerformanceInterferenceReader(input: InputStream, mapper: Objec
/**
* The computed value from the file.
*/
- private val items: Map<String, TreeSet<PerformanceInterferenceModelItem>>
+ private val items: Map<String, TreeSet<PerformanceInterferenceModel.Item>>
init {
val entries: List<PerformanceInterferenceEntry> = mapper.readValue(input)
- val res = mutableMapOf<String, TreeSet<PerformanceInterferenceModelItem>>()
+ val res = mutableMapOf<String, TreeSet<PerformanceInterferenceModel.Item>>()
for (entry in entries) {
- val item = PerformanceInterferenceModelItem(TreeSet(entry.vms), entry.minServerLoad, entry.performanceScore)
+ val item = PerformanceInterferenceModel.Item(TreeSet(entry.vms), entry.minServerLoad, entry.performanceScore)
for (workload in entry.vms) {
res.computeIfAbsent(workload) { TreeSet() }.add(item)
}
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt
index bfcc30ce..66efbcd0 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt
@@ -22,14 +22,14 @@
package org.opendc.format.trace.sc20
-import org.opendc.compute.core.image.FlopsHistoryFragment
-import org.opendc.compute.core.image.VmImage
-import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
import org.opendc.compute.core.workload.VmWorkload
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.core.User
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.interference.IMAGE_PERF_INTERFERENCE_MODEL
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+import org.opendc.simulator.compute.workload.SimTraceWorkload
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
@@ -64,7 +64,6 @@ public class Sc20TraceReader(
val timestampCol = 0
val cpuUsageCol = 1
val coreCol = 12
- val vmIdCol = 19
val provisionedMemoryCol = 20
val traceInterval = 5 * 60 * 1000L
@@ -109,7 +108,7 @@ public class Sc20TraceReader(
}
val flopsFragments = sequence {
- var last: FlopsHistoryFragment? = null
+ var last: SimTraceWorkload.Fragment? = null
BufferedReader(FileReader(vmFile)).use { reader ->
reader.lineSequence()
@@ -130,8 +129,8 @@ public class Sc20TraceReader(
last = if (last != null && last!!.flops == 0L && flops == 0L) {
val oldFragment = last!!
- FlopsHistoryFragment(
- oldFragment.tick,
+ SimTraceWorkload.Fragment(
+ oldFragment.time,
oldFragment.flops + flops,
oldFragment.duration + traceInterval,
cpuUsage,
@@ -139,7 +138,7 @@ public class Sc20TraceReader(
)
} else {
val fragment =
- FlopsHistoryFragment(timestamp, flops, traceInterval, cpuUsage, cores)
+ SimTraceWorkload.Fragment(timestamp, flops, traceInterval, cpuUsage, cores)
if (last != null) {
yield(last!!)
}
@@ -165,13 +164,15 @@ public class Sc20TraceReader(
uuid,
"VM Workload $vmId",
UnnamedUser,
- VmImage(
+ SimWorkloadImage(
uuid,
vmId,
- mapOf(IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems),
- flopsFragments.asSequence(),
- maxCores,
- requiredMemory
+ mapOf(
+ IMAGE_PERF_INTERFERENCE_MODEL to relevantPerformanceInterferenceModelItems,
+ "cores" to cores,
+ "required-memory" to requiredMemory
+ ),
+ SimTraceWorkload(flopsFragments.asSequence())
)
)
entries[uuid] = TraceEntryImpl(
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt
index 13bd7ac3..52d41c44 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt
@@ -22,12 +22,12 @@
package org.opendc.format.trace.swf
-import org.opendc.compute.core.image.FlopsHistoryFragment
-import org.opendc.compute.core.image.VmImage
import org.opendc.compute.core.workload.VmWorkload
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.core.User
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.workload.SimTraceWorkload
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
@@ -64,17 +64,17 @@ public class SwfTraceReader(
val sliceDuration = 5 * 60L
- var jobNumber = -1L
- var submitTime = -1L
- var waitTime = -1L
- var runTime = -1L
- var cores = -1
- var memory = -1L
- var slicedWaitTime = -1L
- var flopsPerSecond = -1L
- var flopsPartialSlice = -1L
- var flopsFullSlice = -1L
- var runtimePartialSliceRemainder = -1L
+ var jobNumber: Long
+ var submitTime: Long
+ var waitTime: Long
+ var runTime: Long
+ var cores: Int
+ var memory: Long
+ var slicedWaitTime: Long
+ var flopsPerSecond: Long
+ var flopsPartialSlice: Long
+ var flopsFullSlice: Long
+ var runtimePartialSliceRemainder: Long
BufferedReader(FileReader(file)).use { reader ->
reader.lineSequence()
@@ -103,7 +103,7 @@ public class SwfTraceReader(
memory /= 1000 // convert KB to MB
}
- val flopsHistory = mutableListOf<FlopsHistoryFragment>()
+ val flopsHistory = mutableListOf<SimTraceWorkload.Fragment>()
// Insert waiting time slices
@@ -112,7 +112,7 @@ public class SwfTraceReader(
if (waitTime >= sliceDuration) {
for (tick in submitTime until (submitTime + waitTime - sliceDuration) step sliceDuration) {
flopsHistory.add(
- FlopsHistoryFragment(
+ SimTraceWorkload.Fragment(
tick * 1000L,
0L,
sliceDuration * 1000L,
@@ -137,7 +137,7 @@ public class SwfTraceReader(
step sliceDuration
) {
flopsHistory.add(
- FlopsHistoryFragment(
+ SimTraceWorkload.Fragment(
tick * 1000L,
flopsFullSlice / sliceDuration,
sliceDuration * 1000L,
@@ -149,7 +149,7 @@ public class SwfTraceReader(
if (runtimePartialSliceRemainder > 0) {
flopsHistory.add(
- FlopsHistoryFragment(
+ SimTraceWorkload.Fragment(
submitTime + (slicedWaitTime + runTime - runtimePartialSliceRemainder),
flopsPartialSlice,
sliceDuration,
@@ -164,13 +164,14 @@ public class SwfTraceReader(
uuid,
"SWF Workload $jobNumber",
UnnamedUser,
- VmImage(
+ SimWorkloadImage(
uuid,
jobNumber.toString(),
- emptyMap(),
- flopsHistory.asSequence(),
- cores,
- memory
+ mapOf(
+ "cores" to cores,
+ "required-memory" to memory
+ ),
+ SimTraceWorkload(flopsHistory.asSequence())
)
)
diff --git a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/wtf/WtfTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/wtf/WtfTraceReader.kt
index de6647d0..b2931468 100644
--- a/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/wtf/WtfTraceReader.kt
+++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/wtf/WtfTraceReader.kt
@@ -25,10 +25,11 @@ package org.opendc.format.trace.wtf
import org.apache.avro.generic.GenericRecord
import org.apache.hadoop.fs.Path
import org.apache.parquet.avro.AvroParquetReader
-import org.opendc.compute.core.image.FlopsApplicationImage
+import org.opendc.compute.simulator.SimWorkloadImage
import org.opendc.core.User
import org.opendc.format.trace.TraceEntry
import org.opendc.format.trace.TraceReader
+import org.opendc.simulator.compute.workload.SimFlopsWorkload
import org.opendc.workflows.workload.Job
import org.opendc.workflows.workload.Task
import org.opendc.workflows.workload.WORKFLOW_TASK_DEADLINE
@@ -69,8 +70,6 @@ public class WtfTraceReader(path: String) : TraceReader<Job> {
val dependencies = (nextRecord.get("parents") as ArrayList<GenericRecord>).map {
it.get("item") as Long
}
- val inputSize: Long = 0
- val outputSize: Long = 0
val flops: Long = 4100 * (runtime / 1000) * cores
@@ -81,7 +80,7 @@ public class WtfTraceReader(path: String) : TraceReader<Job> {
val task = Task(
UUID(0L, taskId),
"<unnamed>",
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), flops, cores),
+ SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(flops, cores)),
HashSet(),
mapOf(WORKFLOW_TASK_DEADLINE to runtime)
)
diff --git a/simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/swf/SwfTraceReaderTest.kt b/simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/swf/SwfTraceReaderTest.kt
index 40132ad3..8db2ab40 100644
--- a/simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/swf/SwfTraceReaderTest.kt
+++ b/simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/swf/SwfTraceReaderTest.kt
@@ -24,6 +24,8 @@ package org.opendc.format.trace.swf
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
+import org.opendc.compute.simulator.SimWorkloadImage
+import org.opendc.simulator.compute.workload.SimTraceWorkload
import java.io.File
class SwfTraceReaderTest {
@@ -33,13 +35,13 @@ class SwfTraceReaderTest {
var entry = reader.next()
assertEquals(0, entry.submissionTime)
// 1961 slices for waiting, 3 full and 1 partial running slices
- assertEquals(1965, entry.workload.image.flopsHistory.toList().size)
+ assertEquals(1965, ((entry.workload.image as SimWorkloadImage).workload as SimTraceWorkload).trace.toList().size)
entry = reader.next()
assertEquals(164472, entry.submissionTime)
// 1188 slices for waiting, 0 full and 1 partial running slices
- assertEquals(1189, entry.workload.image.flopsHistory.toList().size)
- assertEquals(5_100_000L, entry.workload.image.flopsHistory.toList().last().flops)
- assertEquals(0.25, entry.workload.image.flopsHistory.toList().last().usage)
+ assertEquals(1189, ((entry.workload.image as SimWorkloadImage).workload as SimTraceWorkload).trace.toList().size)
+ assertEquals(5_100_000L, ((entry.workload.image as SimWorkloadImage).workload as SimTraceWorkload).trace.toList().last().flops)
+ assertEquals(0.25, ((entry.workload.image as SimWorkloadImage).workload as SimTraceWorkload).trace.toList().last().usage)
}
}
diff --git a/simulator/opendc-runner-web/build.gradle.kts b/simulator/opendc-runner-web/build.gradle.kts
index 7e81347c..cf437843 100644
--- a/simulator/opendc-runner-web/build.gradle.kts
+++ b/simulator/opendc-runner-web/build.gradle.kts
@@ -34,10 +34,11 @@ application {
dependencies {
api(project(":opendc-core"))
- implementation(project(":opendc-compute"))
+ implementation(project(":opendc-compute:opendc-compute-simulator"))
implementation(project(":opendc-format"))
implementation(project(":opendc-experiments:opendc-experiments-sc20"))
- implementation(project(":opendc-simulator"))
+ implementation(project(":opendc-simulator:opendc-simulator-core"))
+ implementation(project(":opendc-simulator:opendc-simulator-compute"))
implementation("com.github.ajalt:clikt:2.8.0")
implementation("io.github.microutils:kotlin-logging:1.7.10")
diff --git a/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt
index 67ec046a..26577ef2 100644
--- a/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt
+++ b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt
@@ -38,7 +38,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.test.TestCoroutineScope
import mu.KotlinLogging
import org.bson.Document
-import org.opendc.compute.virt.service.allocation.*
+import org.opendc.compute.simulator.allocation.*
import org.opendc.experiments.sc20.experiment.attachMonitor
import org.opendc.experiments.sc20.experiment.createFailureDomain
import org.opendc.experiments.sc20.experiment.createProvisioner
@@ -50,7 +50,6 @@ import org.opendc.experiments.sc20.trace.Sc20RawParquetTraceReader
import org.opendc.format.trace.sc20.Sc20PerformanceInterferenceReader
import org.opendc.simulator.utils.DelayControllerClockAdapter
import java.io.File
-import java.util.*
import kotlin.random.Random
private val logger = KotlinLogging.logger {}
@@ -278,8 +277,7 @@ public class RunnerCli : CliktCommand(name = "runner") {
trace,
scheduler,
chan,
- monitor,
- emptyMap()
+ monitor
)
logger.debug("SUBMIT=${scheduler.submittedVms}")
diff --git a/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt
index de9ece75..5e483271 100644
--- a/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt
+++ b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt
@@ -31,19 +31,20 @@ import com.mongodb.client.model.Projections
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.bson.Document
-import org.opendc.compute.core.MemoryUnit
-import org.opendc.compute.core.ProcessingNode
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.metal.NODE_CLUSTER
-import org.opendc.compute.metal.driver.SimpleBareMetalDriver
-import org.opendc.compute.metal.power.LinearLoadPowerModel
-import org.opendc.compute.metal.service.ProvisioningService
-import org.opendc.compute.metal.service.SimpleProvisioningService
+import org.opendc.compute.core.metal.NODE_CLUSTER
+import org.opendc.compute.core.metal.service.ProvisioningService
+import org.opendc.compute.core.metal.service.SimpleProvisioningService
+import org.opendc.compute.simulator.SimBareMetalDriver
+import org.opendc.compute.simulator.power.LinearLoadPowerModel
import org.opendc.core.Environment
import org.opendc.core.Platform
import org.opendc.core.Zone
import org.opendc.core.services.ServiceRegistry
import org.opendc.format.environment.EnvironmentReader
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
import java.time.Clock
import java.util.*
@@ -55,11 +56,10 @@ public class TopologyParser(private val collection: MongoCollection<Document>, p
* Parse the topology with the specified [id].
*/
override suspend fun construct(coroutineScope: CoroutineScope, clock: Clock): Environment {
- val nodes = mutableListOf<SimpleBareMetalDriver>()
+ val nodes = mutableListOf<SimBareMetalDriver>()
val random = Random(0)
for (machine in fetchMachines(id)) {
- val machineId = machine.getString("_id")
val clusterId = machine.getString("rack_id")
val position = machine.getInteger("position")
@@ -81,14 +81,13 @@ public class TopologyParser(private val collection: MongoCollection<Document>, p
)
}
nodes.add(
- SimpleBareMetalDriver(
+ SimBareMetalDriver(
coroutineScope,
clock,
UUID(random.nextLong(), random.nextLong()),
"node-$clusterId-$position",
mapOf(NODE_CLUSTER to clusterId),
- processors,
- memoryUnits,
+ SimMachineModel(processors, memoryUnits),
// For now we assume a simple linear load model with an idle draw of ~200W and a maximum
// power draw of 350W.
// Source: https://stackoverflow.com/questions/6128960
diff --git a/simulator/opendc-simulator/build.gradle.kts b/simulator/opendc-simulator/build.gradle.kts
index a740dcf3..e69de29b 100644
--- a/simulator/opendc-simulator/build.gradle.kts
+++ b/simulator/opendc-simulator/build.gradle.kts
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-description = "Simulation-specific code for use in OpenDC"
-
-/* Build configuration */
-plugins {
- `kotlin-library-convention`
-}
-
-dependencies {
- api("org.jetbrains.kotlinx:kotlinx-coroutines-test:${Library.KOTLINX_COROUTINES}")
-}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerManagementContext.kt b/simulator/opendc-simulator/opendc-simulator-compute/build.gradle.kts
index 51727e43..cd7e5706 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerManagementContext.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/build.gradle.kts
@@ -1,7 +1,5 @@
/*
- * MIT License
- *
- * Copyright (c) 2020 atlarge-research
+ * 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
@@ -22,19 +20,16 @@
* SOFTWARE.
*/
-package org.opendc.compute.core.execution
+description = "Library for simulation of cloud computing components"
-/**
- * An extended [ServerContext] providing several methods for managing the execution context.
- */
-public interface ServerManagementContext : ServerContext {
- /**
- * Initialize the management context.
- */
- public suspend fun init()
+plugins {
+ `kotlin-library-convention`
+}
+
+dependencies {
+ api(project(":opendc-simulator:opendc-simulator-core"))
- /**
- * Terminate the execution of the server.
- */
- public suspend fun exit(cause: Throwable? = null)
+ testImplementation("org.junit.jupiter:junit-jupiter-api:${Library.JUNIT_JUPITER}")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Library.JUNIT_JUPITER}")
+ testImplementation("org.junit.platform:junit-platform-launcher:${Library.JUNIT_PLATFORM}")
}
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
new file mode 100644
index 00000000..c6d5bdd1
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
@@ -0,0 +1,281 @@
+/*
+ * 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.simulator.compute
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.intrinsics.startCoroutineCancellable
+import kotlinx.coroutines.selects.SelectClause0
+import kotlinx.coroutines.selects.SelectInstance
+import org.opendc.simulator.compute.workload.SimWorkload
+import java.lang.Runnable
+import java.time.Clock
+import kotlin.coroutines.ContinuationInterceptor
+import kotlin.math.ceil
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * A simulated bare-metal machine that is able to run a single workload.
+ *
+ * A [SimBareMetalMachine] is a stateful object and you should be careful when operating this object concurrently. For
+ * example. the class expects only a single concurrent call to [run].
+ *
+ * @param coroutineScope The [CoroutineScope] to run the simulated workload in.
+ * @param clock The virtual clock to track the simulation time.
+ * @param model The machine model to simulate.
+ */
+@OptIn(ExperimentalCoroutinesApi::class, InternalCoroutinesApi::class)
+public class SimBareMetalMachine(
+ private val coroutineScope: CoroutineScope,
+ private val clock: Clock,
+ override val model: SimMachineModel
+) : SimMachine {
+ /**
+ * A [StateFlow] representing the CPU usage of the simulated machine.
+ */
+ override val usage: StateFlow<Double>
+ get() = usageState
+
+ /**
+ * The current active workload.
+ */
+ private var activeWorkload: SimWorkload? = null
+
+ /**
+ * Run the specified [SimWorkload] on this machine and suspend execution util the workload has finished.
+ */
+ override suspend fun run(workload: SimWorkload) {
+ require(activeWorkload == null) { "Run should not be called concurrently" }
+
+ try {
+ activeWorkload = workload
+ workload.run(ctx)
+ } finally {
+ activeWorkload = null
+ }
+ }
+
+ /**
+ * The execution context in which the workload runs.
+ */
+ private val ctx = object : SimExecutionContext {
+ override val machine: SimMachineModel
+ get() = this@SimBareMetalMachine.model
+
+ override val clock: Clock
+ get() = this@SimBareMetalMachine.clock
+
+ override fun onRun(
+ batch: Sequence<SimExecutionContext.Slice>,
+ triggerMode: SimExecutionContext.TriggerMode,
+ merge: (SimExecutionContext.Slice, SimExecutionContext.Slice) -> SimExecutionContext.Slice
+ ): SelectClause0 {
+ return object : SelectClause0 {
+ @InternalCoroutinesApi
+ override fun <R> registerSelectClause0(select: SelectInstance<R>, block: suspend () -> R) {
+ // Do not reset the usage state: we will set it ourselves
+ usageFlush?.dispose()
+ usageFlush = null
+
+ val queue = batch.iterator()
+ var start = Long.MIN_VALUE
+ var currentWork: SliceWork? = null
+ var currentDisposable: DisposableHandle? = null
+
+ fun schedule(slice: SimExecutionContext.Slice) {
+ start = clock.millis()
+
+ val isLastSlice = !queue.hasNext()
+ val work = SliceWork(slice)
+ val candidateDuration = when (triggerMode) {
+ SimExecutionContext.TriggerMode.FIRST -> work.minExit
+ SimExecutionContext.TriggerMode.LAST -> work.maxExit
+ SimExecutionContext.TriggerMode.DEADLINE -> slice.deadline - start
+ }
+
+ // Check whether the deadline is exceeded during the run of the slice.
+ val duration = min(candidateDuration, slice.deadline - start)
+
+ val action = Runnable {
+ currentWork = null
+
+ // Flush all the work that was performed
+ val hasFinished = work.stop(duration)
+
+ if (!isLastSlice) {
+ val candidateSlice = queue.next()
+ val nextSlice =
+ // If our previous slice exceeds its deadline, merge it with the next candidate slice
+ if (hasFinished)
+ candidateSlice
+ else
+ merge(candidateSlice, slice)
+ schedule(nextSlice)
+ } else if (select.trySelect()) {
+ block.startCoroutineCancellable(select.completion)
+ }
+ }
+
+ // Schedule the flush after the entire slice has finished
+ currentDisposable = delay.invokeOnTimeout(duration, action)
+
+ // Start the slice work
+ currentWork = work
+ work.start()
+ }
+
+ // Schedule the first work
+ if (queue.hasNext()) {
+ schedule(queue.next())
+
+ // A DisposableHandle to flush the work in case the call is cancelled
+ val disposable = DisposableHandle {
+ val end = clock.millis()
+ val duration = end - start
+
+ currentWork?.stop(duration)
+ currentDisposable?.dispose()
+
+ // Schedule reset the usage of the machine since the call is returning
+ usageFlush = delay.invokeOnTimeout(1) {
+ usageState.value = 0.0
+ usageFlush = null
+ }
+ }
+
+ select.disposeOnSelect(disposable)
+ } else if (select.trySelect()) {
+ // No work has been given: select immediately
+ block.startCoroutineCancellable(select.completion)
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * The [MutableStateFlow] containing the load of the server.
+ */
+ private val usageState = MutableStateFlow(0.0)
+
+ /**
+ * A disposable to prevent resetting the usage state for subsequent calls to onRun.
+ */
+ private var usageFlush: DisposableHandle? = null
+
+ /**
+ * Cache the [Delay] instance for timing.
+ *
+ * XXX We need to cache this before the call to [onRun] since doing this in [onRun] is too heavy.
+ * XXX Note however that this is an ugly hack which may break in the future.
+ */
+ @OptIn(InternalCoroutinesApi::class)
+ private val delay = coroutineScope.coroutineContext[ContinuationInterceptor] as Delay
+
+ /**
+ * A slice to be processed.
+ */
+ private inner class SliceWork(val slice: SimExecutionContext.Slice) {
+ /**
+ * The duration after which the first processor finishes processing this slice.
+ */
+ val minExit: Long
+
+ /**
+ * The duration after which the last processor finishes processing this slice.
+ */
+ val maxExit: Long
+
+ /**
+ * A flag to indicate that the slice will exceed the deadline.
+ */
+ val exceedsDeadline: Boolean
+ get() = slice.deadline < maxExit
+
+ /**
+ * The total amount of CPU usage.
+ */
+ val totalUsage: Double
+
+ /**
+ * A flag to indicate that this slice is empty.
+ */
+ val isEmpty: Boolean
+
+ init {
+ var totalUsage = 0.0
+ var minExit = Long.MAX_VALUE
+ var maxExit = 0L
+ var nonEmpty = false
+
+ // Determine the duration of the first/last CPU to finish
+ for (i in 0 until min(model.cpus.size, slice.burst.size)) {
+ val cpu = model.cpus[i]
+ val usage = min(slice.limit[i], cpu.frequency)
+ val cpuDuration = ceil(slice.burst[i] / usage * 1000).toLong() // Convert from seconds to milliseconds
+
+ totalUsage += usage / cpu.frequency
+
+ if (cpuDuration != 0L) { // We only wait for processor cores with a non-zero burst
+ minExit = min(minExit, cpuDuration)
+ maxExit = max(maxExit, cpuDuration)
+ nonEmpty = true
+ }
+ }
+
+ this.isEmpty = !nonEmpty
+ this.totalUsage = totalUsage
+ this.minExit = minExit
+ this.maxExit = maxExit
+ }
+
+ /**
+ * Indicate that the work on the slice has started.
+ */
+ fun start() {
+ usageState.value = totalUsage / model.cpus.size
+ }
+
+ /**
+ * Flush the work performed on the slice.
+ */
+ fun stop(duration: Long): Boolean {
+ var hasFinished = true
+
+ for (i in 0 until min(model.cpus.size, slice.burst.size)) {
+ val usage = min(slice.limit[i], model.cpus[i].frequency)
+ val granted = ceil(duration / 1000.0 * usage).toLong()
+ val res = max(0, slice.burst[i] - granted)
+ slice.burst[i] = res
+
+ if (res != 0L) {
+ hasFinished = false
+ }
+ }
+
+ return hasFinished
+ }
+ }
+}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerContext.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimExecutionContext.kt
index 9674c98d..5801fcd5 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/execution/ServerContext.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimExecutionContext.kt
@@ -20,39 +20,27 @@
* SOFTWARE.
*/
-package org.opendc.compute.core.execution
+package org.opendc.simulator.compute
import kotlinx.coroutines.selects.SelectClause0
import kotlinx.coroutines.selects.select
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.core.Server
-import org.opendc.compute.core.image.Image
-import org.opendc.core.services.ServiceKey
import java.time.Clock
/**
- * Represents the execution context in which a bootable [Image] runs on a [Server].
+ * A simulated execution context in which a bootable image runs. This interface represents the
+ * firmware interface between the running image (e.g. operating system) and the physical or virtual firmware on
+ * which the image runs.
*/
-public interface ServerContext {
+public interface SimExecutionContext {
/**
- * The virtual clock.
+ * The virtual clock tracking simulation time.
*/
public val clock: Clock
/**
- * The server on which the image runs.
+ * The machine model of the machine that is running the image.
*/
- public val server: Server
-
- /**
- * A list of processing units available to use.
- */
- public val cpus: List<ProcessingUnit>
-
- /**
- * Publish the specified [service] at the given [ServiceKey].
- */
- public suspend fun <T : Any> publishService(key: ServiceKey<T>, service: T)
+ public val machine: SimMachineModel
/**
* Ask the processor cores to run the specified [slice] and suspend execution until the trigger condition is met as
@@ -66,7 +54,7 @@ public interface ServerContext {
* @param triggerMode The trigger condition to resume execution.
*/
public suspend fun run(slice: Slice, triggerMode: TriggerMode = TriggerMode.FIRST): Unit =
- select<Unit> { onRun(slice, triggerMode).invoke {} }
+ select { onRun(slice, triggerMode).invoke {} }
/**
* Ask the processors cores to run the specified [batch] of work slices and suspend execution until the trigger
@@ -88,7 +76,7 @@ public interface ServerContext {
batch: Sequence<Slice>,
triggerMode: TriggerMode = TriggerMode.FIRST,
merge: (Slice, Slice) -> Slice = { _, r -> r }
- ): Unit = select<Unit> { onRun(batch, triggerMode, merge).invoke {} }
+ ): Unit = select { onRun(batch, triggerMode, merge).invoke {} }
/**
* Ask the processor cores to run the specified [slice] and select when the trigger condition is met as specified
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimpleVirtDriver.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt
index fb3d5f84..6087227b 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/virt/driver/SimpleVirtDriver.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt
@@ -20,180 +20,100 @@
* SOFTWARE.
*/
-package org.opendc.compute.virt.driver
+package org.opendc.simulator.compute
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.intrinsics.startCoroutineCancellable
import kotlinx.coroutines.selects.SelectClause0
import kotlinx.coroutines.selects.SelectInstance
import kotlinx.coroutines.selects.select
-import mu.KotlinLogging
-import org.opendc.compute.core.Flavor
-import org.opendc.compute.core.ProcessingUnit
-import org.opendc.compute.core.Server
-import org.opendc.compute.core.ServerEvent
-import org.opendc.compute.core.ServerState
-import org.opendc.compute.core.execution.ServerContext
-import org.opendc.compute.core.execution.ServerManagementContext
-import org.opendc.compute.core.execution.ShutdownException
-import org.opendc.compute.core.image.Image
-import org.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL
-import org.opendc.compute.core.workload.PerformanceInterferenceModel
-import org.opendc.compute.virt.HypervisorEvent
-import org.opendc.core.services.ServiceKey
-import org.opendc.core.services.ServiceRegistry
-import org.opendc.utils.flow.EventFlow
+import org.opendc.simulator.compute.interference.PerformanceInterferenceModel
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.compute.workload.SimWorkload
import java.time.Clock
-import java.util.UUID
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
/**
- * The logging instance to use.
- */
-private val logger = KotlinLogging.logger {}
-
-/**
- * A [VirtDriver] that is backed by a simple hypervisor implementation.
+ * SimHypervisor distributes the computing requirements of multiple [SimWorkload] on a single [SimBareMetalMachine] concurrently.
+ *
+ * @param coroutineScope The [CoroutineScope] to run the simulated workloads in.
+ * @param clock The virtual clock to track the simulation time.
*/
-@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
-public class SimpleVirtDriver(
- private val hostContext: ServerContext,
- scope: CoroutineScope
-) : VirtDriver, CoroutineScope by scope {
+@OptIn(ExperimentalCoroutinesApi::class, InternalCoroutinesApi::class)
+public class SimHypervisor(
+ private val coroutineScope: CoroutineScope,
+ private val clock: Clock,
+ private val listener: Listener? = null
+) : SimWorkload {
/**
- * The [Server] on which this hypervisor runs.
+ * A set for tracking the VM context objects.
*/
- public val server: Server
- get() = hostContext.server
+ private val vms: MutableSet<VmExecutionContext> = mutableSetOf()
/**
- * A set for tracking the VM context objects.
+ * A flag to indicate the driver is stopped.
*/
- private val vms: MutableSet<VmServerContext> = mutableSetOf()
+ private var stopped: Boolean = false
/**
- * Current total memory use of the images on this hypervisor.
+ * The channel for scheduling new CPU requests.
*/
- private var availableMemory: Long = hostContext.server.flavor.memorySize
+ private val schedulingQueue = Channel<SchedulerCommand>(Channel.UNLIMITED)
/**
- * The [EventFlow] to emit the events.
+ * Create a [SimMachine] instance on which users may run a [SimWorkload].
+ *
+ * @param model The machine to create.
*/
- internal val eventFlow = EventFlow<HypervisorEvent>()
-
- override val events: Flow<HypervisorEvent> = eventFlow
-
- init {
- launch {
- try {
- // Yield first to allow class variables to initialize
- yield()
- scheduler()
- } catch (e: Exception) {
- if (e !is CancellationException) {
- logger.error("Hypervisor scheduler failed", e)
+ public fun createMachine(model: SimMachineModel, performanceInterferenceModel: PerformanceInterferenceModel? = null): SimMachine {
+ val vm = VmSession(model, performanceInterferenceModel)
+ val vmCtx = VmExecutionContext(vm)
+
+ return object : SimMachine {
+ override val model: SimMachineModel
+ get() = vmCtx.machine
+
+ override val usage: StateFlow<Double>
+ get() = vm.usage
+
+ /**
+ * The current active workload.
+ */
+ private var activeWorkload: SimWorkload? = null
+
+ override suspend fun run(workload: SimWorkload) {
+ require(activeWorkload == null) { "Run should not be called concurrently" }
+
+ try {
+ activeWorkload = workload
+ workload.run(vmCtx)
+ } finally {
+ activeWorkload = null
}
- throw e
}
- }
- }
- override suspend fun spawn(
- name: String,
- image: Image,
- flavor: Flavor
- ): Server {
- val requiredMemory = flavor.memorySize
- if (availableMemory - requiredMemory < 0) {
- throw InsufficientMemoryOnServerException()
+ override fun toString(): String = "SimVirtualMachine"
}
- require(flavor.cpuCount <= hostContext.server.flavor.cpuCount) { "Machine does not fit" }
-
- val events = EventFlow<ServerEvent>()
- val server = Server(
- UUID.randomUUID(),
- name,
- emptyMap(),
- flavor,
- image,
- ServerState.BUILD,
- ServiceRegistry(),
- events
- )
- availableMemory -= requiredMemory
- vms.add(VmServerContext(server, events))
- vmStarted(server)
- eventFlow.emit(HypervisorEvent.VmsUpdated(this, vms.size, availableMemory))
- return server
- }
-
- internal fun cancel() {
- eventFlow.close()
- }
-
- private fun vmStarted(server: Server) {
- vms.forEach {
- val performanceModel =
- it.server.image.tags[IMAGE_PERF_INTERFERENCE_MODEL] as? PerformanceInterferenceModel?
- performanceModel?.vmStarted(server)
- }
- }
-
- private fun vmStopped(server: Server) {
- vms.forEach {
- val performanceModel =
- it.server.image.tags[IMAGE_PERF_INTERFERENCE_MODEL] as? PerformanceInterferenceModel?
- performanceModel?.vmStopped(server)
- }
- }
-
- /**
- * A scheduling command processed by the scheduler.
- */
- private sealed class SchedulerCommand {
- /**
- * Schedule the specified VM on the hypervisor.
- */
- data class Schedule(val vm: Vm) : SchedulerCommand()
-
- /**
- * De-schedule the specified VM on the hypervisor.
- */
- data class Deschedule(val vm: Vm) : SchedulerCommand()
-
- /**
- * Interrupt the scheduler.
- */
- object Interrupt : SchedulerCommand()
}
/**
- * A flag to indicate the driver is stopped.
+ * Run the scheduling process of the hypervisor.
*/
- private var stopped: Boolean = false
+ override suspend fun run(ctx: SimExecutionContext) {
+ val model = ctx.machine
+ val maxUsage = model.cpus.sumByDouble { it.frequency }
+ val pCPUs = model.cpus.indices.sortedBy { model.cpus[it].frequency }
- /**
- * The channel for scheduling new CPU requests.
- */
- private val schedulingQueue = Channel<SchedulerCommand>(Channel.UNLIMITED)
-
- /**
- * The scheduling process of the hypervisor.
- */
- private suspend fun scheduler() {
- val clock = hostContext.clock
- val maxUsage = hostContext.cpus.sumByDouble { it.frequency }
- val pCPUs = hostContext.cpus.indices.sortedBy { hostContext.cpus[it].frequency }
-
- val vms = mutableSetOf<Vm>()
+ val vms = mutableSetOf<VmSession>()
val vcpus = mutableListOf<VCpu>()
- val usage = DoubleArray(hostContext.cpus.size)
- val burst = LongArray(hostContext.cpus.size)
+ val usage = DoubleArray(model.cpus.size)
+ val burst = LongArray(model.cpus.size)
fun process(command: SchedulerCommand) {
when (command) {
@@ -228,7 +148,6 @@ public class SimpleVirtDriver(
val start = clock.millis()
- val vmCount = vms.size
var duration: Double = Double.POSITIVE_INFINITY
var deadline: Long = Long.MAX_VALUE
var availableUsage = maxUsage
@@ -274,7 +193,7 @@ public class SimpleVirtDriver(
// Divide the requests over the available capacity of the pCPUs fairly
for (i in pCPUs) {
- val maxCpuUsage = hostContext.cpus[i].frequency
+ val maxCpuUsage = model.cpus[i].frequency
val fraction = maxCpuUsage / maxUsage
val grantedUsage = min(maxCpuUsage, totalAllocatedUsage * fraction)
val grantedBurst = ceil(duration * grantedUsage).toLong()
@@ -289,7 +208,7 @@ public class SimpleVirtDriver(
// time, so not all of the burst may be executed.
select<Boolean> {
schedulingQueue.onReceive { schedulingQueue.offer(it); true }
- hostContext.onRun(ServerContext.Slice(burst, usage, deadline), ServerContext.TriggerMode.DEADLINE)
+ ctx.onRun(SimExecutionContext.Slice(burst, usage, deadline), SimExecutionContext.TriggerMode.DEADLINE)
.invoke { false }
}
@@ -316,9 +235,7 @@ public class SimpleVirtDriver(
val vm = vmIterator.next()
// Apply performance interference model
- val performanceModel =
- vm.ctx.server.image.tags[IMAGE_PERF_INTERFERENCE_MODEL] as? PerformanceInterferenceModel?
- val performanceScore = performanceModel?.apply(serverLoad) ?: 1.0
+ val performanceScore = vm.performanceInterferenceModel?.apply(serverLoad) ?: 1.0
var hasFinished = false
for (vcpu in vm.vcpus) {
@@ -336,7 +253,7 @@ public class SimpleVirtDriver(
// Compute remaining burst time to be executed for the request
if (vcpu.consume(usedBurst)) {
hasFinished = true
- } else if (vm.deadline <= end && hostContext.server.state != ServerState.ERROR) {
+ } else if (vm.deadline <= end) {
// Request must have its entire burst consumed or otherwise we have overcommission
// Note that we count the overcommissioned burst if the hypervisor has failed.
totalOvercommissionedBurst += vcpu.burst
@@ -352,26 +269,60 @@ public class SimpleVirtDriver(
}
}
- eventFlow.emit(
- HypervisorEvent.SliceFinished(
- this@SimpleVirtDriver,
- totalRequestedBurst,
- min(totalRequestedSubBurst, totalGrantedBurst), // We can run more than requested due to timing
- totalOvercommissionedBurst,
- totalInterferedBurst, // Might be smaller than zero due to FP rounding errors,
- min(
- totalAllocatedUsage,
- totalRequestedUsage
- ), // The allocated usage might be slightly higher due to FP rounding
- totalRequestedUsage,
- vmCount, // Some VMs might already have finished, so keep initial VM count
- server
- )
+ listener?.onSliceFinish(
+ this,
+ totalRequestedBurst,
+ min(totalRequestedSubBurst, totalGrantedBurst), // We can run more than requested due to timing
+ totalOvercommissionedBurst,
+ totalInterferedBurst, // Might be smaller than zero due to FP rounding errors,
+ min(
+ totalAllocatedUsage,
+ totalRequestedUsage
+ ), // The allocated usage might be slightly higher due to FP rounding
+ totalRequestedUsage
)
}
}
/**
+ * Event listener for hypervisor events.
+ */
+ public interface Listener {
+ /**
+ * This method is invoked when a slice is finished.
+ */
+ public fun onSliceFinish(
+ hypervisor: SimHypervisor,
+ requestedBurst: Long,
+ grantedBurst: Long,
+ overcommissionedBurst: Long,
+ interferedBurst: Long,
+ cpuUsage: Double,
+ cpuDemand: Double
+ )
+ }
+
+ /**
+ * A scheduling command processed by the scheduler.
+ */
+ private sealed class SchedulerCommand {
+ /**
+ * Schedule the specified VM on the hypervisor.
+ */
+ data class Schedule(val vm: VmSession) : SchedulerCommand()
+
+ /**
+ * De-schedule the specified VM on the hypervisor.
+ */
+ data class Deschedule(val vm: VmSession) : SchedulerCommand()
+
+ /**
+ * Interrupt the scheduler.
+ */
+ object Interrupt : SchedulerCommand()
+ }
+
+ /**
* A virtual machine running on the hypervisor.
*
* @param ctx The execution context the vCPU runs in.
@@ -380,10 +331,11 @@ public class SimpleVirtDriver(
* @param select The function to select on finish.
*/
@OptIn(InternalCoroutinesApi::class)
- private data class Vm(
- val ctx: VmServerContext,
- var triggerMode: ServerContext.TriggerMode = ServerContext.TriggerMode.FIRST,
- var merge: (ServerContext.Slice, ServerContext.Slice) -> ServerContext.Slice = { _, r -> r },
+ private data class VmSession(
+ val model: SimMachineModel,
+ val performanceInterferenceModel: PerformanceInterferenceModel? = null,
+ var triggerMode: SimExecutionContext.TriggerMode = SimExecutionContext.TriggerMode.FIRST,
+ var merge: (SimExecutionContext.Slice, SimExecutionContext.Slice) -> SimExecutionContext.Slice = { _, r -> r },
var select: () -> Unit = {}
) {
/**
@@ -394,12 +346,12 @@ public class SimpleVirtDriver(
/**
* The slices that the VM wants to run.
*/
- var queue: Iterator<ServerContext.Slice> = emptyList<ServerContext.Slice>().iterator()
+ var queue: Iterator<SimExecutionContext.Slice> = emptyList<SimExecutionContext.Slice>().iterator()
/**
* The current active slice.
*/
- var activeSlice: ServerContext.Slice? = null
+ var activeSlice: SimExecutionContext.Slice? = null
/**
* The current deadline of the VM.
@@ -413,19 +365,24 @@ public class SimpleVirtDriver(
val isIdle: Boolean
get() = activeSlice == null
+ /**
+ * The usage of the virtual machine.
+ */
+ val usage: MutableStateFlow<Double> = MutableStateFlow(0.0)
+
init {
- vcpus = ctx.cpus.mapIndexed { i, model -> VCpu(this, model, i) }
+ vcpus = model.cpus.mapIndexed { i, model -> VCpu(this, model, i) }
}
/**
* Schedule the given slices on this vCPU, replacing the existing slices.
*/
- fun schedule(slices: Sequence<ServerContext.Slice>) {
+ fun schedule(slices: Sequence<SimExecutionContext.Slice>) {
queue = slices.iterator()
if (queue.hasNext()) {
activeSlice = queue.next()
- vcpus.forEach { it.refresh() }
+ refresh()
}
}
@@ -433,9 +390,9 @@ public class SimpleVirtDriver(
* Cancel the existing workload on the VM.
*/
fun cancel() {
- queue = emptyList<ServerContext.Slice>().iterator()
+ queue = emptyList<SimExecutionContext.Slice>().iterator()
activeSlice = null
- vcpus.forEach { it.refresh() }
+ refresh()
}
/**
@@ -454,7 +411,7 @@ public class SimpleVirtDriver(
this.activeSlice = slice
// Update the vCPU cache
- vcpus.forEach { it.refresh() }
+ refresh()
false
} else {
@@ -463,6 +420,14 @@ public class SimpleVirtDriver(
true
}
}
+
+ /**
+ * Refresh the vCPU cache.
+ */
+ fun refresh() {
+ vcpus.forEach { it.refresh() }
+ usage.value = vcpus.sumByDouble { it.burst / it.limit } / vcpus.size
+ }
}
/**
@@ -473,7 +438,7 @@ public class SimpleVirtDriver(
* @param id The id of the vCPU with respect to the VM.
*/
private data class VCpu(
- val vm: Vm,
+ val vm: VmSession,
val model: ProcessingUnit,
val id: Int
) : Comparable<VCpu> {
@@ -516,124 +481,54 @@ public class SimpleVirtDriver(
* Compare to another vCPU based on the current load of the vCPU.
*/
override fun compareTo(other: VCpu): Int {
- var cmp = limit.compareTo(other.limit)
-
- if (cmp != 0) {
- return cmp
- }
-
- cmp = vm.ctx.server.uid.compareTo(other.vm.ctx.server.uid)
-
- if (cmp != 0) {
- return cmp
- }
-
- return id.compareTo(other.id)
+ return limit.compareTo(other.limit)
}
/**
* Create a string representation of the vCPU.
*/
override fun toString(): String =
- "vCPU(vm=${vm.ctx.server.uid},id=$id,burst=$burst,limit=$limit,allocatedLimit=$allocatedLimit)"
+ "vCPU(id=$id,burst=$burst,limit=$limit,allocatedLimit=$allocatedLimit)"
}
/**
* The execution context in which a VM runs.
*
- * @param server The details of the VM.
- * @param events The event stream to publish to.
*/
- private inner class VmServerContext(server: Server, val events: EventFlow<ServerEvent>) :
- ServerManagementContext,
- DisposableHandle {
- private var finalized: Boolean = false
- private var initialized: Boolean = false
- private val vm: Vm
-
- internal val job: Job = launch {
- delay(1) // TODO Introduce boot time
- init()
- try {
- server.image(this@VmServerContext)
- exit()
- } catch (cause: Throwable) {
- exit(cause)
- }
- }
-
- override var server: Server = server
- set(value) {
- if (field.state != value.state) {
- events.emit(ServerEvent.StateChanged(value, field.state))
- }
-
- field = value
- }
-
- override val cpus: List<ProcessingUnit> = hostContext.cpus.take(server.flavor.cpuCount)
+ private inner class VmExecutionContext(val session: VmSession) :
+ SimExecutionContext, DisposableHandle {
+ override val machine: SimMachineModel
+ get() = session.model
override val clock: Clock
- get() = hostContext.clock
-
- init {
- vm = Vm(this)
- }
-
- override suspend fun <T : Any> publishService(key: ServiceKey<T>, service: T) {
- server = server.copy(services = server.services.put(key, service))
- events.emit(ServerEvent.ServicePublished(server, key))
- }
-
- override suspend fun init() {
- assert(!finalized) { "VM is already finalized" }
-
- server = server.copy(state = ServerState.ACTIVE)
- initialized = true
- }
-
- override suspend fun exit(cause: Throwable?) {
- finalized = true
-
- val serverState =
- if (cause == null || (cause is ShutdownException && cause.cause == null))
- ServerState.SHUTOFF
- else
- ServerState.ERROR
- server = server.copy(state = serverState)
- availableMemory += server.flavor.memorySize
- vms.remove(this)
- vmStopped(server)
- eventFlow.emit(HypervisorEvent.VmsUpdated(this@SimpleVirtDriver, vms.size, availableMemory))
- events.close()
- }
+ get() = this@SimHypervisor.clock
@OptIn(InternalCoroutinesApi::class)
override fun onRun(
- batch: Sequence<ServerContext.Slice>,
- triggerMode: ServerContext.TriggerMode,
- merge: (ServerContext.Slice, ServerContext.Slice) -> ServerContext.Slice
+ batch: Sequence<SimExecutionContext.Slice>,
+ triggerMode: SimExecutionContext.TriggerMode,
+ merge: (SimExecutionContext.Slice, SimExecutionContext.Slice) -> SimExecutionContext.Slice
): SelectClause0 = object : SelectClause0 {
@InternalCoroutinesApi
override fun <R> registerSelectClause0(select: SelectInstance<R>, block: suspend () -> R) {
- vm.triggerMode = triggerMode
- vm.merge = merge
- vm.select = {
+ session.triggerMode = triggerMode
+ session.merge = merge
+ session.select = {
if (select.trySelect()) {
block.startCoroutineCancellable(select.completion)
}
}
- vm.schedule(batch)
+ session.schedule(batch)
// Indicate to the hypervisor that the VM should be re-scheduled
- schedulingQueue.offer(SchedulerCommand.Schedule(vm))
- select.disposeOnSelect(this@VmServerContext)
+ schedulingQueue.offer(SchedulerCommand.Schedule(session))
+ select.disposeOnSelect(this@VmExecutionContext)
}
}
override fun dispose() {
- if (!vm.isIdle) {
- vm.cancel()
- schedulingQueue.offer(SchedulerCommand.Deschedule(vm))
+ if (!session.isIdle) {
+ session.cancel()
+ schedulingQueue.offer(SchedulerCommand.Deschedule(session))
}
}
}
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt
new file mode 100644
index 00000000..f66085af
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.simulator.compute
+
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.StateFlow
+import org.opendc.simulator.compute.workload.SimWorkload
+
+/**
+ * A generic machine that is able to run a [SimWorkload].
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+public interface SimMachine {
+ /**
+ * The model of the machine containing its specifications.
+ */
+ public val model: SimMachineModel
+
+ /**
+ * A [StateFlow] representing the CPU usage of the simulated machine.
+ */
+ public val usage: StateFlow<Double>
+
+ /**
+ * Run the specified [SimWorkload] on this machine and suspend execution util the workload has finished.
+ */
+ public suspend fun run(workload: SimWorkload)
+}
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt
new file mode 100644
index 00000000..c2988b11
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.simulator.compute
+
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingUnit
+
+/**
+ * A description of the physical or virtual machine on which a bootable image runs.
+ *
+ * @property cpus The list of processing units available to the image.
+ * @property memory The list of memory units available to the image.
+ */
+public data class SimMachineModel(public val cpus: List<ProcessingUnit>, public val memory: List<MemoryUnit>)
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/PerformanceInterferenceModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt
index 7956c095..4c409887 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/workload/PerformanceInterferenceModel.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt
@@ -20,9 +20,8 @@
* SOFTWARE.
*/
-package org.opendc.compute.core.workload
+package org.opendc.simulator.compute.interference
-import org.opendc.compute.core.Server
import java.util.*
import kotlin.random.Random
@@ -34,41 +33,35 @@ public const val IMAGE_PERF_INTERFERENCE_MODEL: String = "image:performance-inte
/**
* Performance Interference Model describing the variability incurred by different sets of workloads if colocated.
*
- * @param items The [PerformanceInterferenceModelItem]s that make up this model.
+ * @param items The [PerformanceInterferenceModel.Item]s that make up this model.
*/
public class PerformanceInterferenceModel(
- public val items: SortedSet<PerformanceInterferenceModelItem>,
+ public val items: SortedSet<Item>,
private val random: Random = Random(0)
) {
- private var intersectingItems: List<PerformanceInterferenceModelItem> = emptyList()
+ private var intersectingItems: List<Item> = emptyList()
private val colocatedWorkloads = TreeMap<String, Int>()
- internal fun vmStarted(server: Server) {
- colocatedWorkloads.merge(server.image.name, 1, Int::plus)
+ /**
+ * Indicate that a VM has started.
+ */
+ public fun onStart(name: String) {
+ colocatedWorkloads.merge(name, 1, Int::plus)
intersectingItems = items.filter { item -> doesMatch(item) }
}
- internal fun vmStopped(server: Server) {
- colocatedWorkloads.computeIfPresent(server.image.name) { _, v -> (v - 1).takeUnless { it == 0 } }
+ /**
+ * Indicate that a VM has stopped.
+ */
+ public fun onStop(name: String) {
+ colocatedWorkloads.computeIfPresent(name) { _, v -> (v - 1).takeUnless { it == 0 } }
intersectingItems = items.filter { item -> doesMatch(item) }
}
- private fun doesMatch(item: PerformanceInterferenceModelItem): Boolean {
- var count = 0
- for (
- name in item.workloadNames.subSet(
- colocatedWorkloads.firstKey(),
- colocatedWorkloads.lastKey() + "\u0000"
- )
- ) {
- count += colocatedWorkloads.getOrDefault(name, 0)
- if (count > 1)
- return true
- }
- return false
- }
-
- internal fun apply(currentServerLoad: Double): Double {
+ /**
+ * Compute the performance interference based on the current server load.
+ */
+ public fun apply(currentServerLoad: Double): Double {
if (intersectingItems.isEmpty()) {
return 1.0
}
@@ -82,45 +75,60 @@ public class PerformanceInterferenceModel(
1.0
}
}
-}
-
-/**
- * Model describing how a specific set of workloads causes performance variability for each workload.
- *
- * @param workloadNames The names of the workloads that together cause performance variability for each workload in the set.
- * @param minServerLoad The minimum total server load at which this interference is activated and noticeable.
- * @param performanceScore The performance score that should be applied to each workload's performance. 1 means no
- * influence, <1 means that performance degrades, and >1 means that performance improves.
- */
-public data class PerformanceInterferenceModelItem(
- public val workloadNames: SortedSet<String>,
- public val minServerLoad: Double,
- public val performanceScore: Double
-) : Comparable<PerformanceInterferenceModelItem> {
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
- other as PerformanceInterferenceModelItem
+ private fun doesMatch(item: Item): Boolean {
+ var count = 0
+ for (
+ name in item.workloadNames.subSet(
+ colocatedWorkloads.firstKey(),
+ colocatedWorkloads.lastKey() + "\u0000"
+ )
+ ) {
+ count += colocatedWorkloads.getOrDefault(name, 0)
+ if (count > 1)
+ return true
+ }
+ return false
+ }
- if (workloadNames != other.workloadNames) return false
+ /**
+ * Model describing how a specific set of workloads causes performance variability for each workload.
+ *
+ * @param workloadNames The names of the workloads that together cause performance variability for each workload in the set.
+ * @param minServerLoad The minimum total server load at which this interference is activated and noticeable.
+ * @param performanceScore The performance score that should be applied to each workload's performance. 1 means no
+ * influence, <1 means that performance degrades, and >1 means that performance improves.
+ */
+ public data class Item(
+ public val workloadNames: SortedSet<String>,
+ public val minServerLoad: Double,
+ public val performanceScore: Double
+ ) : Comparable<Item> {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as Item
+
+ if (workloadNames != other.workloadNames) return false
+
+ return true
+ }
- return true
- }
+ override fun hashCode(): Int = workloadNames.hashCode()
- override fun hashCode(): Int = workloadNames.hashCode()
+ override fun compareTo(other: Item): Int {
+ var cmp = performanceScore.compareTo(other.performanceScore)
+ if (cmp != 0) {
+ return cmp
+ }
- override fun compareTo(other: PerformanceInterferenceModelItem): Int {
- var cmp = performanceScore.compareTo(other.performanceScore)
- if (cmp != 0) {
- return cmp
- }
+ cmp = minServerLoad.compareTo(other.minServerLoad)
+ if (cmp != 0) {
+ return cmp
+ }
- cmp = minServerLoad.compareTo(other.minServerLoad)
- if (cmp != 0) {
- return cmp
+ return hashCode().compareTo(other.hashCode())
}
-
- return hashCode().compareTo(other.hashCode())
}
}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/MemoryUnit.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt
index f41c41c4..bcbde5b1 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/MemoryUnit.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt
@@ -1,7 +1,5 @@
/*
- * MIT License
- *
- * Copyright (c) 2020 atlarge-research
+ * 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
@@ -22,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.core
+package org.opendc.simulator.compute.model
/**
* A memory unit of a compute resource, either virtual or physical.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ProcessingNode.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt
index 7e4694d4..58ed816c 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ProcessingNode.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt
@@ -1,7 +1,5 @@
/*
- * MIT License
- *
- * Copyright (c) 2020 atlarge-research
+ * 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
@@ -22,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.core
+package org.opendc.simulator.compute.model
/**
* A processing node/package/socket containing possibly several CPU cores.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ProcessingUnit.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt
index e6ee7f9a..415e95e6 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/ProcessingUnit.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt
@@ -1,7 +1,5 @@
/*
- * MIT License
- *
- * Copyright (c) 2020 atlarge-research
+ * 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
@@ -22,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.compute.core
+package org.opendc.simulator.compute.model
/**
* A single logical compute unit of processor node, either virtual or physical.
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/FlopsApplicationImage.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt
index 58c00e13..918a78bd 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/FlopsApplicationImage.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt
@@ -20,32 +20,24 @@
* SOFTWARE.
*/
-package org.opendc.compute.core.image
+package org.opendc.simulator.compute.workload
-import org.opendc.compute.core.execution.ServerContext
-import org.opendc.core.resource.TagContainer
-import java.util.UUID
+import org.opendc.simulator.compute.SimExecutionContext
import kotlin.math.min
/**
- * An application [Image] that models applications performing a static number of floating point operations ([flops]) on
+ * A [SimWorkload] that models applications performing a static number of floating point operations ([flops]) on
* a compute resource.
*
- * @property uid The unique identifier of this image.
- * @property name The name of this image.
- * @property tags The tags attached to the image.
* @property flops The number of floating point operations to perform for this task in MFLOPs.
* @property cores The number of cores that the image is able to utilize.
* @property utilization A model of the CPU utilization of the application.
*/
-public data class FlopsApplicationImage(
- public override val uid: UUID,
- public override val name: String,
- public override val tags: TagContainer,
+public class SimFlopsWorkload(
public val flops: Long,
public val cores: Int,
public val utilization: Double = 0.8
-) : Image {
+) : SimWorkload {
init {
require(flops >= 0) { "Negative number of flops" }
require(cores > 0) { "Negative number of cores or no cores" }
@@ -55,11 +47,11 @@ public data class FlopsApplicationImage(
/**
* Execute the runtime behavior based on a number of floating point operations to execute.
*/
- override suspend fun invoke(ctx: ServerContext) {
- val cores = min(this.cores, ctx.server.flavor.cpuCount)
+ override suspend fun run(ctx: SimExecutionContext) {
+ val cores = min(this.cores, ctx.machine.cpus.size)
val burst = LongArray(cores) { flops / cores }
- val maxUsage = DoubleArray(cores) { i -> ctx.cpus[i].frequency * utilization }
+ val maxUsage = DoubleArray(cores) { i -> ctx.machine.cpus[i].frequency * utilization }
- ctx.run(ServerContext.Slice(burst, maxUsage, Long.MAX_VALUE), triggerMode = ServerContext.TriggerMode.LAST)
+ ctx.run(SimExecutionContext.Slice(burst, maxUsage, Long.MAX_VALUE), triggerMode = SimExecutionContext.TriggerMode.LAST)
}
}
diff --git a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/VmImage.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt
index 72efbe0b..7b1ddf32 100644
--- a/simulator/opendc-compute/src/main/kotlin/org/opendc/compute/core/image/VmImage.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt
@@ -20,35 +20,34 @@
* SOFTWARE.
*/
-package org.opendc.compute.core.image
+package org.opendc.simulator.compute.workload
-import org.opendc.compute.core.execution.ServerContext
-import org.opendc.core.resource.TagContainer
-import java.util.*
+import org.opendc.simulator.compute.SimExecutionContext
import kotlin.math.min
-public class VmImage(
- public override val uid: UUID,
- public override val name: String,
- public override val tags: TagContainer,
- public val flopsHistory: Sequence<FlopsHistoryFragment>,
- public val maxCores: Int,
- public val requiredMemory: Long
-) : Image {
-
- override suspend fun invoke(ctx: ServerContext) {
+/**
+ * A [SimWorkload] that replays a workload trace consisting of multiple fragments, each indicating the resource
+ * consumption for some period of time.
+ */
+public class SimTraceWorkload(public val trace: Sequence<Fragment>) : SimWorkload {
+ override suspend fun run(ctx: SimExecutionContext) {
var offset = ctx.clock.millis()
- val batch = flopsHistory.map { fragment ->
- val cores = min(fragment.cores, ctx.server.flavor.cpuCount)
+ val batch = trace.map { fragment ->
+ val cores = min(fragment.cores, ctx.machine.cpus.size)
val burst = LongArray(cores) { fragment.flops / cores }
val usage = DoubleArray(cores) { fragment.usage / cores }
offset += fragment.duration
- ServerContext.Slice(burst, usage, offset)
+ SimExecutionContext.Slice(burst, usage, offset)
}
ctx.run(batch)
}
- override fun toString(): String = "VmImage(uid=$uid, name=$name, cores=$maxCores, requiredMemory=$requiredMemory)"
+ override fun toString(): String = "SimTraceWorkload"
+
+ /**
+ * A fragment of the workload.
+ */
+ public data class Fragment(val time: Long, val flops: Long, val duration: Long, val usage: Double, val cores: Int)
}
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt
new file mode 100644
index 00000000..2add8cce
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.simulator.compute.workload
+
+import org.opendc.simulator.compute.SimExecutionContext
+
+/**
+ * A model that characterizes the runtime behavior of some particular workload.
+ *
+ * Workloads are stateful objects that may be paused and resumed at a later moment. As such, be careful when using the
+ * same [SimWorkload] from multiple contexts as only a single concurrent [run] call is expected.
+ */
+public interface SimWorkload {
+ /**
+ * Launch the workload in the specified [SimExecutionContext].
+ *
+ * This method should encapsulate and characterize the runtime behavior of the instance resulting from launching
+ * the workload on some machine, in terms of the resource consumption on the machine.
+ */
+ public suspend fun run(ctx: SimExecutionContext)
+}
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt
new file mode 100644
index 00000000..78bd2940
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt
@@ -0,0 +1,129 @@
+/*
+ * 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.simulator.compute
+
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestCoroutineScope
+import kotlinx.coroutines.yield
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertAll
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.compute.workload.SimTraceWorkload
+import org.opendc.simulator.utils.DelayControllerClockAdapter
+import java.time.Clock
+
+/**
+ * Test suite for the [SimHypervisor] class.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+internal class SimHypervisorTest {
+ private lateinit var scope: TestCoroutineScope
+ private lateinit var clock: Clock
+ private lateinit var machineModel: SimMachineModel
+
+ @BeforeEach
+ fun setUp() {
+ scope = TestCoroutineScope()
+ clock = DelayControllerClockAdapter(scope)
+
+ val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2)
+ machineModel = SimMachineModel(
+ cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) },
+ memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
+ )
+ }
+
+ /**
+ * Test overcommissioning of a hypervisor.
+ */
+ @Test
+ fun overcommission() {
+ val listener = object : SimHypervisor.Listener {
+ var totalRequestedBurst = 0L
+ var totalGrantedBurst = 0L
+ var totalOvercommissionedBurst = 0L
+
+ override fun onSliceFinish(
+ hypervisor: SimHypervisor,
+ requestedBurst: Long,
+ grantedBurst: Long,
+ overcommissionedBurst: Long,
+ interferedBurst: Long,
+ cpuUsage: Double,
+ cpuDemand: Double
+ ) {
+ totalRequestedBurst += requestedBurst
+ totalGrantedBurst += grantedBurst
+ totalOvercommissionedBurst += overcommissionedBurst
+ }
+ }
+
+ scope.launch {
+ val duration = 5 * 60L
+ val workloadA =
+ SimTraceWorkload(
+ sequenceOf(
+ SimTraceWorkload.Fragment(0, 28L * duration, duration * 1000, 28.0, 2),
+ SimTraceWorkload.Fragment(0, 3500L * duration, duration * 1000, 3500.0, 2),
+ SimTraceWorkload.Fragment(0, 0, duration * 1000, 0.0, 2),
+ SimTraceWorkload.Fragment(0, 183L * duration, duration * 1000, 183.0, 2)
+ ),
+ )
+ val workloadB =
+ SimTraceWorkload(
+ sequenceOf(
+ SimTraceWorkload.Fragment(0, 28L * duration, duration * 1000, 28.0, 2),
+ SimTraceWorkload.Fragment(0, 3100L * duration, duration * 1000, 3100.0, 2),
+ SimTraceWorkload.Fragment(0, 0, duration * 1000, 0.0, 2),
+ SimTraceWorkload.Fragment(0, 73L * duration, duration * 1000, 73.0, 2)
+ )
+ )
+
+ val machine = SimBareMetalMachine(scope, clock, machineModel)
+ val hypervisor = SimHypervisor(scope, clock, listener)
+
+ launch {
+ machine.run(hypervisor)
+ }
+
+ yield()
+ launch { hypervisor.createMachine(machineModel).run(workloadA) }
+ launch { hypervisor.createMachine(machineModel).run(workloadB) }
+ }
+
+ scope.advanceUntilIdle()
+
+ assertAll(
+ { Assertions.assertEquals(emptyList<Throwable>(), scope.uncaughtExceptions, "No errors") },
+ { Assertions.assertEquals(2073600, listener.totalRequestedBurst, "Requested Burst does not match") },
+ { Assertions.assertEquals(2013600, listener.totalGrantedBurst, "Granted Burst does not match") },
+ { Assertions.assertEquals(60000, listener.totalOvercommissionedBurst, "Overcommissioned Burst does not match") },
+ { Assertions.assertEquals(1200001, scope.currentTime) }
+ )
+ }
+}
diff --git a/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
new file mode 100644
index 00000000..332ca8e9
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.simulator.compute
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.test.TestCoroutineScope
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.compute.workload.SimFlopsWorkload
+import org.opendc.simulator.utils.DelayControllerClockAdapter
+
+/**
+ * Test suite for the [SimBareMetalMachine] class.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+class SimMachineTest {
+ private lateinit var machineModel: SimMachineModel
+
+ @BeforeEach
+ fun setUp() {
+ val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2)
+
+ machineModel = SimMachineModel(
+ cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) },
+ memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
+ )
+ }
+
+ @Test
+ fun testFlopsWorkload() {
+ val testScope = TestCoroutineScope()
+ val clock = DelayControllerClockAdapter(testScope)
+ val machine = SimBareMetalMachine(testScope, clock, machineModel)
+
+ testScope.runBlockingTest {
+ machine.run(SimFlopsWorkload(2_000, 2, utilization = 1.0))
+
+ // Two cores execute 1000 MFlOps per second (1000 ms)
+ assertEquals(1000, testScope.currentTime)
+ }
+ }
+
+ @Test
+ fun testUsage() {
+ val testScope = TestCoroutineScope()
+ val clock = DelayControllerClockAdapter(testScope)
+ val machine = SimBareMetalMachine(testScope, clock, machineModel)
+
+ testScope.runBlockingTest {
+ machine.run(SimFlopsWorkload(2_000, 2, utilization = 1.0))
+ assertEquals(1.0, machine.usage.value)
+
+ // Wait for the usage to reset
+ delay(1)
+ assertEquals(0.0, machine.usage.value)
+ }
+ }
+}
diff --git a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/core/image/FlopsApplicationImageTest.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt
index 309dceb8..51bed76c 100644
--- a/simulator/opendc-compute/src/test/kotlin/org/opendc/compute/core/image/FlopsApplicationImageTest.kt
+++ b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt
@@ -1,7 +1,5 @@
/*
- * MIT License
- *
- * Copyright (c) 2020 atlarge-research
+ * 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
@@ -22,57 +20,54 @@
* SOFTWARE.
*/
-package org.opendc.compute.core.image
+package org.opendc.simulator.compute.workload
-import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
-import java.util.UUID
/**
- * Test suite for [FlopsApplicationImage]
+ * Test suite for [SimFlopsWorkload] class.
*/
-@DisplayName("FlopsApplicationImage")
-internal class FlopsApplicationImageTest {
+class SimFlopsWorkloadTest {
@Test
- fun `flops must be non-negative`() {
+ fun testFlopsNonNegative() {
assertThrows<IllegalArgumentException>("FLOPs must be non-negative") {
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), -1, 1)
+ SimFlopsWorkload(-1, 1)
}
}
@Test
- fun `cores cannot be zero`() {
+ fun testCoresNonZero() {
assertThrows<IllegalArgumentException>("Cores cannot be zero") {
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1, 0)
+ SimFlopsWorkload(1, 0)
}
}
@Test
- fun `cores cannot be negative`() {
+ fun testCoresPositive() {
assertThrows<IllegalArgumentException>("Cores cannot be negative") {
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1, -1)
+ SimFlopsWorkload(1, -1)
}
}
@Test
- fun `utilization cannot be zero`() {
+ fun testUtilizationNonZero() {
assertThrows<IllegalArgumentException>("Utilization cannot be zero") {
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1, 1, 0.0)
+ SimFlopsWorkload(1, 1, 0.0)
}
}
@Test
- fun `utilization cannot be negative`() {
+ fun testUtilizationPositive() {
assertThrows<IllegalArgumentException>("Utilization cannot be negative") {
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1, 1, -1.0)
+ SimFlopsWorkload(1, 1, -1.0)
}
}
@Test
- fun `utilization cannot be larger than one`() {
+ fun testUtilizationNotLargerThanOne() {
assertThrows<IllegalArgumentException>("Utilization cannot be larger than one") {
- FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1, 1, 2.0)
+ SimFlopsWorkload(1, 1, 2.0)
}
}
}
diff --git a/simulator/opendc-simulator/opendc-simulator-core/build.gradle.kts b/simulator/opendc-simulator/opendc-simulator-core/build.gradle.kts
new file mode 100644
index 00000000..a740dcf3
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-core/build.gradle.kts
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+description = "Simulation-specific code for use in OpenDC"
+
+/* Build configuration */
+plugins {
+ `kotlin-library-convention`
+}
+
+dependencies {
+ api("org.jetbrains.kotlinx:kotlinx-coroutines-test:${Library.KOTLINX_COROUTINES}")
+}
diff --git a/simulator/opendc-simulator/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt b/simulator/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt
index 84c18e87..84c18e87 100644
--- a/simulator/opendc-simulator/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt
+++ b/simulator/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt
diff --git a/simulator/opendc-simulator/opendc-simulator-failures/build.gradle.kts b/simulator/opendc-simulator/opendc-simulator-failures/build.gradle.kts
new file mode 100644
index 00000000..1c30506f
--- /dev/null
+++ b/simulator/opendc-simulator/opendc-simulator-failures/build.gradle.kts
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+description = "Failure models for OpenDC"
+
+plugins {
+ `kotlin-library-convention`
+}
+
+dependencies {
+ api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Library.KOTLINX_COROUTINES}")
+}
diff --git a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/CorrelatedFaultInjector.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/CorrelatedFaultInjector.kt
index f3bd7f5a..0e15f338 100644
--- a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/CorrelatedFaultInjector.kt
+++ b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/CorrelatedFaultInjector.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.core.failure
+package org.opendc.simulator.failures
import kotlinx.coroutines.*
import java.time.Clock
diff --git a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/FailureDomain.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FailureDomain.kt
index 0795b09a..dc3006e8 100644
--- a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/FailureDomain.kt
+++ b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FailureDomain.kt
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.opendc.core.failure
+package org.opendc.simulator.failures
import kotlinx.coroutines.CoroutineScope
diff --git a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/FaultInjector.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FaultInjector.kt
index ad776641..a866260c 100644
--- a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/FaultInjector.kt
+++ b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FaultInjector.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.core.failure
+package org.opendc.simulator.failures
/**
* An interface for stochastically injecting faults into a running system.
diff --git a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/UncorrelatedFaultInjector.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/UncorrelatedFaultInjector.kt
index f64b8815..b3bd737e 100644
--- a/simulator/opendc-core/src/main/kotlin/org/opendc/core/failure/UncorrelatedFaultInjector.kt
+++ b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/UncorrelatedFaultInjector.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.core.failure
+package org.opendc.simulator.failures
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
diff --git a/simulator/opendc-workflows/build.gradle.kts b/simulator/opendc-workflows/build.gradle.kts
index 97c588da..f61bdac6 100644
--- a/simulator/opendc-workflows/build.gradle.kts
+++ b/simulator/opendc-workflows/build.gradle.kts
@@ -29,11 +29,15 @@ plugins {
dependencies {
api(project(":opendc-core"))
- api(project(":opendc-compute"))
+ api(project(":opendc-compute:opendc-compute-core"))
implementation(project(":opendc-utils"))
- testImplementation(project(":opendc-simulator"))
+ testImplementation(project(":opendc-simulator:opendc-simulator-core"))
testImplementation(project(":opendc-format"))
+ testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8") {
+ exclude("org.jetbrains.kotlin", module = "kotlin-reflect")
+ }
+ testImplementation(kotlin("reflect"))
testImplementation("org.junit.jupiter:junit-jupiter-api:${Library.JUNIT_JUPITER}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Library.JUNIT_JUPITER}")
testImplementation("org.junit.platform:junit-platform-launcher:${Library.JUNIT_PLATFORM}")
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt
index bc08b22d..3b4e6eab 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt
@@ -31,8 +31,8 @@ import kotlinx.coroutines.launch
import org.opendc.compute.core.Server
import org.opendc.compute.core.ServerEvent
import org.opendc.compute.core.ServerState
-import org.opendc.compute.metal.Node
-import org.opendc.compute.metal.service.ProvisioningService
+import org.opendc.compute.core.metal.Node
+import org.opendc.compute.core.metal.service.ProvisioningService
import org.opendc.utils.flow.EventFlow
import org.opendc.workflows.service.stage.job.JobAdmissionPolicy
import org.opendc.workflows.service.stage.job.JobOrderPolicy
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt
index ddfbeae3..ed023c82 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt
@@ -22,7 +22,7 @@
package org.opendc.workflows.service
-import org.opendc.compute.metal.Node
+import org.opendc.compute.core.metal.Node
import org.opendc.workflows.workload.Task
public class TaskState(public val job: JobState, public val task: Task) {
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt
index 38b37140..8dc323ec 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt
@@ -22,7 +22,7 @@
package org.opendc.workflows.service.stage.resource
-import org.opendc.compute.metal.Node
+import org.opendc.compute.core.metal.Node
import org.opendc.workflows.service.StageWorkflowService
/**
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt
index 9381ffd7..ac79a9ce 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt
@@ -22,7 +22,7 @@
package org.opendc.workflows.service.stage.resource
-import org.opendc.compute.metal.Node
+import org.opendc.compute.core.metal.Node
import org.opendc.workflows.service.StageWorkflowService
import org.opendc.workflows.service.TaskState
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt
index b31a6217..caf87c70 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt
@@ -22,7 +22,7 @@
package org.opendc.workflows.service.stage.resource
-import org.opendc.compute.metal.Node
+import org.opendc.compute.core.metal.Node
import org.opendc.workflows.service.StageWorkflowService
import java.util.*
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt
index 9f44fddf..4923a34b 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt
@@ -22,7 +22,7 @@
package org.opendc.workflows.service.stage.resource
-import org.opendc.compute.metal.Node
+import org.opendc.compute.core.metal.Node
import org.opendc.workflows.service.TaskState
import org.opendc.workflows.service.stage.StagePolicy
diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt
index 3682844a..990b990a 100644
--- a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt
+++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt
@@ -22,7 +22,7 @@
package org.opendc.workflows.service.stage.resource
-import org.opendc.compute.metal.Node
+import org.opendc.compute.core.metal.Node
import org.opendc.workflows.service.stage.StagePolicy
/**
diff --git a/simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt b/simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt
index 6e9e7430..90cf5b99 100644
--- a/simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt
+++ b/simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt
@@ -35,7 +35,7 @@ import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
-import org.opendc.compute.metal.service.ProvisioningService
+import org.opendc.compute.core.metal.service.ProvisioningService
import org.opendc.format.environment.sc18.Sc18EnvironmentReader
import org.opendc.format.trace.gwf.GwfTraceReader
import org.opendc.simulator.utils.DelayControllerClockAdapter
diff --git a/simulator/settings.gradle.kts b/simulator/settings.gradle.kts
index e5e218b8..935a18d0 100644
--- a/simulator/settings.gradle.kts
+++ b/simulator/settings.gradle.kts
@@ -22,11 +22,14 @@
rootProject.name = "opendc-simulator"
include(":opendc-core")
-include(":opendc-compute")
+include(":opendc-compute:opendc-compute-core")
+include(":opendc-compute:opendc-compute-simulator")
include(":opendc-workflows")
include(":opendc-format")
include(":opendc-experiments:opendc-experiments-sc18")
include(":opendc-experiments:opendc-experiments-sc20")
include(":opendc-runner-web")
-include(":opendc-simulator")
+include(":opendc-simulator:opendc-simulator-core")
+include(":opendc-simulator:opendc-simulator-compute")
+include(":opendc-simulator:opendc-simulator-failures")
include(":opendc-utils")